やりたいこと
カラーで保存されたpngファイルがたくさんあります。ほとんどの画像は文字画像なのでグレースケールで保存して容量削減したいのだけれど、一部は写真画像なのでカラーのままにしたい、というケースがあり、Python3+Pillow でやってみました
事前調査
ググり力がたりないけれどいくつか似た要望を持っている人を見つけました。これらをもとに少し頑張ってみます
やったこと
ようはグレーっぽさなる指標を得られればいいわけです。それは、RGBからHSVに変換した際のS値(彩度)です。S値は白・黒・グレーの場合には値が0で, そこから離れるにしたがって値が大きくなり, 最大で255になります(Pillowの場合です。上限を100%にする流儀や1.0にする流儀もあるようです)。
そこで閾値としてS値の平均値を採用し、例えば10くらいにすると「写真画像」と「テキスト画像」の判別ができそうです。
というわけで上述の「やりたいこと」をスクリプト化してみました。
import os, sys, shutil
from PIL import Image
"""
通常のグレー判定なら閾値は1とかでもいいけど,
HTML Linkで色のついた画像の場合もグレーと判定したいなら10くらいの閾値は必要
"""
def check_vivid(im, threshold=10):
if im.mode in ["1", "L"]:
return (False, 0)
pxs = im.convert("HSV").getdata()
score = sum(map(lambda hsv: hsv[1], pxs)) / len(pxs)
return (score > threshold, score)
def main(src, dst):
for f in os.listdir(src):
f0, ext = os.path.splitext(f)
if not ext in [".jpg", ".jpeg", ".png"]:
continue
im = Image.open(os.path.join(src, f))
t,v = check_vivid(im)
print(t,v,f)
if t:
shutil.copy(os.path.join(src, f), os.path.join(dst, f))
else:
im.convert("L").save(os.path.join(dst, f"{f0}_g{ext}"))
if __name__ == "__main__":
d = os.path.abspath(sys.argv[1])
workdir = os.path.dirname(d)
src = os.path.basename(d)
dst = os.path.join(workdir, f"{src}_gray")
os.chdir(workdir)
os.makedirs(dst, exist_ok=True)
main(src, dst)
自分の用途ではこれで十分でした。知見があるひとはコメントくれると助かります。