【Pillow(PIL)】画像の縦横比(アスペクト比)を変えずにサイズ変更[Python]

  • URLをコピーしました!
目次

Pillow(PIL)

前回、Pythonの画像処理ライブラリPillow(PIL)を使って、トリミング、サイズ変更、保存を試してみました。

今回はサイズ変更に関して、画像の縦横比を変えない形で画像のサイズ変更をする方法を考えていきたいと思います。

ということで、前回のおさらいからいきましょう。

まずはpillow(PIL)のインポートと画像の読み込みです。

<セル1>

from PIL import Image

im = Image.open("Figure.jpg")

im

実行結果

後ほど元の画像のサイズを使用するので、わかりやすい変数に格納しておきましょう。

<セル2>

original_size = im.size

print(original_size)

実行結果
(1920, 1280)

幅のサイズ変更をして、高さを元の画像のままにしておくとこんな感じになります。

<セル3>

im_width1000 = im.resize((1000, original_size[1]))

print(im_width1000.size)

im_width1000

実行結果
(1000, 1280)

逆に高さを変更して、幅を元の画像のサイズのままにしておくとこうなります。

<セル4>

im_height1000 = im.resize((original_size[0], 1000))

print(im_height1000.size)

im_height1000

実行結果
(1920, 1000)

どちらでもせっかくの画像が歪んでしまっています。

そこで今回は重要比を保ちつつ、画像のサイズ変更を行う方法を探っていきます。

縦横比を保ちつつサイズ変更をする方法

縦横比を保ちつつサイズ変更するには、縦か横のどちらかのみのサイズが指定されているため、そこから逆側のサイズを計算する必要があります。

例えば、横2000ピクセル、縦1500ピクセルの画像の横を1000ピクセルにすることを考えてみましょう。

横が2000ピクセルから1000ピクセルへ変更されるため、2000/1000で2倍縮小されます。

そして同じ比率で縦を縮小するということは、1500/2=750にすれば良いということです。

つまり、縦の元のサイズ / (横の変更後のサイズ / 横の元のサイズ) という計算式が立てられます。

(注:上記の式をもう少し計算して 縦の元のサイズ*横の元のサイズ / 横の変更後のサイズ でもOKです)

プログラムとして書くとこうなります。

resized = im.resize((resize_width, original_size[1]/(original_size[0]/resize_width)))

これをプログラムに組み込んでいきましょう。

<セル5>

resize_width = 1000

resized = im.resize((resize_width, original_size[1]/(original_size[0]/resize_width)))

print(resized.size)

resized

実行結果
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-25-4ed78b04857e> in <module>
      1 resize_width = 1000
      2 
----> 3 resized = im.resize((resize_width, original_size[1]/(original_size[0]/resize_width)))
      4 
      5 print(resized.size)

/opt/anaconda3/lib/python3.7/site-packages/PIL/Image.py in resize(self, size, resample, box, reducing_gap)
   1903                 )
   1904 
-> 1905         return self._new(self.im.resize(size, resample, box))
   1906 
   1907     def reduce(self, factor, box=None):

TypeError: integer argument expected, got float

変更後の横幅を1000としたらエラーとなってしまいました。

原因はサイズ変更後のサイズに小数点が入ってしまったことにあります。

ということでいつでも整数となるようint()を使いましょう。

<セル5 修正>

resize_width = 1000

resized = im.resize((resize_width, int(original_size[1]/(original_size[0]/resize_width))))

print(resized.size)

resized

実行結果
(1000, 666)

同様にして、縦を指定した場合のプログラムも作ってみましょう。

<セル6>

resize_height = 1000

resized = im.resize((int(original_size[0]/(original_size[1]/resize_height)), resize_height))

print(resized.size)

resized

実行結果
(1500, 1000)

どちらも縦横比を変えずに画像サイズを変更することができました。

縦横比を変える、変えないどちらにでも対応できるようにする

せっかくなので、縦を基準に縦横比を変えずにサイズ変更、横を基準に縦横比を変えずにサイズ変更、縦も横もサイズ変更という3種類に対応できるプログラムを作ってみましょう。

サイズを指定する方法を[横, 縦]として、どちらかを0とした時に、縦横比を保ったまま0でない方にサイズ変更をする、また両方とも指定した場合には両方のサイズ変更を行う、というプログラムを作成すれば良さそうです。

もう少し詳しく書くと、以下の4つの場合分けをすれば良さそうです。

  1. 縦も横も0と指定した場合 => エラーを表示
  2. 横を0と指定した場合 => 縦の変更前後のサイズから横のサイズを算出して変更
  3. 縦を0と指定した場合 => 横の変更前後のサイズから縦のサイズを算出して変更
  4. 縦も横もサイズを指定した場合 => 指定されたサイズに変更

ということで作ってみたのがこちら。

<セル7>

resize_size = [1000, 500]

if resize_size[0] == 0 and resize_size[1] == 0:
    print("ERROR: resize_size should not be [0, 0]")
elif resize_size[0] == 0:
    resized = im.resize((int(original_size[0]/(original_size[1]/resize_height)), resize_height))
elif resize_size[1] == 0:
    resized = im.resize((resize_width, int(original_size[1]/(original_size[0]/resize_width))))
elif resize_size[0] != 0 and resize_size[1] != 0:
    resized = im.resize((resize_size[0], resize_size[1]))
    
print(resized.size)

resized

これで「resize_size」の二つの値によって、色々なサイズ変更が可能になりました。

大体やりたいことはできるようになってきたので、次回からプログラムの作成を進めていきましょう。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次