ゆっくり開発

開発したい時に開発するブログ

画像に使われている色(RGB)を取得する

作ったもの

タイトルの通り,入力画像からその画像に使われているRGBを取得するプログラムを作成.ただし,入力画像は 100×100 にリサイズして扱う.

以下は入力画像とリサイズ後の画像

f:id:uttnaoki:20180901144040p:plain:w300 f:id:uttnaoki:20180901144422p:plain:w300

また,取得したRGBについて,各RGBが何ピクセル使われているかをカウントし,それらを降順で出力.

以下は出力結果の例

f:id:uttnaoki:20180901144217p:plain:w300

その後,使用頻度の多いRGBから画像に並べ,color_map.pngとして出力.

こんな感じ

f:id:uttnaoki:20180901144352p:plain:w300

ソースコード

from PIL import Image
import math

def resize_img (filename, size_tuple):
    # 既存ファイルを readモードで読み込み
    img = Image.open(filename, 'r')

    # リサイズ。サイズは幅と高さをtupleで指定
    return img.resize(size_tuple)

def count_pixel_colors (img):
    # 集計結果を格納する辞書配列
    img_pixel_colors = {}

    # 指定された座標のピクセルの RGB を取得し,そのRGBのカウンターをインクリメント
    def increment_color_counter (x, y):
        # (x,y)座標のピクセルの rgb を取得
        r,g,b = img.getpixel((x,y))
        # rgbを辞書配列のキーに使うために文字列化 (ex. 238-211-114)
        rgb = '-'.join([str(n) for n in [r,g,b]])
        # 取得した rgb が key になければ 値0 で追加
        img_pixel_colors.setdefault(rgb, 0)
        # 取得した rgb のカウンターをインクリメント
        img_pixel_colors[rgb] += 1

    # 画像の幅と高さを取得
    width, height = img.size
    # 画像に使われている色の数を集計し,辞書配列で img_pixel_colors に格納
    [increment_color_counter(x, y) for x in range(width) for y in range(height)]

    return img_pixel_colors

# ピクセル数の多い色順にピクセルを並べた画像を作成
def make_color_map (img_size, rgb_set, filename):
    img = Image.new('RGB', img_size)
    x=0
    y=0
    for rgb, count in sorted(rgb_set.items(),  key=lambda x: -x[1]):
        while count > 0:
            rgb_tuple = tuple([int(v) for v in rgb.split('-')])
            img.putpixel((x, y), rgb_tuple)
            x+=1
            if x == img_size[0]:
                x=0
                y+=1
            count-=1
    img.save(filename)

def main (img_name):
    # 出力画像のサイズ
    outimg_size = (100, 100)

    # 画像をリサイズすることでモザイク画像を取得
    mosaic_img = resize_img('pikachu.png', outimg_size)
    # 取得したモザイク画像を保存
    mosaic_img.save('mosaic_img.png', 'PNG', quality=100, optimize=True)

    # RGBに変換
    rgb_img = mosaic_img.convert('RGB')

    # 使われている色の種類を取得し,それらのピクセル数をカウント
    img_pixel_colors = count_pixel_colors(rgb_img)

    for k, v in sorted(img_pixel_colors.items(),  key=lambda x: -x[1]):
        print(k, v)

    # ピクセル数の多い色順にピクセルを並べた画像を作成
    make_color_map(outimg_size, img_pixel_colors, 'color_map.png')

if __name__ == '__main__':
    main('pikachu.png')

今後の展開

リサイズ処理で生成する画像について,使用するRGBを制限したい. 指定のRGBで画像を表現できるようにしたい. 例えば,マイクラのブロックの色だけで表現するとか.