画像でモザイク画を作る(フォトモザイク)
画像をモザイク画に変換します。様々な色合いの画像を用意し15x10ピクセルに縮小、置き換え用画像にします。変換する画像を15x10ピクセルの碁盤目状のセルに分割し各セルのBGR平均値を出し、BGR平均値の近い置き換え用画像に置き換えます。
環境
準備
変換する画像はフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'photos'を作成しその中に保存しました。
mamechi.jpg
置き換え用画像は色味の異なる画像30枚、同じくフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'images'を作成しその中に保存しました。
コード
変換する画像の15x10ピクセルに分割し、各セルのB,G,R値の平均を求めます。置き換え用画像30枚のB,G,R値と比較し、最も近い置き換え用画像を選びます。近さは
B値の差の二乗 + G値の差の二乗 + R値の差の二乗
により求め、この値が最も小さい置き換え用画像を選びます。
import os import cv2 import numpy as np # 置き換え用画像格納リスト image_list = [] # 置き換え用画像BGR平均値格納リスト bgr_list = [] # セルのサイズ xpitch = 15 ypitch = 10 # imagesフォルダ内のファイルのリスト生成 files = os.listdir('images/') # imagesフォルダからファイル名を1つずつ取り出して処理 for i in files: pic = cv2.imread('images/'+i) resize = cv2.resize(pic, (xpitch, ypitch)) image_list.append(resize) bgr_list.append(np.mean(resize, axis=(1,0))) # 変換する画像を読み出し、セルサイズの整数倍にリサイズ # 同じサイズの黒画像(replace)を変換後画像用に作成 pic = cv2.imread('mamechi.jpg') height, width, channel = pic.shape resize = cv2.resize(pic, (width//xpitch*xpitch, height//ypitch*ypitch)) replace = np.zeros((height//ypitch*ypitch, width//xpitch*xpitch, 3), np.uint8) # 変換する画像をセルサイズに分割して読み出し、各セルのBGR平均値を算出 # 置き換え用画像と比較し、最も近い画像を選択、変換後画像に張り付ける for y in range(0, height//ypitch*ypitch, ypitch): for x in range(0, width//xpitch*xpitch, xpitch): part = pic[y:y+ypitch, x:x+xpitch] bgr = np.mean(part, axis=(1,0)) min_distance = 195075 for i in range(len(image_list)): j = image_list[i] k = bgr_list[i] distance = ((bgr[0]-k[0])**2+ (bgr[1]-k[1])**2+ (bgr[2]-k[2])**2) if distance<min_distance: min_distance = distance choice = j replace[y:y+ypitch, x:x+xpitch] = choice # 変換後画像の保存 cv2.imwrite('replace.jpg', replace)
実行結果
モザイク画に変換された画像(replace.jpg)が保存されます
もう少しモザイク画を滑らかにするために、①xpitch = 9 ypitch = 6に変更②モザイク用画像を30→47枚に増やしました。だいぶ滑らかになりました。
以下のサイトを参考にさせていただきました
Pythonの文法メモ > 【OpenCV】画像読み出しとサイズ・画素情報取得、切り抜き、貼り付け、チャネル操作
Pythonの文法メモ > 【OpenCV】画像サイズを変更するresize