物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

Python OpenCV 大量のアイコンからモザイクアートを作ってみる

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("出力完了")