Loading [MathJax]/jax/output/HTML-CSS/config.js
MENU

piexifでrawからのexifデータ取得

python

 Pythonにてraw現像の処理をいろいろ調べたり、追加したりしてきましたが、最後JPEG保存するにあたり、やはりEXIFデータの付加は必須だろうと思い、いろいろ調べてみたメモです。ライブラリとしては、piexifというのを使ってみました。

 結論から言ってしまうと、どのようなデータにも当てはまるような、汎用的な記述に行き着きませんでした。Canon限定でうまく動いているようですが、Olympus、Panasonic、iPhoneのrawデータでは一部書き換えが必要です。

piexif

 Python上でEXIFを簡単に扱うことができるライブラリです。執筆時点では1.1.3というバージョンになってます。日本の方が作ったもののようです。PyCharmからのインストールはいつものように、File-> Setting-> Project Interpreter から右上の+ボタンを押して、検索のところからpiexifと検索すると見つかり、インストールできました。他にもいろいろ扱う手段はありそうです。

 例えば、PIL (Pillow)でもこんな感じで、

1
2
3
from PIL import Image
 
exif = Image.open(filename).info['parsed_exif']

 扱えるようですが、rawデータから取ってきてくれなかったり、取ってきた後の編集もやや回りくどかったです。個人的には。

 また、他にも、ExifReadというライブラリもあるようです。こちらはrawでも一応開いてはくれましたが、書き込みの方法がぱっと見つからなかったので、あきらめました。こちらも

1
2
3
4
import exifread
 
f = open(filename, 'rb')
exif = exifread.process_file(f)

 こんな感じで読み込めました。手段はいろいろあるようです。

読み書き(Canon)

 基本的には読み取りをpiexifで行い、書き込みをPILで行う。という流れで扱います。サンプルコードがそうなっていたので。なので、処理フローは

1.piexifでrawを読み取り、exif取得
2.rawpyで現像 適宜exif書き換え
3.PILでexif付きで保存

 こんな感じになります。Canonのrawデータには素直にEXIFがついているのか、するっとこのフローを通せました。コードとしては、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from PIL import Image
import piexif
import rawpy
 
exif_dict = piexif.load(filename)
 
raw = rawpy.imread(filename)
img = raw.postprocess(use_camera_wb=True,
                      user_flip=0)
 
# 画像サイズだけ修正
exif_dict["0th"][piexif.ImageIFD.ImageWidth]  = img.shape[1]
exif_dict["0th"][piexif.ImageIFD.ImageLength] = img.shape[0]
 
exif_bytes = piexif.dump(exif_dict)
 
im = Image.fromarray(img)
im.save(savefile, "jpeg", exif=exif_bytes)

 こんな感じになるかと思います。現像時のオプションで、user_flipをあえて無回転に設定してEXIFの情報と合わせています。なので本来サイズを変更する必要はないのですが、サンプルとして。本当はJPEGに変換しているので、それ関連の値も付与した方がいいのかもしれませんが、必要性を感じたことがないので、個人的にはこれで十分です。

 ココで辞書に指定している[piexif.ImageIFD.ImageWidth]とかのキーですが、Web上に情報がなく、ソースコードを覗いて調べました。このソースにある数字とEXIFの仕様書から突き合わせて使います。いちいちソース覗くのが面倒なので、最後に該当コードの定義部だけ載せておきます。

読み書き(Panasonic)

 上記のCanonのケースはレギュラーケースで、他の会社のRawデータはそのまま使えませんでした。Panasonic(DMC-GM1)のRawデータには不正なタグがあるのか、読み込めたのですが、書き込めなかったです。なので不正なタグを消して対応することになりました。

 コードは

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from PIL import Image
import piexif
import rawpy
 
exif_dict = piexif.load(filename)
 
raw = rawpy.imread(filename)
img = raw.postprocess(use_camera_wb=True,
                      user_flip=0)
 
# 画像サイズだけ修正
exif_dict["0th"][piexif.ImageIFD.ImageWidth]  = img.shape[1]
exif_dict["0th"][piexif.ImageIFD.ImageLength] = img.shape[0]
# この3つのタグを消去(何がいけないのか不明)
del exif_dict["0th"][piexif.ImageIFD.ProcessingSoftware]
del exif_dict["0th"][piexif.ImageIFD.XResolution]
del exif_dict["0th"][piexif.ImageIFD.YResolution]
 
exif_bytes = piexif.dump(exif_dict)
 
im = Image.fromarray(img)
im.save(savefile, "jpeg", exif=exif_bytes)

 これで動きました。この3つのタグが悪さをしているようです。なぜか不明です。ダンプすると確かにおかしな値が入ってます。

 他にもJPEGにしてしまえば不要なタグはいろいろありそうですが、いったん放置しときます。

読み書き(Olympus)

 これが厄介。完全に壊れた値が読み込まれています。機種はOMD E-M10 MkIIです。一部書き換えてどうにかなるレベルではないです。現像処理自体はできるのですごく残念ですが、諦めます。フォーマットの問題なのかなぁ…。

 こいつを使う場合には、raw+JPEGで撮影しておいて、JPEGのEXIFをコピーすることで回避しようと思います。JPEGであればこのコードのままで読み込めました。なので、現像時にJPEGも用意しておく必要が出てきます。少しダサいですが、しょうがないです。

読み書き(iPhone SE)

 iPhoneのRAWデータもいくつかタグを消す必要がありました。こいつの場合には、上記Panasonicのコードのように、6つのタグを消し去るとうまく行きました。

1
2
3
4
5
6
7
# この6つのタグを消去
del exif_dict["0th"][piexif.ImageIFD.TileWidth]
del exif_dict["0th"][piexif.ImageIFD.TileLength]
del exif_dict["0th"][piexif.ImageIFD.TileOffsets]
del exif_dict["0th"][piexif.ImageIFD.TileByteCounts]
del exif_dict["0th"][piexif.ImageIFD.BlackLevel]
del exif_dict["0th"][piexif.ImageIFD.AsShotNeutral]

 他にも消して差し支えないようなタグ(現像してしまえば不要なタグ)もいっぱい入ってましたが、最低限は上記で済みそうです。

まとめ

 いろいろ妥協をしていますが、ひとまず手元にあるrawデータのEXIFのコピーを取ることができました。現像したJPEGには付けときたいですよね。現像したいメーカーのRAWデータに応じたコードの修正が必要になりますが、うまい方法が見つかりませんでした。

 ちまちま必須タグだけ取り出せばよいのかもしれませんが、メーカーオリジナルタグもあるし、レンズ情報もないオールドレンズの写真もあるので、めんどくさい。ので深追いはやめにします。

スポンサーリンク

おまけ

 piexifのタグ定義の箇所を抜粋しときます。よくにらめっこしたので。ファイルは、_exif.pyってのでした。(作者様にお断り入れた方がいいのかな…、こういうのって)

 大きく[“0th”]のタグと、[“Exif”]のタグと、[“GPS”]のタグの3つをいじることが多いです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
class ImageIFD:
    """Exif tag number reference - 0th IFD"""
    ProcessingSoftware = 11
    NewSubfileType = 254
    SubfileType = 255
    ImageWidth = 256
    ImageLength = 257
    BitsPerSample = 258
    Compression = 259
    PhotometricInterpretation = 262
    Threshholding = 263
    CellWidth = 264
    CellLength = 265
    FillOrder = 266
    DocumentName = 269
    ImageDescription = 270
    Make = 271
    Model = 272
    StripOffsets = 273
    Orientation = 274
    SamplesPerPixel = 277
    RowsPerStrip = 278
    StripByteCounts = 279
    XResolution = 282
    YResolution = 283
    PlanarConfiguration = 284
    GrayResponseUnit = 290
    GrayResponseCurve = 291
    T4Options = 292
    T6Options = 293
    ResolutionUnit = 296
    TransferFunction = 301
    Software = 305
    DateTime = 306
    Artist = 315
    HostComputer = 316
    Predictor = 317
    WhitePoint = 318
    PrimaryChromaticities = 319
    ColorMap = 320
    HalftoneHints = 321
    TileWidth = 322
    TileLength = 323
    TileOffsets = 324
    TileByteCounts = 325
    SubIFDs = 330
    InkSet = 332
    InkNames = 333
    NumberOfInks = 334
    DotRange = 336
    TargetPrinter = 337
    ExtraSamples = 338
    SampleFormat = 339
    SMinSampleValue = 340
    SMaxSampleValue = 341
    TransferRange = 342
    ClipPath = 343
    XClipPathUnits = 344
    YClipPathUnits = 345
    Indexed = 346
    JPEGTables = 347
    OPIProxy = 351
    JPEGProc = 512
    JPEGInterchangeFormat = 513
    JPEGInterchangeFormatLength = 514
    JPEGRestartInterval = 515
    JPEGLosslessPredictors = 517
    JPEGPointTransforms = 518
    JPEGQTables = 519
    JPEGDCTables = 520
    JPEGACTables = 521
    YCbCrCoefficients = 529
    YCbCrSubSampling = 530
    YCbCrPositioning = 531
    ReferenceBlackWhite = 532
    XMLPacket = 700
    Rating = 18246
    RatingPercent = 18249
    ImageID = 32781
    CFARepeatPatternDim = 33421
    CFAPattern = 33422
    BatteryLevel = 33423
    Copyright = 33432
    ExposureTime = 33434
    ImageResources = 34377
    ExifTag = 34665
    InterColorProfile = 34675
    GPSTag = 34853
    Interlace = 34857
    TimeZoneOffset = 34858
    SelfTimerMode = 34859
    FlashEnergy = 37387
    SpatialFrequencyResponse = 37388
    Noise = 37389
    FocalPlaneXResolution = 37390
    FocalPlaneYResolution = 37391
    FocalPlaneResolutionUnit = 37392
    ImageNumber = 37393
    SecurityClassification = 37394
    ImageHistory = 37395
    ExposureIndex = 37397
    TIFFEPStandardID = 37398
    SensingMethod = 37399
    XPTitle = 40091
    XPComment = 40092
    XPAuthor = 40093
    XPKeywords = 40094
    XPSubject = 40095
    PrintImageMatching = 50341
    DNGVersion = 50706
    DNGBackwardVersion = 50707
    UniqueCameraModel = 50708
    LocalizedCameraModel = 50709
    CFAPlaneColor = 50710
    CFALayout = 50711
    LinearizationTable = 50712
    BlackLevelRepeatDim = 50713
    BlackLevel = 50714
    BlackLevelDeltaH = 50715
    BlackLevelDeltaV = 50716
    WhiteLevel = 50717
    DefaultScale = 50718
    DefaultCropOrigin = 50719
    DefaultCropSize = 50720
    ColorMatrix1 = 50721
    ColorMatrix2 = 50722
    CameraCalibration1 = 50723
    CameraCalibration2 = 50724
    ReductionMatrix1 = 50725
    ReductionMatrix2 = 50726
    AnalogBalance = 50727
    AsShotNeutral = 50728
    AsShotWhiteXY = 50729
    BaselineExposure = 50730
    BaselineNoise = 50731
    BaselineSharpness = 50732
    BayerGreenSplit = 50733
    LinearResponseLimit = 50734
    CameraSerialNumber = 50735
    LensInfo = 50736
    ChromaBlurRadius = 50737
    AntiAliasStrength = 50738
    ShadowScale = 50739
    DNGPrivateData = 50740
    MakerNoteSafety = 50741
    CalibrationIlluminant1 = 50778
    CalibrationIlluminant2 = 50779
    BestQualityScale = 50780
    RawDataUniqueID = 50781
    OriginalRawFileName = 50827
    OriginalRawFileData = 50828
    ActiveArea = 50829
    MaskedAreas = 50830
    AsShotICCProfile = 50831
    AsShotPreProfileMatrix = 50832
    CurrentICCProfile = 50833
    CurrentPreProfileMatrix = 50834
    ColorimetricReference = 50879
    CameraCalibrationSignature = 50931
    ProfileCalibrationSignature = 50932
    AsShotProfileName = 50934
    NoiseReductionApplied = 50935
    ProfileName = 50936
    ProfileHueSatMapDims = 50937
    ProfileHueSatMapData1 = 50938
    ProfileHueSatMapData2 = 50939
    ProfileToneCurve = 50940
    ProfileEmbedPolicy = 50941
    ProfileCopyright = 50942
    ForwardMatrix1 = 50964
    ForwardMatrix2 = 50965
    PreviewApplicationName = 50966
    PreviewApplicationVersion = 50967
    PreviewSettingsName = 50968
    PreviewSettingsDigest = 50969
    PreviewColorSpace = 50970
    PreviewDateTime = 50971
    RawImageDigest = 50972
    OriginalRawFileDigest = 50973
    SubTileBlockSize = 50974
    RowInterleaveFactor = 50975
    ProfileLookTableDims = 50981
    ProfileLookTableData = 50982
    OpcodeList1 = 51008
    OpcodeList2 = 51009
    OpcodeList3 = 51022
    NoiseProfile = 51041
    ZZZTestSlong1 = 60606
    ZZZTestSlong2 = 60607
    ZZZTestSByte = 60608
    ZZZTestSShort = 60609
    ZZZTestDFloat = 60610
 
 
class ExifIFD:
    """Exif tag number reference - Exif IFD"""
    ExposureTime = 33434
    FNumber = 33437
    ExposureProgram = 34850
    SpectralSensitivity = 34852
    ISOSpeedRatings = 34855
    OECF = 34856
    SensitivityType = 34864
    StandardOutputSensitivity = 34865
    RecommendedExposureIndex = 34866
    ISOSpeed = 34867
    ISOSpeedLatitudeyyy = 34868
    ISOSpeedLatitudezzz = 34869
    ExifVersion = 36864
    DateTimeOriginal = 36867
    DateTimeDigitized = 36868
    OffsetTime = 36880
    OffsetTimeOriginal = 36881
    OffsetTimeDigitized = 36882
    ComponentsConfiguration = 37121
    CompressedBitsPerPixel = 37122
    ShutterSpeedValue = 37377
    ApertureValue = 37378
    BrightnessValue = 37379
    ExposureBiasValue = 37380
    MaxApertureValue = 37381
    SubjectDistance = 37382
    MeteringMode = 37383
    LightSource = 37384
    Flash = 37385
    FocalLength = 37386
    Temperature = 37888
    Humidity = 37889
    Pressure = 37890
    WaterDepth = 37891
    Acceleration = 37892
    CameraElevationAngle = 37893
    SubjectArea = 37396
    MakerNote = 37500
    UserComment = 37510
    SubSecTime = 37520
    SubSecTimeOriginal = 37521
    SubSecTimeDigitized = 37522
    FlashpixVersion = 40960
    ColorSpace = 40961
    PixelXDimension = 40962
    PixelYDimension = 40963
    RelatedSoundFile = 40964
    InteroperabilityTag = 40965
    FlashEnergy = 41483
    SpatialFrequencyResponse = 41484
    FocalPlaneXResolution = 41486
    FocalPlaneYResolution = 41487
    FocalPlaneResolutionUnit = 41488
    SubjectLocation = 41492
    ExposureIndex = 41493
    SensingMethod = 41495
    FileSource = 41728
    SceneType = 41729
    CFAPattern = 41730
    CustomRendered = 41985
    ExposureMode = 41986
    WhiteBalance = 41987
    DigitalZoomRatio = 41988
    FocalLengthIn35mmFilm = 41989
    SceneCaptureType = 41990
    GainControl = 41991
    Contrast = 41992
    Saturation = 41993
    Sharpness = 41994
    DeviceSettingDescription = 41995
    SubjectDistanceRange = 41996
    ImageUniqueID = 42016
    CameraOwnerName = 42032
    BodySerialNumber = 42033
    LensSpecification = 42034
    LensMake = 42035
    LensModel = 42036
    LensSerialNumber = 42037
    Gamma = 42240
 
 
class GPSIFD:
    """Exif tag number reference - GPS IFD"""
    GPSVersionID = 0
    GPSLatitudeRef = 1
    GPSLatitude = 2
    GPSLongitudeRef = 3
    GPSLongitude = 4
    GPSAltitudeRef = 5
    GPSAltitude = 6
    GPSTimeStamp = 7
    GPSSatellites = 8
    GPSStatus = 9
    GPSMeasureMode = 10
    GPSDOP = 11
    GPSSpeedRef = 12
    GPSSpeed = 13
    GPSTrackRef = 14
    GPSTrack = 15
    GPSImgDirectionRef = 16
    GPSImgDirection = 17
    GPSMapDatum = 18
    GPSDestLatitudeRef = 19
    GPSDestLatitude = 20
    GPSDestLongitudeRef = 21
    GPSDestLongitude = 22
    GPSDestBearingRef = 23
    GPSDestBearing = 24
    GPSDestDistanceRef = 25
    GPSDestDistance = 26
    GPSProcessingMethod = 27
    GPSAreaInformation = 28
    GPSDateStamp = 29
    GPSDifferential = 30
    GPSHPositioningError = 31
python現像
スポンサーリンク
キャンプ工学

コメント

タイトルとURLをコピーしました