Pythonで実装してみた
元画像を読み込むところ。BGRに分割し、分割された領域ごとの平均輝度値を求める
import cv2 import glob import numpy as np orgfile = "original02.png" orgimg = cv2.imread(orgfile) P=20 #分割する縦横のピクセル数 Nx = int(orgimg.shape[1]/P) Ny = int(orgimg.shape[0]/P) N = Nx*Ny assert(P*Nx==orgimg.shape[1]) #割り切れることを確認 assert(P*Ny==orgimg.shape[0]) #割り切れることを確認 print("横方向のピクセル数 width =",orgimg.shape[1]) print("横方向の分割数",Nx) print("縦方向のピクセル数 height=",orgimg.shape[0]) print("縦方向の分割数",Ny) orgimg_bgr = cv2.split(orgimg) orgmean_bgr = [[],[],[]] for ic in range(3): for iy in range(Ny): for ix in range(Nx): orgmean_bgr[ic].append(np.mean(orgimg_bgr[ic][iy*P:(iy+1)*P,ix*P:(ix+1)*P]))
アイコン画像を読み込むところ。各アイコンの平均輝度値を計算する
#モザイクで使うアイコン画像の読み込み files = glob.glob("thumbnails\\*.png") print("アイコン画像数",len(files)) meanb = [] meang = [] meanr = [] flag = [] W=150 #アイコン画像の横幅 for i,filename in enumerate(files): img = cv2.imread(filename) assert(img.shape[0]==W) assert(img.shape[1]==W) img_bgr = cv2.split(img) meanb.append(np.mean(img_bgr[0])) meang.append(np.mean(img_bgr[1])) meanr.append(np.mean(img_bgr[2])) flag.append(False)
端から作成するとモザイクっぽくならない。画像内でランダムな場所から似た画像を調べるため、乱数を作成
seed=0 rs = np.random.RandomState(seed) order = [] for i in range(N): order.append(i) rs.shuffle(order)
元画像のBGRの輝度値とアイコン画像の輝度値の差から、最も近いアイコン画像を選ぶ
imglist = [] for i in order: ix=i%Nx iy=i//Nx vmin = 255*3 jmin = -1 orgb = orgmean_bgr[0][i] orgg = orgmean_bgr[1][i] orgr = orgmean_bgr[2][i] for j,(b,g,r) in enumerate(zip(meanb,meang,meanr)): if flag[j]:continue v = abs(orgb-b)+abs(orgg-g)+abs(orgr-r) if vmin>v: vmin=v jmin=j imglist.append(jmin) flag[jmin]=True
アイコンを張り合わせてモザイク画像を作成、出力
dst = np.zeros((Ny*W, Nx*W, 3)) print("横方向のピクセル数 width =",dst.shape[1]) print("縦方向のピクセル数 height=",dst.shape[0]) for i,j in zip(order,imglist): img = cv2.imread(files[j]) ix=i%Nx iy=i//Nx dst[iy*W:(iy+1)*W, ix*W:(ix+1)*W] = img cv2.imwrite(f"mosaic_Nx{Nx}_Ny{Ny}.png",dst) print("出力完了")