使用Python获取IOS设备拍摄的HEIC图片拍摄地址、坐标和位置,并利用Google Earth绘制XML文件

前言

出去旅游,用iphone拍了非常多的照片,心想这些照片都有位置信息和拍摄时间信息,那能不能用python制作一个程序,输入所有照片,然后读取这些信息,最后输出一个xml路径文件,打开在googleEarth看。虽然最近逐步奉行“不讨论意义主义”,但我觉得此举的意义,首先是折腾python的乐趣,其次对于超长途旅行路线,能够结合更为宏观的视角来回顾本次旅行,譬如我发现原来我拍摄的地方,是甘肃和新疆的接壤,原来重庆在兰州的正下方偏东,原来我这次横跨了三个阶梯等等,能够带来许多乐趣。

csdn是程序员为主的博客平台,所以本文也会聚焦于这个程序,这个程序的功能在前言中已经有所概述,并且功能将会更丰富。定位是google Earth的小插件吧。能够输入照片,输出googleEarth使用的xml路径文件。

设计蓝图

#mermaid-svg-TkCy88sonp8V0M6t {font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-TkCy88sonp8V0M6t .error-icon{fill:#552222;}#mermaid-svg-TkCy88sonp8V0M6t .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TkCy88sonp8V0M6t .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-TkCy88sonp8V0M6t .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TkCy88sonp8V0M6t .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TkCy88sonp8V0M6t .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TkCy88sonp8V0M6t .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TkCy88sonp8V0M6t .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TkCy88sonp8V0M6t .marker.cross{stroke:#333333;}#mermaid-svg-TkCy88sonp8V0M6t svg{font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TkCy88sonp8V0M6t .label{font-family:”trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-TkCy88sonp8V0M6t .cluster-label text{fill:#333;}#mermaid-svg-TkCy88sonp8V0M6t .cluster-label span{color:#333;}#mermaid-svg-TkCy88sonp8V0M6t .label text,#mermaid-svg-TkCy88sonp8V0M6t span{fill:#333;color:#333;}#mermaid-svg-TkCy88sonp8V0M6t .node rect,#mermaid-svg-TkCy88sonp8V0M6t .node circle,#mermaid-svg-TkCy88sonp8V0M6t .node ellipse,#mermaid-svg-TkCy88sonp8V0M6t .node polygon,#mermaid-svg-TkCy88sonp8V0M6t .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TkCy88sonp8V0M6t .node .label{text-align:center;}#mermaid-svg-TkCy88sonp8V0M6t .node.clickable{cursor:pointer;}#mermaid-svg-TkCy88sonp8V0M6t .arrowheadPath{fill:#333333;}#mermaid-svg-TkCy88sonp8V0M6t .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TkCy88sonp8V0M6t .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TkCy88sonp8V0M6t .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-TkCy88sonp8V0M6t .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-TkCy88sonp8V0M6t .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TkCy88sonp8V0M6t .cluster text{fill:#333;}#mermaid-svg-TkCy88sonp8V0M6t .cluster span{color:#333;}#mermaid-svg-TkCy88sonp8V0M6t div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TkCy88sonp8V0M6t :root{–mermaid-font-family:”trebuchet ms”,verdana,arial,sans-serif;}

输入

输出

多媒体mp4,jpg

程序

XML路径文件

Google Earth查看

主程序代码

主流程

参考文献:
How to extract GPS coordinates from Images in Python
How to extract GPS location from HEIC files?
一、获取单个HEIC文件的位置信息:
1.pillow库读取HEIC文件
2.获得照片拍摄的坐标,格式是Degrees, minutes, and seconds (DMS)
e.g.

(11.0, 53.0, 7.42199999)

3.将(DMS)格式坐标转化为 Decimal degrees (DD)格式。
e.g.

(43.46715666666389, 11.885394999997223)

4.坐标纠偏
5.难点:如何获得HEIC文件的拍摄时间?
根据如下这篇文章《python exif不能找到heic的“date taken”也就是拍摄时间,但是在windows资源管理器下却是可见的》
Python EXIF can’t find HEIC file date taken, but it’s visible in other tools
采用了如下方法:

import exifread

with open(filename, 'rb') as image:
  exif = exifread.process_file(image)

但是报错,报错如下,并找到了解决方案也如下
exifread.process_file() throws “KeyError: ‘hdlr’” and “NoParser: hdlr Output is truncated.” for a HEIC image even though exifread can deal with HEIC
解决方案如原文:

This is just to share what I found on the net to fix this. Check HEIC processing error: hdlr on Apple Silicon #4.

Thus, you should downgrade to a version below 3.0.0:
也就是要将exifread降级到3以下,3以下最新的就是pip install exifread==2.3.2

然后不再报错

最终程序:

import simplekml
import exifread
import os
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener()

list2 = [('1', 51.500152, -0.126236), ('2', 1.500152, -50.126236)]
img_path = r'F:\trippicProject\pic\IMG_4563.HEIC'
HEICpath = r'F:\trippicProject\pic'

# 该函数用于将pillow获取的gps tag(DMS格式)转化为Decimal degrees (DD)(x,y)的格式
# you will get the coordinates in Degrees, minutes, and seconds (DMS). We will soon convert this format to Decimal degrees (DD) format.
def decimal_coords(coords, ref):
    decimal_degrees = float(coords[0]) + float(coords[1]) / 60 + float(coords[2]) / 3600
    if ref == 'S' or ref == 'W':
        decimal_degrees = -decimal_degrees
    return decimal_degrees


def get_heicGeoCoords(heicPath):
    image = Image.open(heicPath)
    image.verify()

    exif = image.getexif().get_ifd(0x8825)
    geo_tagging_info = {}
    if not exif:
        raise ValueError("No EXIF metadata found")
    else:
        gps_keys = ['GPSVersionID', 'GPSLatitudeRef', 'GPSLatitude', 'GPSLongitudeRef', 'GPSLongitude',
                    'GPSAltitudeRef', 'GPSAltitude', 'GPSTimeStamp', 'GPSSatellites', 'GPSStatus', 'GPSMeasureMode',
                    'GPSDOP', 'GPSSpeedRef', 'GPSSpeed', 'GPSTrackRef', 'GPSTrack', 'GPSImgDirectionRef',
                    'GPSImgDirection', 'GPSMapDatum', 'GPSDestLatitudeRef', 'GPSDestLatitude', 'GPSDestLongitudeRef',
                    'GPSDestLongitude', 'GPSDestBearingRef', 'GPSDestBearing', 'GPSDestDistanceRef', 'GPSDestDistance',
                    'GPSProcessingMethod', 'GPSAreaInformation', 'GPSDateStamp', 'GPSDifferential']

        for k, v in exif.items():
            try:
                geo_tagging_info[gps_keys[k]] = v
            except IndexError:
                pass
        coords = (decimal_coords(geo_tagging_info['GPSLatitude'], geo_tagging_info['GPSLatitudeRef']), decimal_coords(geo_tagging_info['GPSLongitude'], geo_tagging_info['GPSLongitudeRef']))
        return coords


def get_heicTime(heicPath):
    pic_data = exifread.process_file(open(heicPath, 'rb'))
    time = pic_data['Image DateTime']
    time_stamp = str(time)[2:4] + str(time)[5:7] + str(time)[8:10] + str(time)[11:13] + str(time)[14:16] + str(time)[17:19]
    return time_stamp


if __name__ == '__main__':

    imgs = os.listdir(r'F:\trippicProject\pic')

    dateDatas = []
    date2Details = {}
    for imgName in imgs:
        if imgName[-4:] == 'HEIC':
            try:
                img_path = HEICpath + '\\' + imgName

                thisTime = get_heicTime(img_path)
                thisCoords = get_heicGeoCoords(img_path)

                dateDatas.append(int(thisTime))
                date2Details[thisTime] = [thisCoords, imgName]
                print("Done=>"+imgName)
            except ValueError:
                print("No EXIF metadata found=>"+imgName)
    dateDatas.sort()


    kml = simplekml.Kml()
    lin = kml.newlinestring(name="trip")
    lin.extrude = 1
    lin.altitudemode = simplekml.AltitudeMode.clamptoground
    lin.style.linestyle.width = 5
    lin.style.linestyle.color = simplekml.Color.blue

    for date in dateDatas:
        coords = date2Details[str(date)][0]
        pnt = kml.newpoint(description='test', coords=[(coords[1], coords[0])])
        description = '<![CDATA[<img style="max-width:500px;" src="file:///F:/trippicProject/jpg/' + date2Details[str(date)][1][:-5] +'.jpg">]]>'
        pnt.description = description
        lin.coords.addcoordinates([(coords[1], coords[0])])
    kml.save("test.kml")



物联沃分享整理
物联沃-IOTWORD物联网 » 使用Python获取IOS设备拍摄的HEIC图片拍摄地址、坐标和位置,并利用Google Earth绘制XML文件

发表评论