以前就想做一个马赛克合成的图片了,最近不务正业,就写了一个 方法很简单:
- 抓取一组图片的并缩放到统一大小
- 计算每张图片的rgb值的中值
- 所有的图片中值生成kd-tree
- 加载目标图片,并缩放到想要的结果图片的大小,然后创建结果图片(np.zeros)
- 每一小格结果图片的大小和抓取的小图大小一样,计算目标图片每小格的rgb 中值
- 查找最想进的小图,并用小图的rgb值填充到结果图片里
- 生成结果图片
马赛克图片生成代码:
import Image
import os
import numpy as np
from scipy import spatial
#calculate a mean rgb of an image
def meanRGB(img):
rgb = np.array(img.getdata())
mean_r = np.mean(rgb[:,0])
mean_g = np.mean(rgb[:,1])
mean_b = np.mean(rgb[:,2])
return [mean_r, mean_g, mean_b]
if __name__ == "__main__":
#grid size
mosaic_img_size = (20, 20)
#size of target image to generated
target_img_size = (1000, 1000)
target_img = Image.open("./VanGogh-starry_night_ballance1.jpg")
target_img = target_img.resize(target_img_size)
#grid images directory
directory = "./icons/"
listing = os.listdir(directory)
img_list = []
color_list = []
#load images and calculate mean rgb
for infile in listing:
if infile.endswith("jpg"):
img = Image.open(directory+infile)
img = img.resize(mosaic_img_size, Image.ANTIALIAS)
img_list.append(img)
color_list.append(meanRGB(img))
#create kdt for future pnn query
data = np.array(color_list)
tree = spatial.KDTree(data, leafsize=5)
count_x = 0
count_y = 0
new_image = np.zeros((target_img_size[0],target_img_size[1],3), dtype=np.uint8)
target_img_data = np.reshape(np.array(target_img.getdata()), (target_img_size[0],target_img_size[1],3))
length = mosaic_img_size[0]*mosaic_img_size[1]
#calculate mean rgb of each grid in the target image, search a nearest neighbor and fill the new image with
#the rgb values of the grid image
while count_x+mosaic_img_size[0] < target_img_size[0]:
count_y = 0
while count_y+mosaic_img_size[1] < target_img_size[1]:
mean_r = np.mean(target_img_data[count_x:count_x+mosaic_img_size[0],count_y:count_y+mosaic_img_size[1],0])
mean_g = np.mean(target_img_data[count_x:count_x+mosaic_img_size[0],count_y:count_y+mosaic_img_size[1],1])
mean_b = np.mean(target_img_data[count_x:count_x+mosaic_img_size[0],count_y:count_y+mosaic_img_size[1],2])
img_index = tree.query(np.array([mean_r,mean_g,mean_b]))[1]
new_image[count_x:count_x+mosaic_img_size[0],count_y:count_y+mosaic_img_size[1],:] = np.reshape(np.array(img_list[img_index].getdata()), (mosaic_img_size[0],mosaic_img_size[1],3))
count_y += mosaic_img_size[1]
count_x += mosaic_img_size[0]
#image created
im = Image.fromarray(new_image)
im.show()
im.save("./1VanGogh-starry_night_ballance1.jpg")
里面有些小bug,但不影响使用,譬如最右最下有一圈黑色的,是代码中某个逻辑没写好,没有填充进去,但是不管它了- -(貌似把小于号改成小于等于就可以了)
原图: 效果: 768的向量空间长度,图片量一定要大一些,要不然的结果会是,颜色很单一,拼出来的马赛克效果不好。自己的友邻太少了,可能结果会不理想,所以这里我抓了豆瓣活动上的豆友,570多位。。