Python工具箱系列(五十二)

haod使用EXIF信息对相片进行定位

打开华为手机的图库,你会发现已经自动进行人脸识别,相片的归类与聚合等工作,甚至于还可以进行一步根据场景来搜索。当然这些肯定是在用户同意的前提下,对图片进行了操作与计算。事实上,当拿出手机进行拍照的这一刻,很多信息已经记录在案,这就是EXIF信息。Exif的全称是“Exchangeable image file format”,翻译过来就是可交换图像文件格式的意思。Exif能附带很多图片生成的信息,例如使用数码相机拍摄图片的话,那么相机型号、光圈、快门等信息都会被Exif记录下来。目前绝大部分图片格式都支持Exif,只有JPEG2000、GIF等少数格式不兼容Exif。而Exif也不仅仅能用于图片文件,它也可以用于音频。如下图所示,在windows 11下显示一张图片的相关信息。

这里我们需要注意的是,并非所有的照片都能够进行解析,必须是携带exif信息的原始图片。如果中间进行了压缩或者P图,那么就无法识别了。当然像一些社交平台也会专门针对exif进行处理,比如微信,你发在朋友圈的图片会自动压缩,所以是不会暴露信息的。下面的python代码示范了如何获得exif信息。

import exifread

def exifinfo(fullfilename: str) -> dict:
    """
    获得图片的EXIF信息

    Args:
        fullfilename (str): 图片文件名

    Returns:
        dict: EXIF信息组成的字典
    """
    f = open(fullfilename, 'rb')
    tags = exifread.process_file(f)
    for tag in tags.keys():
        if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'):
                print("Key: %s, value %s" % (tag, tags[tag]))

def exifgps(fullfilename: str)->list:
    """
    获得图片的EXIF信息中的GPS位置信息

    Args:
        fullfilename (str): 图片文件名

    Returns:
        list: 包括经度、纬度与创建时间的列表
    """
    f = open(fullfilename, 'rb')
    tags = exifread.process_file(f)

    key = 'EXIF DateTimeOriginal'
    if key in tags.keys():
        eDate=tags[key].printable
    
    key = 'GPS GPSLongitude'
    if key in tags.keys():
        eLon=tags[key].printable
        eLat=tags['GPS GPSLatitude'].printable
        lon=eLon[1:-1].replace(' ','').replace('/',',').split(',')
        lon=float(lon[0])+float(lon[1])/60+float(lon[2])/float(lon[3])/3600
        lat=eLat[1:-1].replace(' ','').replace('/',',').split(',')
        lat=float(lat[0])+float(lat[1])/60+float(lat[2])/float(lat[3])/3600
        return [lon,lat,eDate]  #经度,纬度,拍摄时间

targetfile = r'd:\test\IMG_20220813_121501.jpg'
exifinfo(targetfile)
print(exifgps(targetfile))

​上述代码中:

exifinfo中跳过了很难看懂的key,例如"JPEGThumbnail",否则显示一大堆数字。

exifgps中,不断的进行判断,是因为图片不一定存在exif,也不一定存在gps的定位信息。许多软件都具备破坏exif的能力。

接下来的任务就是通过坐标来在地图上打点,我们使用python folium库来完成。folium底层使用leaflet.js库,因此数据可视化的呈现是网页。之所以使用folium,而不是使用网上常见的pyechart的主要原因就是不想受制于大厂的专有技术。使用folium也可以在后台灵活对接多个第三方的地图引擎。下述代码完整演示了这个过程。

import exifread
import folium

def exifinfo(fullfilename: str) -> dict:
    """
    获得图片的EXIF信息

    Args:
        fullfilename (str): 图片文件名

    Returns:
        dict: EXIF信息组成的字典
    """
    f = open(fullfilename, 'rb')
    tags = exifread.process_file(f)
    for tag in tags.keys():
        if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'):
                print("Key: %s, value %s" % (tag, tags[tag]))

def exifgps(fullfilename: str)->list:
    """
    获得图片的EXIF信息中的GPS位置信息

    Args:
        fullfilename (str): 图片文件名

    Returns:
        list: 包括经度、纬度与创建时间的列表
    """
    f = open(fullfilename, 'rb')
    tags = exifread.process_file(f)

    key = 'EXIF DateTimeOriginal'
    if key in tags.keys():
        eDate=tags[key].printable
    
    key = 'GPS GPSLongitude'
    if key in tags.keys():
        eLon=tags[key].printable
        eLat=tags['GPS GPSLatitude'].printable
        lon=eLon[1:-1].replace(' ','').replace('/',',').split(',')
        lon=float(lon[0])+float(lon[1])/60+float(lon[2])/float(lon[3])/3600
        lat=eLat[1:-1].replace(' ','').replace('/',',').split(',')
        lat=float(lat[0])+float(lat[1])/60+float(lat[2])/float(lat[3])/3600
        return [lon,lat,eDate]  #经度,纬度,拍摄时间

targetfile = r'd:\test\IMG_20220813_121501.jpg'

exifinfo(targetfile)
# 获得图片的经纬度
lon,lat,_= exifgps(targetfile)

# 注意location是(纬度,经度)组合
m = folium.Map(location=[lat,lon],width=600,height=600,zoom_start=12)
folium.Marker(location=[lat,lon],popup='Here!',icon=folium.Icon(icon='cloud')).add_to(m)
m.save('d:\dev\map.html')

​folium能够在jupyter中直接展示,这段代码运行后将结果保存到html文件中,打开后的效果如下所示。

从图中可以看出照片是在金地广场,确实如此。

posted @ 2024-04-28 16:09  西安衍舆航天  阅读(12)  评论(0编辑  收藏  举报