コードDE描画

プログラミングで図を描く練習

【pythonista3】Pillowモジュールで画像を編集するImageChopsモジュールの使用例9選

pythonスクリプトでjpgやpmgなどの画像を加工、作成することが出来る。

簡単な画像処理にPillowモジュールが使われる。このモジュールは、読み込んだ画像をもとに新たな画像の作成、保存が出来る。

iOSアプリのpythonista3には標準でこのモジュールがあるがver1.1.7と古い。(2020年3月アップデート版現在。)

pythonista3内でPillowモジュールが出来ることを紹介する。

以下では、次の7つの操作を説明する。

  • オフセット
  • 四則演算
  • 比較
  • mod演算
  • 差の絶対値
  • グレースケール
  • 合成

使用環境

使っているアプリの都合上、Pillowモジュールが古い。そのため関数の引数など現在の仕様が若干異なる場合がある。

Pythonista3では最初からPillowモジュールが入っているためインストールは必要がない。

使い方

以下では次の画像を元にする。

sample.png
sample.png

この画像をsample.pngとする。

sample1.png
sample1.png

この画像をsample1.pngとする。

お借りした画像のリソース

以下のマスク画像を使う。

mask.png
mask.png

この画像をmask.pngとする。

オフセット

例1

画像のピクセルを上下左右にずらす。

  • 実行結果

オフセット画像
オフセット画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
w,h=img.size

# オフセットでピクセルをずらす
out=ImageChops.offset(img,int(w*0.55),int(h*0.55))

# 画像を保存
out.save('pillow-chops-1.png')
  • 解説

引数に画像オブジェクト、左右のピクセル、上下のピクセルを指定する。

ImageChops.offset(画像オブジェクト,x方向オフセット,y方向オフセット)

四則演算

例2

2つの画像の色のビット数を足し算する。

  • 実行結果

足し算した画像
足し算した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)

# ピクセルを足し算する
out=ImageChops.add(img,mask)

# 画像を保存
out.save('pillow-chops-2.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = min(image1 + image2 , 255)

足した結果が255を超えるようならば、255に丸める。

例3

2つの画像の色のビット数を引き算する。

  • 実行結果

引き算した画像
引き算した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)

# ピクセルを引き算する
out=ImageChops.subtract(img,mask)

# 画像を保存
out.save('pillow-chops-3.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = max(image1 - image2 , 0)

引いた結果が0を超えるようならば、0に丸める。

例4

2つの画像の色のビット数の明るさを掛け算する。

  • 実行結果

掛け算した画像
掛け算した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)

# ピクセルを掛け算する
out=ImageChops.multiply(img,mask)

# 画像を保存
out.save('pillow-chops-4.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = image1 * image2 / 255

白を1、黒を0として掛け算する。

例えばimage1=127,image2=127の場合次のような演算で63になる。

\begin{aligned}
& 127 * 127 / 255 \\
&=63
\end{aligned}
例5

2つの画像の色のビット数の暗さを掛け算する。

  • 実行結果

スクリーン演算した画像
スクリーン演算した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)
# スクリーン演算
# MAX = 255 として
# out = MAX - ((MAX - image1) * (MAX - image2) / MAX)
# ヘルプドキュメントより
out=ImageChops.screen(img,mask)

# 画像を保存
out.save('pillow-chops-5.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = 255 - (255 - image1) * (255 - image2) / 255

白を1、黒を0として掛け算する。 一度ネガポジ反転したものを掛け算して再度ネガポジ反転する。 つまり掛け算する時だけネガポジ反転した状態になっている。

例えばimage1=127,image2=127の場合次のような演算で191になる。

\begin{aligned}
& 255 - (255 - 127) * (255 - 127) / 255 \\
&=255 - 128 * 128 / 255 \\
&=255 - 64 \\
&=191
\end{aligned}

比較

例6

2つの画像の色のビット数の明るい方を比較する。

  • 実行結果

明るいピクセルを比較した画像
明るいピクセルを比較した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)
# 明るい方のピクセルを比較
out=ImageChops.lighter(img,mask)

# 画像を保存
out.save('pillow-chops-6.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = max(image1 , image2)

2つの画像の各ピクセルのRGB値の成分で数値の大きい方が採用される。

例7

2つの画像の色のビット数の暗い方を比較する。

  • 実行結果

暗いピクセルを比較した画像
暗いピクセルを比較した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)
# 暗い方のピクセルを比較
out=ImageChops.darker(img,mask)

# 画像を保存
out.save('pillow-chops-7.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = min(image1 , image2)

2つの画像の各ピクセルのRGB値の成分で数値の小さい方が採用される。

剰余演算

例8

2つの画像の色のビット数を足し算して剰余演算する。

  • 実行結果

足し算してmod演算した画像
足し算してmod演算した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)
# 足し算してmod演算
out=ImageChops.add_modulo(img,mask)

# 画像を保存
out.save('pillow-chops-8.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = (image1 + image2) % 256

足した結果が255を超えるようならば、256を引く。 例えばimage1=200,image2=200の場合次のような演算で144になる。

\begin{aligned}
& (200 + 200) mod 256 \\
&=400 mod 256 \\
&=144
\end{aligned}
例9

2つの画像の色のビット数を引き算して剰余演算する。

  • 実行結果

引き算してmod演算した画像
引き算してmod演算した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)
# 引き算してmod演算
out=ImageChops.subtract_modulo(img,mask)

# 画像を保存
out.save('pillow-chops-9.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = (image1 - image2) % 256

引いた結果が0を超えるようならば、256を足す。

例えばimage1=100,image2=200の場合次のような演算で156になる。

\begin{aligned}
& (100 - 200) mod 256 \\
&=-100 mod 256 \\
&=156
\end{aligned}

差の絶対値

例10

2つの画像の色のビット数の差分を演算する。

  • 実行結果

ピクセルの差の絶対値の画像
ピクセルの差の絶対値の画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
mask=Image.open('mask.png').convert('RGB').resize(img.size)
# 2つの画像のピクセルの差の絶対値
out=ImageChops.difference(img,mask)

# 画像を保存
out.save('pillow-chops-10.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = abs(image1 - image2)

色が同じなら0になり、片方が255、他方が0なら255になる。

グレースケール

例11

画像全体をグレースケールで塗りつぶす。

  • 実行結果

グレーで塗り潰した画像
グレーで塗り潰した画像

from PIL import Image,ImageChops

# 画像読み込み
img=Image.open('sample.png')
# グレースケールで塗り潰す
out=ImageChops.constant(img,128)

# 画像を保存
out.save('pillow-chops-11.png')
  • 解説

全てのピクセルのRGB成分値を引数で指定した値にして、グレースケールで塗り潰す。

ImageChops.constant(画像オブジェクト,グレースケール値)

合成

例12

2つの画像全体の色を、割合を指定して混ぜ合わせる。

合成前に画像のサイズを合わせておく。

  • 実行結果

ピクセルを混ぜた画像
ピクセルを混ぜた画像

from PIL import Image,ImageChops

# 画像読み込み
img1=Image.open('sample.png')
img2=Image.open('sample1.png').resize(img1.size)
# 2つのピクセルを混ぜる
out=ImageChops.blend(img1,img2,0.5)

# 画像を保存
out.save('pillow-chops-12.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = image1 * mask + image2 * (1 - mask) 

mask=0の場合はimage2になり、mask=1の場合はimage1になる。それ以外の値ではmaskの数値に応じた割合で合成する。

例13

2つの画像全体の色を、マスク画像を利用して混ぜ合わせる。

合成前に画像のサイズを合わせておく。

  • 実行結果

マスク画像で合成した画像
マスク画像で合成した画像

from PIL import Image,ImageChops

# 画像読み込み
img1=Image.open('sample.png')
img2=Image.open('sample1.png').resize(img1.size)
mask=Image.open('mask.png').convert('L').resize(img1.size)
# マスク画像で合成
out=ImageChops.composite(img1,img2,mask)

# 画像を保存
out.save('pillow-chops-13.png')
  • 解説

ピクセルのRGB値それぞれに次のように演算する。

output = (image1 * mask + image2 * (255 - mask)) / 255

マスク画像はグレースケールの画像を使う。マスク画像のピクセルが黒の場合はimage2になり、白の場合はimage1になる。それ以外の値ではグレーの度合いに応じた割合で合成する。

まとめ

ImageChopsモジュールには以下のメソッドがある。 2つの画像をピクセル単位で演算するものが多い。

  • オフセット
    • offset
  • 四則演算
    • add:足し算
    • subtract:引き算
    • multiply:明るさの掛け算
    • screen:暗さの掛け算
  • 比較
    • lighter:明るい方を比較
    • darker:暗い方を比較
  • 剰余演算
    • add_modulo:足し算して剰余
    • subtract_modulo:引き算して剰余
  • 差の絶対値
    • difference
  • グレースケール
    • constant:グレースケールで塗り潰す
  • 合成
    • blend:全体を合成
    • composite:マスク画像を使う

参考リンク