よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【PillowとNumpy】画像の色を変える

自民党議員は高齢者ばかりです。新型コロナがガチにヤバいウイルスなら「先週までいた○○派が半分お亡くなりになられ、」みたいな大変な状況も考えられた。



「○○県、第○区△△△△議員の入滅確定です。おめでとうございます。」

f:id:chayarokurokuro:20210205180346j:plain



しかし、銀座を飲み歩いたり会食でステーキを頬張るなどされておられるようですので余り心配はなさそうです。ダイヤモンドプリンセス号の件でウイルスの実力は分かっているのでしょう。

上の黄色い画像の元の画像は花が赤です。それを黄色く変えました。
今回は、色の変え方をメモしておきます。 Numpyとmatplotlib、それと画像保存用にPillowを使います。

import numpy as np
import matplotlib.pyplot as plt

# 元の画像
imgf = "senkyo.jpg"
# matplotlibでNumpy配列化
img = plt.imread(imgf)

# matplotlibで画像表示
plt.imshow(img)

f:id:chayarokurokuro:20210205180459j:plain
元の画像


この赤い花を最初の画像のように黄色く変えたい。

例えば座標の(50,100)や(100,100)辺りは赤い花があります。色の配列がどうなっているかをNumpyで確認します。
その前に配列全体を確認。

np.array(img)
array([[[201, 202, 206],
        [199, 203, 206],
        [200, 204, 207],
        ...,
        [177, 204, 137],
        [181, 203, 138],
        [180, 201, 134]],

       [[198, 202, 205],
        [199, 203, 206],
        [201, 205, 208],
        ...,
        [176, 205, 138],
        [180, 205, 139],
        [182, 204, 139]],

       [[199, 203, 206],
        [199, 203, 206],
        [200, 204, 207],
        ...,
        [171, 202, 134],
        [174, 203, 136],
        [177, 203, 138]],

       ...,

       [[221, 226, 229],
        [216, 221, 227],
        [217, 221, 230],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]],

       [[219, 224, 227],
        [223, 228, 234],
        [220, 223, 230],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]],

       [[217, 225, 228],
        [219, 220, 224],
        [214, 223, 228],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]]], dtype=uint8)



配列の形を確認。

img.shape
(353, 500, 3)



座標(100,100)の色(RGB)を確認。

img[100,100]
array([203,   0,   0], dtype=uint8)

赤いのでRGBのRが高い値、その他はゼロになっています。

赤かったら黄色に変える」ということがしたい。どうすれば出来るだろうか。

やり方は色々あるとは思いますが、 配列の分散を使ってみます。分散は配列のバラつき具合を示します。バラつきゼロなら分散もゼロ、バラついていれば分散の値は大きくなります。
座標(100,100)の分散値をNumpyで確認します。

# 分散
np.var(img[100,100])
9157.555555555553

だいぶん高い。座標(50,100)はどうでしょうか。

np.var(img[50,100])
8624.888888888887

座標(250,300)辺りは影になっていて黒い。どんな具合だろうか。

np.var(img[250,300])
3931.555555555555

よし、これで行こう。

全配列において、分散が4000以上なら、配列を黄色の[255,255,0]に置換する処理を施す。

imgc =  img.copy()
for i in range(imgc.shape[0]):
    for j in range(imgc.shape[1]):
        if np.var(imgc[i][j])>=4000:
            imgc[i][j]=np.array([255,255,0])
        

色を置換した画像の表示

plt.imshow(imgc)

画像省略(花が黄色で、目盛りのついた画像が表示される)



画像の保存をします。

matplotlibで、plt.savefig("保存名.jpg")としても良いのですが、それだと画像に目盛りがついたまま保存されてしまいます。
plt.axis("off")で目盛りを消しても、余白が残って画像自体が小さくなる。余白の削除が若干面倒なので、Pillowを使って保存します。これなら余白も目盛りも気にする必要はありません。

from PIL import Image

# Numpy配列をイメージオブジェクトに直す
imgo = Image.fromarray(imgc)

# オブジェクトを画像として保存
imgo.save("nyuumetsu.jpg")

上 : 変更前
下 : 変更後
f:id:chayarokurokuro:20210205181322j:plain


おめでとうございました。

ちなみに、画像の上下の結合は次のようにしました。

from PIL import Image

img1f = "senkyo.jpg"
img2f = "nyuumetsu.jpg"

# 画像取り込み
img1 = Image.open(img1f)
img2 = Image.open(img2f)

# 新規画像作成
dst = Image.new('RGB', (img1.width, img1.height + img2.height))

# 新規画像に貼り付け
dst.paste(img1,(0,0))
dst.paste(img2,(0,img1.height))

# 画像の保存
dst.save("con.jpg")



以上です。