web-dev-qa-db-ja.com

Pythonを使用してEXIFで指定された方向で画像を回転する、サムネイルを含むPILなし

次のシナリオがあります。

  • IPhoneから画像をEXIF情報とともにPyhonソケットサーバーに送信しています。
  • 画像が撮影されたときの実際の方向に基づいて、画像が適切に方向付けられる必要があります。私は知っていますIOSは常に画像を横向き左として保存し、実際の向きをEXIFフィールド(EXIF.Image.Orientation)として追加します。
  • EXIFフィールドを読んで、実際の方向を確認しています。次に、wxpythonを使用して画像を適切な向きに回転させます。

EXIF操作にpyexiv2を使用しています。

問題:wxpythonを使用して画像を回転しているときに、サムネイルを含むEXIF情報が失われました。

私がしたこと:画像を回転する前にEXIFを読んでいます。 EXIFの方向フィールドをリセットします。それから、回転後に元に戻します。

問題:

EXIF内のサムネイルは回転しません。したがって、画像とサムネイルの向きは異なります。

質問は?

EXIF情報を保持したまま画像を回転させるPIL以外のモジュールはありますか?

サムネイルの向きに別のEXIFフィールドはありますか?

サムネイルだけを回転させる方法はありますか?

ご協力いただきありがとうございます...

22
ATOzTOA

私は解決策を見つけました...これをチェックしてください... http://www.atoztoa.com/2012/12/rotate-images-along-with-thumbnails-in.html

'''
Rotate Image
'''
import pyexiv2
import wx
import cStringIO
import os

def rotateImage(infile, device):
    try:
        # Read Metadata from the image
        metadata = pyexiv2.metadata.ImageMetadata(infile)
        metadata.read();

        # Let's get the orientation
        orientation = metadata.__getitem__("Exif.Image.Orientation")
        orientation = int(str(orientation).split("=")[1][1:-1])

        # Extract thumbnail
        thumb = metadata.exif_thumbnail

        angle = 0

        # Check the orientation field in EXIF and rotate image accordingly
        if device == "iPhone" or device == "iPad":
            # Landscape Left : Do nothing
            if orientation == ORIENTATION_NORMAL:
                angle = 0
            # Portrait Normal : Rotate Right
            Elif orientation == ORIENTATION_LEFT:
                angle = -90
            # Landscape Right : Rotate Right Twice
            Elif orientation == ORIENTATION_DOWN:
                angle = 180
            # Portrait Upside Down : Rotate Left
            Elif orientation == ORIENTATION_RIGHT:
                angle = 90

            # Resetting Exif field to normal
            print "Resetting exif..."
            orientation = 1
            metadata.__setitem__("Exif.Image.Orientation", orientation)

        # Rotate
        if angle != 0:
            # Just rotating the image based on the angle
            print "Rotating image..."
            angle = math.radians(angle)
            img = wx.Image(infile, wx.BITMAP_TYPE_ANY)
            img_centre = wx.Point( img.GetWidth()/2, img.GetHeight()/2 )
            img = img.Rotate( angle, img_centre, True )
            img.SaveFile(infile, wx.BITMAP_TYPE_JPEG)

            # Create a stream out of the thumbnail and rotate it using wx
            # Save the rotated image to a temporary file
            print "Rotating thumbnail..."
            t = wx.EmptyImage(100, 100)
            thumbStream = cStringIO.StringIO(thumb.data)
            t.LoadStream(thumbStream, wx.BITMAP_TYPE_ANY)
            t_centre = wx.Point( t.GetWidth()/2, t.GetHeight()/2 )
            t = t.Rotate( angle, t_centre, True )
            t.SaveFile(infile + ".jpg", wx.BITMAP_TYPE_JPEG)
            thumbStream.close()

            # Read the rotated thumbnail and put it back in the rotated image
            thumb.data = open(infile + ".jpg", "rb").read();
            # Remove temporary file
            os.remove(infile + ".jpg")

        # Write back metadata
        metadata.write();

    except Exception, e:
        print "Error rotating image... : " + str(e)
5
ATOzTOA

このソリューションは私のために働きます: PILサムネイルは私のイメージを回転していますか?

IPhoneかiPadかを確認する必要はありません。写真に方向タグがある場合–回転させます。

from PIL import Image, ExifTags

try:
    image=Image.open(filepath)

    for orientation in ExifTags.TAGS.keys():
        if ExifTags.TAGS[orientation]=='Orientation':
            break

        exif=dict(image._getexif().items())

        if exif[orientation] == 3:
            image=image.rotate(180, expand=True)
        Elif exif[orientation] == 6:
            image=image.rotate(270, expand=True)
        Elif exif[orientation] == 8:
            image=image.rotate(90, expand=True)

        image.save(filepath)
        image.close()
except (AttributeError, KeyError, IndexError):
    # cases: image don't have getexif
    pass

前:

Before

後: After

75
scabbiaza

Pillow> = 6.0. を使用している場合は、組み込みの ImageOps.exif_transpose 関数は、exifタグに従って画像を正しく回転します。

from PIL import ImageOps

image = ImageOps.exif_transpose(image)
15
GaretJax

@scabbiazaとほぼ同じ答えですが、回転の代わりに転置を使用します(パフォーマンスのため)。

from PIL import Image, ExifTags

try:
    image=Image.open(filepath)
    for orientation in ExifTags.TAGS.keys():
        if ExifTags.TAGS[orientation]=='Orientation':
            break
    exif=dict(image._getexif().items())

    if exif[orientation] == 3:
        image=image.transpose(PIL.Image.ROTATE_180)
    Elif exif[orientation] == 6:
        image=image.transpose(PIL.Image.ROTATE_270)
    Elif exif[orientation] == 8:
        image=image.transpose(PIL.Image.ROTATE_90)
    image.save(filepath)
    image.close()

except (AttributeError, KeyError, IndexError):
    # cases: image don't have getexif
    pass
0
Hyagoro

これは「python exif rotate」のトップアンサーなので、回転値のみが必要で、PILで画像を回転させない場合に備えて、追加を追加したいと思います-私の場合、QPixmapを使用してQGraphicsViewの画像を回転させたので、QPixmap変換の角度だけが必要でした。
exifを取得するためにPILを使用する上記の answer はかなり低速です。私のテストでは、PIL.Imageの作成/オープンに時間がかかるため、 piexif ライブラリの場合の6倍の時間がかかりました(6 ms vs 1 ms)。したがって、この場合はpiexifを使用することをお勧めします。

import piexif

def get_exif_rotation_angle(picture)

    exif_dict = piexif.load(picture)
    if piexif.ImageIFD.Orientation in exif_dict["0th"]:
        orientation = exif_dict["0th"][piexif.ImageIFD.Orientation]
        if orientation == 3:
            return 180
        Elif orientation == 6:
            return 90
        Elif orientation == 8:
            return 270
        else:
            return None
    else:
        return None

pictureすることができます ファイルパスまたはバイトオブジェクト。

参照: https://piexif.readthedocs.io/en/latest/sample.html#rotate-image-by-exif-orientation

0
user136036

https://medium.com/@giovanni_cortes/rotate-image-in-Django-when-saved-in-a-model-8fd98aac8f2a

このブログ投稿はそれを明確に説明しています。 _@receiver.._エラーが発生したため、_forms.py_コードを_models.py_または_cannot import model/view_に保持してください。

_rotate_image_メソッドの_models.py_&_@receiver.._コードも_models.py_に保持します。

「そのようなディレクトリはありません」などのエラーも発生しました。 _full_path_がメディアフォルダに正しく設定されていることを確認してください。

私はこのラインを使いました

fullpath = os.path.join(os.path.dirname(BASE_DIR)) + instance.fimage.url

0
joelvarma