标签归档:exif

在Python中,如何读取图像的exif数据?

问题:在Python中,如何读取图像的exif数据?

我正在使用PIL。如何将EXIF数据转换为字典?

I’m using PIL. How do I turn the EXIF data of a picture into a dictionary?


回答 0

试试这个:

import PIL.Image
img = PIL.Image.open('img.jpg')
exif_data = img._getexif()

这应该给您一个由EXIF数字标签索引的字典。如果您希望字典由实际的EXIF标记名称字符串索引,请尝试以下操作:

import PIL.ExifTags
exif = {
    PIL.ExifTags.TAGS[k]: v
    for k, v in img._getexif().items()
    if k in PIL.ExifTags.TAGS
}

You can use the _getexif() protected method of a PIL Image.

import PIL.Image
img = PIL.Image.open('img.jpg')
exif_data = img._getexif()

This should give you a dictionary indexed by EXIF numeric tags. If you want the dictionary indexed by the actual EXIF tag name strings, try something like:

import PIL.ExifTags
exif = {
    PIL.ExifTags.TAGS[k]: v
    for k, v in img._getexif().items()
    if k in PIL.ExifTags.TAGS
}

回答 1

您还可以使用ExifRead模块:

import exifread
# Open image file for reading (binary mode)
f = open(path_name, 'rb')

# Return Exif tags
tags = exifread.process_file(f)

You can also use the ExifRead module:

import exifread
# Open image file for reading (binary mode)
f = open(path_name, 'rb')

# Return Exif tags
tags = exifread.process_file(f)

回答 2

我用这个:

import os,sys
from PIL import Image
from PIL.ExifTags import TAGS

for (k,v) in Image.open(sys.argv[1])._getexif().iteritems():
        print '%s = %s' % (TAGS.get(k), v)

或获取特定字段:

def get_field (exif,field) :
  for (k,v) in exif.iteritems():
     if TAGS.get(k) == field:
        return v

exif = image._getexif()
print get_field(exif,'ExposureTime')

I use this:

import os,sys
from PIL import Image
from PIL.ExifTags import TAGS

for (k,v) in Image.open(sys.argv[1])._getexif().items():
        print('%s = %s' % (TAGS.get(k), v))

or to get a specific field:

def get_field (exif,field) :
  for (k,v) in exif.items():
     if TAGS.get(k) == field:
        return v

exif = image._getexif()
print get_field(exif,'ExposureTime')

回答 3

对于Python3.x和starting Pillow==6.0.0Image对象现在提供了getexif()一种返回的方法,<class 'PIL.Image.Exif'>或者None该图像没有EXIF数据。

Pillow 6.0.0发行说明

getexif()已添加,它返回一个Exif实例。可以像字典一样检索和设置值。保存JPEG,PNG或WEBP时,可以将实例作为exif参数传递,以包括输出图像中的所有更改。

所述Exif输出可以被简单地浇铸到一个dict,从而使EXIF数据然后可以作为一个常规的键-值对被访问dict。键是16位整数,可以使用ExifTags.TAGS模块映射到其字符串名称。

from PIL import Image, ExifTags

img = Image.open("sample.jpg")
img_exif = img.getexif()
print(type(img_exif))
# <class 'PIL.Image.Exif'>

if img_exif is None:
    print("Sorry, image has no exif data.")
else:
    img_exif_dict = dict(img_exif)
    print(img_exif_dict)
    # { ... 42035: 'FUJIFILM', 42036: 'XF23mmF2 R WR', 42037: '75A14188' ... }
    for key, val in img_exif_dict.items():
        if key in ExifTags.TAGS:
            print(f"{ExifTags.TAGS[key]}:{repr(val)}")
            # ExifVersion:b'0230'
            # ...
            # FocalLength:(2300, 100)
            # ColorSpace:1
            # FocalLengthIn35mmFilm:35
            # ...
            # Model:'X-T2'
            # Make:'FUJIFILM'
            # ...
            # DateTime:'2019:12:01 21:30:07'
            # ...

使用Python 3.6.8和Pillow==6.0.0

For Python3.x and starting Pillow==6.0.0, Image objects now provide a getexif() method that returns <class 'PIL.Image.Exif'> or None if the image has no EXIF data.

From Pillow 6.0.0 release notes:

getexif() has been added, which returns an Exif instance. Values can be retrieved and set like a dictionary. When saving JPEG, PNG or WEBP, the instance can be passed as an exif argument to include any changes in the output image.

As stated, the Exif output can simply be casted to a dict with the EXIF data accessible as regular key-value pairs. The keys are 16-bit integers that can be mapped to their string names using the ExifTags.TAGS module.

from PIL import Image, ExifTags

img = Image.open("sample.jpg")
img_exif = img.getexif()
print(type(img_exif))
# <class 'PIL.Image.Exif'>

if img_exif is None:
    print("Sorry, image has no exif data.")
else:
    img_exif_dict = dict(img_exif)
    print(img_exif_dict)
    # { ... 42035: 'FUJIFILM', 42036: 'XF23mmF2 R WR', 42037: '75A14188' ... }
    for key, val in img_exif_dict.items():
        if key in ExifTags.TAGS:
            print(f"{ExifTags.TAGS[key]}:{repr(val)}")
            # ExifVersion:b'0230'
            # ...
            # FocalLength:(2300, 100)
            # ColorSpace:1
            # FocalLengthIn35mmFilm:35
            # ...
            # Model:'X-T2'
            # Make:'FUJIFILM'
            # ...
            # DateTime:'2019:12:01 21:30:07'
            # ...

Tested with Python 3.6.8 and Pillow==6.0.0.


回答 4

import sys
import PIL
import PIL.Image as PILimage
from PIL import ImageDraw, ImageFont, ImageEnhance
from PIL.ExifTags import TAGS, GPSTAGS



class Worker(object):
    def __init__(self, img):
        self.img = img
        self.exif_data = self.get_exif_data()
        self.lat = self.get_lat()
        self.lon = self.get_lon()
        self.date =self.get_date_time()
        super(Worker, self).__init__()

    @staticmethod
    def get_if_exist(data, key):
        if key in data:
            return data[key]
        return None

    @staticmethod
    def convert_to_degress(value):
        """Helper function to convert the GPS coordinates
        stored in the EXIF to degress in float format"""
        d0 = value[0][0]
        d1 = value[0][1]
        d = float(d0) / float(d1)
        m0 = value[1][0]
        m1 = value[1][1]
        m = float(m0) / float(m1)

        s0 = value[2][0]
        s1 = value[2][1]
        s = float(s0) / float(s1)

        return d + (m / 60.0) + (s / 3600.0)

    def get_exif_data(self):
        """Returns a dictionary from the exif data of an PIL Image item. Also
        converts the GPS Tags"""
        exif_data = {}
        info = self.img._getexif()
        if info:
            for tag, value in info.items():
                decoded = TAGS.get(tag, tag)
                if decoded == "GPSInfo":
                    gps_data = {}
                    for t in value:
                        sub_decoded = GPSTAGS.get(t, t)
                        gps_data[sub_decoded] = value[t]

                    exif_data[decoded] = gps_data
                else:
                    exif_data[decoded] = value
        return exif_data

    def get_lat(self):
        """Returns the latitude and longitude, if available, from the 
        provided exif_data (obtained through get_exif_data above)"""
        # print(exif_data)
        if 'GPSInfo' in self.exif_data:
            gps_info = self.exif_data["GPSInfo"]
            gps_latitude = self.get_if_exist(gps_info, "GPSLatitude")
            gps_latitude_ref = self.get_if_exist(gps_info, 'GPSLatitudeRef')
            if gps_latitude and gps_latitude_ref:
                lat = self.convert_to_degress(gps_latitude)
                if gps_latitude_ref != "N":
                    lat = 0 - lat
                lat = str(f"{lat:.{5}f}")
                return lat
        else:
            return None

    def get_lon(self):
        """Returns the latitude and longitude, if available, from the 
        provided exif_data (obtained through get_exif_data above)"""
        # print(exif_data)
        if 'GPSInfo' in self.exif_data:
            gps_info = self.exif_data["GPSInfo"]
            gps_longitude = self.get_if_exist(gps_info, 'GPSLongitude')
            gps_longitude_ref = self.get_if_exist(gps_info, 'GPSLongitudeRef')
            if gps_longitude and gps_longitude_ref:
                lon = self.convert_to_degress(gps_longitude)
                if gps_longitude_ref != "E":
                    lon = 0 - lon
                lon = str(f"{lon:.{5}f}")
                return lon
        else:
            return None

    def get_date_time(self):
        if 'DateTime' in self.exif_data:
            date_and_time = self.exif_data['DateTime']
            return date_and_time 

if __name__ == '__main__':
    try:
        img = PILimage.open(sys.argv[1])
        image = Worker(img)
        lat = image.lat
        lon = image.lon
        date = image.date
        print(date, lat, lon)

    except Exception as e:
        print(e)
import sys
import PIL
import PIL.Image as PILimage
from PIL import ImageDraw, ImageFont, ImageEnhance
from PIL.ExifTags import TAGS, GPSTAGS



class Worker(object):
    def __init__(self, img):
        self.img = img
        self.exif_data = self.get_exif_data()
        self.lat = self.get_lat()
        self.lon = self.get_lon()
        self.date =self.get_date_time()
        super(Worker, self).__init__()

    @staticmethod
    def get_if_exist(data, key):
        if key in data:
            return data[key]
        return None

    @staticmethod
    def convert_to_degress(value):
        """Helper function to convert the GPS coordinates
        stored in the EXIF to degress in float format"""
        d0 = value[0][0]
        d1 = value[0][1]
        d = float(d0) / float(d1)
        m0 = value[1][0]
        m1 = value[1][1]
        m = float(m0) / float(m1)

        s0 = value[2][0]
        s1 = value[2][1]
        s = float(s0) / float(s1)

        return d + (m / 60.0) + (s / 3600.0)

    def get_exif_data(self):
        """Returns a dictionary from the exif data of an PIL Image item. Also
        converts the GPS Tags"""
        exif_data = {}
        info = self.img._getexif()
        if info:
            for tag, value in info.items():
                decoded = TAGS.get(tag, tag)
                if decoded == "GPSInfo":
                    gps_data = {}
                    for t in value:
                        sub_decoded = GPSTAGS.get(t, t)
                        gps_data[sub_decoded] = value[t]

                    exif_data[decoded] = gps_data
                else:
                    exif_data[decoded] = value
        return exif_data

    def get_lat(self):
        """Returns the latitude and longitude, if available, from the 
        provided exif_data (obtained through get_exif_data above)"""
        # print(exif_data)
        if 'GPSInfo' in self.exif_data:
            gps_info = self.exif_data["GPSInfo"]
            gps_latitude = self.get_if_exist(gps_info, "GPSLatitude")
            gps_latitude_ref = self.get_if_exist(gps_info, 'GPSLatitudeRef')
            if gps_latitude and gps_latitude_ref:
                lat = self.convert_to_degress(gps_latitude)
                if gps_latitude_ref != "N":
                    lat = 0 - lat
                lat = str(f"{lat:.{5}f}")
                return lat
        else:
            return None

    def get_lon(self):
        """Returns the latitude and longitude, if available, from the 
        provided exif_data (obtained through get_exif_data above)"""
        # print(exif_data)
        if 'GPSInfo' in self.exif_data:
            gps_info = self.exif_data["GPSInfo"]
            gps_longitude = self.get_if_exist(gps_info, 'GPSLongitude')
            gps_longitude_ref = self.get_if_exist(gps_info, 'GPSLongitudeRef')
            if gps_longitude and gps_longitude_ref:
                lon = self.convert_to_degress(gps_longitude)
                if gps_longitude_ref != "E":
                    lon = 0 - lon
                lon = str(f"{lon:.{5}f}")
                return lon
        else:
            return None

    def get_date_time(self):
        if 'DateTime' in self.exif_data:
            date_and_time = self.exif_data['DateTime']
            return date_and_time 

if __name__ == '__main__':
    try:
        img = PILimage.open(sys.argv[1])
        image = Worker(img)
        lat = image.lat
        lon = image.lon
        date = image.date
        print(date, lat, lon)

    except Exception as e:
        print(e)

回答 5

我发现使用._getexif在更高版本的python中不起作用,而且,它是受保护的类,应该尽可能避免使用它。在深入调试器之后,这是我发现获取图像的EXIF数据的最佳方法:

from PIL import Image

def get_exif(path):
    return Image.open(path).info['parsed_exif']

这将返回图像的所有EXIF数据的字典。

注意:对于Python3.x,请使用Pillow而不是PIL

I have found that using ._getexif doesn’t work in higher python versions, moreover, it is a protected class and one should avoid using it if possible. After digging around the debugger this is what I found to be the best way to get the EXIF data for an image:

from PIL import Image

def get_exif(path):
    return Image.open(path).info['parsed_exif']

This returns a dictionary of all the EXIF data of an image.

Note: For Python3.x use Pillow instead of PIL


回答 6

这是一个可能更容易阅读的内容。希望这会有所帮助。

from PIL import Image
from PIL import ExifTags

exifData = {}
img = Image.open(picture.jpg)
exifDataRaw = img._getexif()
for tag, value in exifDataRaw.items():
    decodedTag = ExifTags.TAGS.get(tag, tag)
    exifData[decodedTag] = value

Here’s the one that may be little easier to read. Hope this is helpful.

from PIL import Image
from PIL import ExifTags

exifData = {}
img = Image.open(picture.jpg)
exifDataRaw = img._getexif()
for tag, value in exifDataRaw.items():
    decodedTag = ExifTags.TAGS.get(tag, tag)
    exifData[decodedTag] = value

回答 7

我通常使用pyexiv2在JPG文件中设置exif信息,但是当我在脚本QGIS脚本中导入库时崩溃。

我找到了使用库exif的解决方案:

https://pypi.org/project/exif/

它是如此易于使用,而且使用Qgis我没有任何问题。

在此代码中,我将GPS坐标插入屏幕快照:

from exif import Image
with open(file_name, 'rb') as image_file:
    my_image = Image(image_file)

my_image.make = "Python"
my_image.gps_latitude_ref=exif_lat_ref
my_image.gps_latitude=exif_lat
my_image.gps_longitude_ref= exif_lon_ref
my_image.gps_longitude= exif_lon

with open(file_name, 'wb') as new_image_file:
    new_image_file.write(my_image.get_file())

I usually use pyexiv2 to set exif information in JPG files, but when I import the library in a script QGIS script crash.

I found a solution using the library exif:

https://pypi.org/project/exif/

It’s so easy to use, and with Qgis I don,’t have any problem.

In this code I insert GPS coordinates to a snapshot of screen:

from exif import Image
with open(file_name, 'rb') as image_file:
    my_image = Image(image_file)

my_image.make = "Python"
my_image.gps_latitude_ref=exif_lat_ref
my_image.gps_latitude=exif_lat
my_image.gps_longitude_ref= exif_lon_ref
my_image.gps_longitude= exif_lon

with open(file_name, 'wb') as new_image_file:
    new_image_file.write(my_image.get_file())

python的Exif操作库

问题:python的Exif操作库

我正在寻找适用于python的良好exif(可交换图像文件格式)操作库。与处理速度相比,我更喜欢灵活性(例如,检索提供商专有标签的能力)。你有什么建议?

I’m looking for good exif (Exchangeable image file format) manipulation library for python. I prefer flexibility (e.g., ability to retrieve providers’ proprietary tags) than processing speed. What would you suggest?


回答 0

您可能要签出exif-py

从tiff和jpeg文件提取EXIF数据的Python库。非常易于使用-$ ./EXIF.py image.jpg

Python Imaging Library(PIL)

Python Imaging Library(PIL)为您的Python解释器添加了图像处理功能。该库支持多种文件格式,并提供强大的图像处理和图形功能。

还有一个恰当命名的pyexif:http ://pyexif.sourceforge.net/

pyexif python库和工具旨在从包含它的Jpeg和Tiff文件中提取EXIF信息。此信息通常包含在使用数字成像设备(例如,数码相机,数字胶片扫描仪等)创建的图像中。

但是,似乎pyexif尚未更新。他们建议,如果他们的技巧不正确,不能签出EXIF-py,那么您可能应该首先尝试一下,因为他们的sourceforge页面最近似乎有一些活动,尽管数量不多。最后,使用PIL您可以执行以下操作:

from PIL import Image
from PIL.ExifTags import TAGS

def get_exif(fn):
    ret = {}
    i = Image.open(fn)
    info = i._getexif()
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

免责声明
实际上我不知道哪个是最好的,这就是我与Google共同努力的结果。:)

You might want to check out exif-py:

Python library to extract EXIF data from tiff and jpeg files. Very easy to use – $ ./EXIF.py image.jpg

or the Python Imaging Library (PIL):

The Python Imaging Library (PIL) adds image processing capabilities to your Python interpreter. This library supports many file formats, and provides powerful image processing and graphics capabilities.

There’s also the aptly named pyexif: http://pyexif.sourceforge.net/

The pyexif python library and tools aims at extracting EXIF information from Jpeg and Tiff files which include it. This information is typically included in images created using digital imaging devices such as digital cameras, digital film scanners, etc.

However, it looks like pyexif hasn’t been updated in quite while. They recommend if theirs isn’t doing the trick to check out EXIF-py, so you should probably try that one first, as their sourceforge page seems to have some activity there lately, though not much. Finally, using PIL you could do this:

from PIL import Image
from PIL.ExifTags import TAGS

def get_exif(fn):
    ret = {}
    i = Image.open(fn)
    info = i._getexif()
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

Disclaimer:
I actually have no idea which is best, this is just what I was able to piece together with Google. :)


回答 1

我最近一直在使用pyexiv2,它似乎非常适合我的需求。也许它也适合您。

I’ve been using pyexiv2 myself recently, and it seems to fit my needs quite nicely. Perhaps it might suit yours as well.


回答 2

基于Exiv2的解决方案

Exiv2(exiv2:http://exiv2.org/ )是一个成熟的开源C ++库,支持将元数据读取和写入多种图像类型(JPEG,PNG,TIFF和许多原始格式),并了解标准(Xmp,IPTC)和Exif)和非标准元数据(“ Makernotes”),并且可以在多种平台(Windows,Linux和Mac)上运行。

Python与exiv2的绑定是:

  • gexiv2(多语言绑定,但适用于python 2.6 / 2.7 / 3.X):https ://wiki.gnome.org/gexiv2
  • pyexiv2(不再受支持,但可与python 2.6 / 2.7一起使用):http ://tilloy.net/dev/pyexiv2/

pyexiv2的一个优点是有一个可用于python 2.7的Windows构建。针对gexiv2的Windows构建请求位于此处:https ://bugzilla.gnome.org/show_bug.cgi?id = 712441

exiv2和绑定都是开源的(GPL)。

Exiv2 Based solutions

Exiv2 (exiv2: http://exiv2.org/) is a mature, open-source C++ library that supports reading and writing metadata to many image types (JPEG, PNG, TIFF and many raw formats), understands standard (Xmp, IPTC and Exif) and non-standard metadata (“Makernotes”), and runs on multiple platforms (Windows, Linux, and, with some work, Mac).

Python bindings to exiv2 are:

One advantage of pyexiv2 is that there is a windows build available for python 2.7. A windows build request for gexiv2 is here: https://bugzilla.gnome.org/show_bug.cgi?id=712441

exiv2 and the bindings are all open source (GPL).


回答 3

本文介绍了一个Python模块,用于使用纯Python编写EXIF元数据(而不仅仅是读取它们)。显然,PIL,pyexif或EXIF-py都不支持编写EXIF。pyexiv2似乎是尖端的,并且是特定于平台的。

This article describes a Python module for writing EXIF metadata (and not just reading them) using pure Python. Apparently, none of PIL, pyexif, nor EXIF-py support writing EXIF. pyexiv2 appears to be bleeding-edge and platform-specific.


回答 4

使用PIL :)

import os,sys
from PIL import Image
from PIL.ExifTags import TAGS

if __name__ == '__main__':
    for (k,v) in Image.open(sys.argv[1])._getexif().iteritems():
        print '%s = %s' % (TAGS.get(k), v)
    os.system('pause')

Use PIL :)

import os,sys
from PIL import Image
from PIL.ExifTags import TAGS

if __name__ == '__main__':
    for (k,v) in Image.open(sys.argv[1])._getexif().iteritems():
        print '%s = %s' % (TAGS.get(k), v)
    os.system('pause')

回答 5

http://redmine.yorba.org/projects/gexiv2/wiki(成为https://wiki.gnome.org/Projects/gexiv2)上的页面现在读取:

这对于Python 2或3同样适用,这使GExiv2成为仅支持Python 2的pyexiv2的理想替代品。

因此,GExiv2现在支持Python2和Python3。

好消息。

The page at http://redmine.yorba.org/projects/gexiv2/wiki (became https://wiki.gnome.org/Projects/gexiv2) reads now:

This will work equally well with either Python 2 or 3, which makes GExiv2 an excellent replacement for pyexiv2, which only supports Python 2.

So, both Python2 and Python3 are now supported by GExiv2.

Good news.


回答 6

您还可以在http://www.emilas.com/jpeg/上查看Gheorghe Milas的jpeg.py库,该库是“用于解析,读取和写入JPEG EXIF,IPTC和COM元数据的python库”。

缺点是他似乎通过DynDNS将其域托管在动态IP上,因此它并不总是可用。

You might also look at Gheorghe Milas’ jpeg.py library at http://www.emilas.com/jpeg/, which is “A python library to parse, read and write JPEG EXIF, IPTC and COM metadata.”

A drawback is that he appears to be hosting his domain on a dynamic IP via DynDNS, so it’s not always available.


回答 7

我用上面的Paolo代码以某种方式获得_getexif的attributeError。我正在使用Python 2.6.6和PIL 1.1.7。_getexif现在过时了吗?

这是一个对我有用的小修改。

from PIL import Image
from PIL.ExifTags import TAGS

def get_exif(fn):
    ret = {}
    i = Image.open(fn)
#    info = i._getexif()
    info = i.tag.tags
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

somehow i get an attributeError for _getexif with Paolo’s code above.. I am using Python 2.6.6 and PIL 1.1.7. Is _getexif obsolete now??

Here’s a small modification that worked for me.

from PIL import Image
from PIL.ExifTags import TAGS

def get_exif(fn):
    ret = {}
    i = Image.open(fn)
#    info = i._getexif()
    info = i.tag.tags
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

回答 8

我开始根据PIL中的代码编写自己的小型库。 在这里检查

I started to write my own small library which is based on the code in PIL. check it here.


回答 9

我一直在http://www.sno.phy.queensu.ca/~phil/exiftool/周围使用我自己的包装器 -原因是它非常完整,开发人员非常活跃。而且,不支持几乎所有图像格式对于该项目来说绝对是必不可少的。

当然,缺点是它不是python,因此您需要像我一样使用子进程调用。

I have been using my own wrappers around http://www.sno.phy.queensu.ca/~phil/exiftool/ — the reason is that it is very complete, the dev is very active. And not being able to support almost all image formats is a absolute showstopper for the project it is needed for

The drawback of course is that it isn’t python, so you would need to use subprocess calls, as I do.


回答 10

上有PIL和EXIF.py一些用法示例ASPN

There are some examples of PIL and EXIF.py usage on ASPN


回答 11

在Python 2.6中,模块的位置不同。用这个:

import Image    
from ExifTags import TAGS

In Python 2.6 the place of module is different. Use this:

import Image    
from ExifTags import TAGS