はじめに
自分用の備忘録として使うことを想定しています。
ご覧になる際、理解や文章の拙いところが多々あると思われますがご了承ください。
また、仮に読んでいただけた場合、誤った理解などがあったら教えていただけると嬉しいです。
背景
- pythonで画像を編集する際に、HSV表色系を介して画像の彩度や明度を操作する必要が出てきた。
- pillowとopencvをそれぞれ試した。個人的にpillowでの操作の方が快適だった。
- いずれ、webアプリ上でpillowを使った画像処理をさせる予定。(今回は、それぞれの処理の速さは特に考えないこととする)
HSV表色系についての詳細、またpillowやopencvの導入等については省略する。
実装
動作環境
・Windows11
・Anaconda
python 3.11.5
pillow 10.2.0
実装したいこと
今回実装したい処理は、
・HSV表色系への変換
・Vの値の変更
・複数の画像の連結(縦横)
サンプルコード
from PIL import Image
img = Image.open('処理したい画像ファイルのパス')
img = img.resize((128, 128))
img = img.convert("HSV") # HSV表色系への変換
h, s, v = img.split()
base_v = v
img_list = []
for j in range(3):
v = base_v.point(lambda i: i+(32*(i-1))
new_img = Image.merge("HSV", (h, s, v))
imageList.append(new_img)
dst = Image.new("RGB", (128,384))
for k in range(3):
dst.paste(img_list[k], (128*k, 0)
dst.save('出力したいファイル名')
コードの簡易な説明+つまずいたこと
img = Image.open('処理したい画像ファイルのパス')
最初に画像の読み込み。
まずはImageオブジェクトを読み込まないと処理が始められないから、変数imgに格納する。
img = img.resize((128, 128))
画像のリサイズについて、サイズが更新されたImageオブジェクトが返される。
引数はサイズのタプルとする。括弧をつけることを忘れがち。
以下、公式のリファレンスより抜粋。
Image.resize(size, resample=None, box=None, reducing_gap=None)
Returns a resized copy of this image.
size – The requested size in pixels, as a 2-tuple:(width, height).
https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize
img = img.convert("HSV") # HSV表色系への変換
Image.convert()で、任意の表色系へ変更されたImageオブジェクトが返される。今回はHSVにしたいから”HSV”と指定する。
他にもいろいろな形式に変えられるようだが、詳細は省略。
h, s, v = img.split()
base_v = v
img_list = []
for j in range(3):
v = base_v.point(lambda i: i+(32*(i-1))
new_img = Image.merge("HSV", (h, s, v))
imageList.append(new_img)
次に、明度の値を調整するために、imgを各要素に分割する必要がある。
split()メソッドを使って分割。
そして、vの値を更新する。
このとき、pointメソッドを使って変更させる。彩度なども同様の書き方で変更できる。
pointについては、リファレンスを読んでもまだ理解できていないと感じる。Imageオブジェクト全体のピクセル値を変更しているという解釈でいいのだろうか。
変更したvの値を用いて、mergeメソッドを使うことで指定形式でImageオブジェクトにできる。
dst = Image.new("RGB", (128,384))
Image.newで出力画像を描画するためのImageオブジェクトを用意する。
for k in range(3):
dst.paste(img_list[k], (128*k, 0)
dst.save('出力したいファイル名')
用意したImageオブジェクトに、pasteメソッドで指定の位置に画像を張り付けていく。
引数として、Imageオブジェクトと、描画先の座標のタプル、そしてマスクを指定できる。
描画先の座標について、要素数2のタプルを指定すると、その座標が貼り付けたい画像の左上隅の座標となる。指定しない場合は要素数2のタプルの時と同様。
要素数4のタプルを指定すると、(左、上、右、下)と解釈される。
最後にImage.saveでImageオブジェクトをセーブして終了。
おわりに
今回使わなかったけど、処理したい画像が多くなるならnumpyを導入したほうがいいかもしれない。
また、サンプルコードはpng形式のRGB画像に対して処理を行い、png形式で出力することを想定している。
試しにjpg形式を読み込んでjpg形式で出力できることも確認できた。
試してはいないが、pillowを用いる際、PNG形式を読み込んでJPG形式にするときは、透過情報のが入っていることが原因で失敗する可能性があるらしい。
仮に拡張子の変更が必要ならそれに対応するための処理の追加も必要だろう。
参考文献