こんにちは、エンジニアのさもです
画像処理をwebサービスにしてみたのですが、なぜかスマホで撮影した画像が横向きになって出力されてしまいました。
いろいろ調べたので、対処方法をまとめておきます。
スポンサーリンク
まず、なぜ横向き担ってしまうかというと、そもそも画像が横向きだったから。
スマホでは、「横向き」という情報を画像が持っているので、向きを整えて表示しています。
その情報は、Exifという規格で保存された画像データに含まれていので、画像処理を行う場合は、まずこの情報を見て、画像を回転させておく必要があります。
また、Exifにどんな情報があるのかというと、以下のサイトで一覧を見ることができます。
とりあえず画像のExif情報を見てみます
from PIL import Image Image.open("./images/test.jpg")._getexif() #=> {34665: 38, 274: 1, 40962: 750, 40963: 1334}
こんな感じの辞書型データが出力されます。
キーが上記サイトのTAGIDで、valueがその値になります。
全ての画像で取れるわけではなくて、何も返ってこない、空の辞書が返ってくる、エラーになるなどバリエーションがあります。
_getexif()の出力を順番に見ていくと、
34665 -> Exif タグ
274 -> 画像方向
40962 -> 実効画像幅
40963 -> 実効画像高さ
ということらしいです。欲しい情報は274っぽいですね。orientationという名前の属性らしいです。値は1です。
orientationの意味はこちらのサイトでみれました。
Value | 0th Row | 0th Column |
1 | top | left side |
2 | top | right side |
3 | bottom | right side |
4 | bottom | left side |
5 | left side | top |
6 | right side | top |
7 | right side | bottom |
8 | left side | bottom |
上記の表で1をみてみると、0行目がトップで、0列目が左側です。普通の向きの画像ですね。
5のところをみると、0行目が左側、0列目がトップということなので、左右反転して、右に90度向きが変わった画像ということですね。頭の体操になりそうです。
画像の変換は以下のサイトを参考にしました
画像の向きを考慮した実装例は以下のようになります
from PIL import Image convert_image = { 1: lambda img: img, 2: lambda img: img.transpose(Image.FLIP_LEFT_RIGHT), # 左右反転 3: lambda img: img.transpose(Image.ROTATE_180), # 180度回転 4: lambda img: img.transpose(Image.FLIP_TOP_BOTTOM), # 上下反転 5: lambda img: img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Pillow.ROTATE_90), # 左右反転&反時計回りに90度回転 6: lambda img: img.transpose(Image.ROTATE_270), # 反時計回りに270度回転 7: lambda img: img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Pillow.ROTATE_270), # 左右反転&反時計回りに270度回転 8: lambda img: img.transpose(Image.ROTATE_90), # 反時計回りに90度回転 } img =Image.open("./images/test.jpg") try: exif = img._getexif() if exif: orientation = exif.get(0x112, 1) img = convert_image[orientation](img) except AttributeError: print(img) new_img = filter1(img) new_img.save("./images/new_test.jpg")
変換用の辞書を定義しておいて、画像を読み込み、exif情報があればそれにしたがって向きを変えます。
tryで例外処理を行っているのは、上でも書きましたが、_getexif()でエラーが出る場合があるからです。
png画像や、img.convert(“RGB”)した画像へ._getexif()をするとエラーになりました。
png画像はしょうがないですが、convert(“RGB”)は向きを整えてからにしましょう。
最後に
ずっと画像が横になる問題は気になっていたのですが、やっと解決できました。
railsで画像アップロードしても、特に横向きになったという経験はないのですが、ちゃんとライブラリが内部で変換してくれているのですかね。 ありがたや~
PCで画像を探してきて、それを加工して試してみるだけではこの処理は不要だと思うのですが、webサービスとして公開するときには少し注意が必要ですね。勉強になりました。
読者登録をしていただけると、ブログを続ける励みになりますので、よろしくお願いします。