小时候看见课本上有用人的照片作为基本元素拼出来的人脸,感觉特别有趣,后来学了ps发现ps做不出来这个效果(其实可以,但是人工很重,效果也不好。具体见:https://www.zhihu.com/question/23820935)后来学了算法后接触了一下图像处理,感觉其实这个东西不难做,把图片当作像素处理就好了,然后就想做一个玩玩。
原理其实很简单,把目标图像划分成许多区域,然后从给定的图库里寻找一张和本区域最相似的图片,将找到的图片贴到对应区域上,重复这一过程,然后就得到了目标图片。寻找相似图片的算法有很多,我这里直接套用了我以前的代码--计算图片三个通道的平均值,和目标做差,在图库中比较差的大小。寻找相似图片的算法还有很多,具体可以参考https://blog.youkuaiyun.com/u011397539/article/details/82982499哈希类算法和https://blog.youkuaiyun.com/weixin_39121325/article/details/84187453
选取不同算法有不同的考虑,虽然在相似度的比较上平均值法不好用,但取平均值只需计算一次,而直方图和余弦算法需要一次次计算和对比。(我的代码里算平均值没有对图片缩放,导致第一次算耗时特别长。)其次我觉得当图片缩小到一个接近于像素的小区域内时,直接对通道取平均值也许更接近原来像素的通道水平。
接下来就是代码了,第一部分是我之前写的相似度算法:
import os, sys
from PIL import Image
from PIL import ImageFilter
import numpy as np
import logging
import json
def act(di):
for i in di.keys():
di[i]=di[i][0]
return None
def CalWeight(str):
"""
what is the differ?
well, it is the index of this function is filename rather not the file pointer
"""
pos=0.0
temp=[]
img=Image.open(str)
#r, g, b = img.split()
for m in img.split():
total=0
m=np.array(m)
for n in m:
for i in n:
total+=i
pos=total/m.size
temp.append(pos)
return temp
class similar:
"""
self.input=args[1]
self.TargetFolder=args[2]
"""
def __init__(self, *args, **kwargs):
if len(args)==3: #or 3?
self.log=None
self.out={} #nmae:[weight_point]
self.standard=[]
self.Best_Match= ""
self.input=args[0]
self.TargetFolder=args[1]
self.log=args[2]
elif len(args)==2 and args[0]=="load":
self.load()
self.log=args[1]
else:
self.out={} #nmae:[weight_point]
self.input=""
self.TargetFolder=""
self.Best_Match="" #name
self.standard=[]
self.log=args[0]
return None
def _CalWeight(self,img):
pos=0.0
temp=[]
#r, g, b = img.split()
for m in img.split():