2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

つい首をかしげてしまう、Exifのwidthとheightと縦と横の話

Posted at

はじめに

本記事はExif三部作の最終章となります。

毎度毎度ノリが違っていて恐縮です。

カメラを傾けて撮影された写真はどう扱われるか

ここでは2015年に出雲駅で撮影した**「富士通のパソコンFMVは出雲生まれ!」の顔出し看板**の写真を使う。
下の画像はWindows10のエクスプローラーの特大アイコン表示のスクリーンショットであって画像そのものではない。

fujitsu.jpg
exp.png

プロパティを確認すると幅1920×高さ2560の縦長画像だ。
prop.png

ところがExif情報を確認すると高さが1920で幅が2560となっている。デジカメはパナソニックのDMC-FH5。スマホではなくデジカメだから基本は横長、それを傾けて撮影している。

ExifTagsでExifを見る
{前略
 'ExifImageHeight': 1920,
 'ExifImageWidth': 2560,
 'Orientation': 6,
 後略}

その代わりと言っては何だが、ExifにはOrientationというプロパティが用意されている。
Orientationの定義は以下のとおり。数学的で誤解の余地のない、だが何ともわかりづらい表現になっている。

orientation.png

OpenCV

この画像のサイズをOpenCVで取得する。全体のソースは省略するが

print (imgCV.shape[:2])

# (2560, 1920)

となる。シェイプは行・列の順すなわち高さ・幅の順で、縦長画像であると正しく解釈されている。
デジカメは普通の姿勢では横長になるが90度回転して縦長になっているという事情は考慮されず、最終的な答えだけが出ている。

PIL

次にPILでサイズを確認する。

print (imgPIL.size)

# (2560, 1920)

となる。OpenCVと同じ…いや違う、PILのsizeは幅・高さの順。ということはOpenCVと扱いが逆になってるじゃないですか。
実際に画像を表示させてみると、
plt.png
ギャー!Orientationが考慮されておらずカメラの初期状態の向きになってる!

これを避けるにあたり、Orientationの値を取得して何番がどの向きだからと自前で計算して回転させる必要はない。Orientationに従って正しく回転してくれるメソッドexif_transposeがPILのImageOpsモジュールにあるのだ(バージョン6.0.0以降)。

ここはソースを挙げておこう。exif_transposeで回転するだけならExif情報を読み取るExifTagsを呼び出す必要はない。

ソース10
from PIL import Image, ImageOps
import matplotlib.pyplot as plt
import numpy as np

filename = "fujitsu.jpg"
imgPIL = Image.open(filename)

print (f"元画像のサイズ:{imgPIL.size}")
arrPIL = np.asarray(imgPIL)
plt.imshow(arrPIL)
plt.show()

img_transpose = ImageOps.exif_transpose(imgPIL)
print (f"回転後のサイズ:{img_transpose.size}")
arr_transpose = np.asarray(img_transpose)
plt.imshow(arr_transpose)
plt.show()
結果10
元画像のサイズ:(2560, 1920)
回転後のサイズ:(1920, 2560)

これでPILでも正しい向きで表示することができるようになった。
plt2.png

Excel VBA

ここで突然Excel VBAの話になる。実はこれまでの話は職場で後輩君にVBAのプログラムを書かせてみてはじめて気づいたことだったりする。

ExcelVBA
Sub AddPic()
    Dim filename As String
    Dim sh As Shape
    filename = "fujitsu.jpg"
    
    Set sh = ActiveSheet.Shapes.AddPicture( _
        filename:=ThisWorkbook.Path & "\" & filename, _
        linktofile:=True, _
        savewithdocument:=False, _
        Left:=0, _
        Top:=0, _
        Width:=-1, _
        Height:=-1)
    Debug.Print ("width:  " & sh.Width)
    Debug.Print ("height: " & sh.Height)
End Sub

結果はこう。倍率が100%だったり101%だったりするのはExcelの持病なのでスルーするとして、縦長画像が期待通りに縦長に貼られていることがわかる。
だが高さと幅では幅のほうが大きく、また回転角も設定されている。本来は横長画像だったのが90度回転していると正しく解釈されているわけだ。
excel.jpg
だがそのことに気づかずに「高さはHeightで幅はWidthだ」だけで進んでいってとんでもないことになり、後輩君と一緒に悩んで今回のネタを思いついたというわけ。

画像ビューアによる違い

ViXは約20年前に公開されたフリーの画像ビューア。脆弱性が見つかり使わないよう呼びかけられているが、これよりも使いやすいソフトにはいまだ出会っていない。
このソフトの数少ない欠点の一つがOrientationによる回転に対応していないこと。まあ、20年前のソフトだしねえ。

XnViewはかなり新しいフリーの画像ビューア。これはExifやGPSの情報を持っているとか回転されているとかいった情報がサムネイル上にアイコン表示されており、非常にわかりやすい。
私がXnViewに完全に乗り換えない理由は…本記事とは関係ないので省略。

ViX XnView
サムネイル fujitsu_vix.png fujitsu_xnview.png
プロパティ fujitsu_vix_exif.png fujitsu_xnview_exif.png

ギャラリー

ここで画像をお見せする意味はほとんどないのだが、コロナ禍でなかなか遠出できないので気分高揚のために画像を貼る。
また旅行に行きたいな。

2004年、デジカメで撮った音止の滝

fall_xnview.png
音止の滝は白糸の滝と同エリアにある富士山麓の名所。デジカメはキヤノンのIXY DIGITAL 200。デジカメなので基本は横長。
Orientationは1。そのため、カメラを90度倒して縦長になるように撮ったのだが、ビューアソフト・PIL・OpenCVともに横長のまま表示される。
Orientation=1の正しい挙動なのでこのことについて文句を言ってはいけない。先ほどのOrientationの定義をよく読むとよい。たとえカメラにセンサーがなく向きを検知できなくても、Orientationのデフォルト値は1なのだ。

2007年、デジカメで撮った昔の雑誌の1ページ

login_xnview.png
デジカメはパナソニックのDMC-FX9。デジカメなので基本は横長。Orientationは1。
XnViewのサムネイルでは普通に横長で表示されているが、ビューア画面では縦長で表示された。また、ViXではサムネイル・ビューア画面ともに期待通り縦長で表示された。横長が普通のはずなのに。
PILで表示させると、exif_transposeを使わずとも縦長で表示された。OpenCVでも同様。ありがたいことだが、なぜそうなるのかはわからない。

雑誌の詳細が気になる? ログイン創刊号(1982年)です。
login.jpg

2010年、ケータイで撮った東尋坊の写真

toujinbo_xnview.png
機種は東芝の911T。挙動は滝と同じ。縦長がデフォで、横長画像も縦長になってしまう。

2018年、スマホで撮ったサンフランシスコの写真

sf_xnview.png
HUAWEIのVNS-L22はよく知られているところのP9 liteのこと。
標準の姿勢では縦長画像になる(であろう)スマホのカメラ、Orientationは0(Unknown)となっている。縦長で表示されてしまうはずなのにありがたいことに横長で表示された。その理由はわからない。
Googleフォトも同様。

2018年、スマホで撮ったサンフランシスコ土産の写真

bag_xnview.png
こちらは横長に撮ったつもりが普通に縦長として保存されている。カメラを水平に構えて真下にある物体を撮影するにあたり、スマホの加速度センサー?を使った縦横判定が機能しなかったのだろう。
Googleフォトも同様。

終わりに

結局どうすればいいのかというと、よくわからない。というか、そもそも写真内のExif情報が当てにならないことが分かった。Orientationとは別の情報があるのだろうか。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?