小时候看见课本上有用人的照片作为基本元素拼出来的人脸,感觉特别有趣,后来学了ps发现ps做不出来这个效果(其实可以,但是人工很重,效果也不好。具体见:https://www.zhihu.com/question/23820935)后来学了算法后接触了一下图像处理,感觉其实这个东西不难做,把图片当作像素处理就好了,然后就想做一个玩玩。

原理其实很简单,把目标图像划分成许多区域,然后从给定的图库里寻找一张和本区域最相似的图片,将找到的图片贴到对应区域上,重复这一过程,然后就得到了目标图片。寻找相似图片的算法有很多,我这里直接套用了我以前的代码--计算图片三个通道的平均值,和目标做差,在图库中比较差的大小。寻找相似图片的算法还有很多,具体可以参考https://blog.csdn.net/u011397539/article/details/82982499哈希类算法和https://blog.csdn.net/weixin_39121325/article/details/84187453

选取不同算法有不同的考虑,虽然在相似度的比较上平均值法不好用,但取平均值只需计算一次,而直方图和余弦算法需要一次次计算和对比。(我的代码里算平均值没有对图片缩放,导致第一次算耗时特别长。)其次我觉得当图片缩小到一个接近于像素的小区域内时,直接对通道取平均值也许更接近原来像素的通道水平。

接下来就是代码了,第一部分是我之前写的相似度算法:

import os, sys
from PIL import Image
from PIL import ImageFilter
import numpy as np
import logging
import jsondef act(di):for i in di.keys():di[i]=di[i][0]return Nonedef CalWeight(str):"""what is the differ?well, it is the index of this function is filename rather not the file pointer"""pos=0.0temp=[]img=Image.open(str)#r, g, b = img.split()for m in img.split():total=0m=np.array(m)for n in m:for i in n:total+=ipos=total/m.sizetemp.append(pos)return tempclass similar:"""
self.input=args[1]
self.TargetFolder=args[2]"""def __init__(self, *args, **kwargs):if len(args)==3:    #or 3?self.log=Noneself.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=""   #nameself.standard=[]self.log=args[0]return Nonedef _CalWeight(self,img):pos=0.0temp=[]#r, g, b = img.split()for m in img.split():total=0m=np.array(m)for n in m:for i in n:total+=ipos=total/m.sizetemp.append(pos)return tempdef sort_out(self):#self.standard=self._CalWeight(Image.open(self.input))      maybe there are better way?m=list(self.out.keys())self.Best_Match=m[0]for n in m:try:if abs(self.out[n][0]-self.standard[0])+abs(self.out[n][1]-self.standard[1])+abs(self.out[n][2]-self.standard[2])<abs(self.out[self.Best_Match][0]-self.standard[0])+abs(self.out[self.Best_Match][1]-self.standard[1])+abs(self.out[self.Best_Match][2]-self.standard[2]):self.Best_Match=n#except IndexError:#self.log.debug("A gif detected,name is%s ",n)        #a gifexcept :self.log.warning("{}\n{}\n{}".format(self.out[n],self.standard,self.out[self.Best_Match]))#self.log.warning("{}\n{}\n{}".format(self.out[n][0],self.out[n][1],self.out[n][2]#                                                   ,self.standard[0],self.standard[1],self.standard[2]#                                                 ,self.out[self.Best_Match][0],self.out[self.Best_Match][1],self.out[self.Best_Match][2]))return self.Best_Matchdef Action(self):for i in self.out.keys():self.log.info(i)im = Image.open(i)self.out[i]=self._CalWeight(im)self.save()return self.outdef FindIM(self):''''''for infile in os.listdir(self.TargetFolder):try:temp=[self.TargetFolder,"\\",infile]    #好用吗?不!!!temp="".join(temp)im = Image.open(temp)print (infile, im.format, "%dx%d" % im.size, im.mode)self.out[temp]=[]except IOError:passreturn self.outdef FindReplanish(self):''''''back_up=self.out.copy()Real_seq=[]for infile in os.listdir(self.TargetFolder):try:temp=[self.TargetFolder,"\\",infile]    #好用吗?不!!!temp="".join(temp)im = Image.open(temp)print (infile, im.format, "%dx%d" % im.size, im.mode)Real_seq.append(temp)if not temp in self.out:img=Image.open(temp)self.out[temp]=self._CalWeight(img)except IOError:passfor i in self.out.keys():if not i in Real_seq:self.out.pop(i)self.save()return self.outdef save(self):with open("temp.json","w") as fw:fw.write(json.dumps(self.__dict__,cls=log_Encoder))def load(self):with open("temp.json","r") as fr:self.__dict__=json.load(fr)class log_Encoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, logging.Logger):return ""else:return json.JSONEncoder.default(self, obj)if __name__=="__main__":with open("info.log","w") as fw:passlogger = logging.getLogger('1')logger.setLevel(logging.INFO)f_handler = logging.FileHandler('info.log')f_handler.setLevel(logging.INFO)f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))logger.addHandler(f_handler)#si=similar("对比.PNG","D:\图片\桌面\合格品",logger)#si.FindIM()#si.Action()si=similar("load",logger)#act(si.out)#si.FindReplanish()si.sort_out()logger.info("最可能的是:%s",si.Best_Match)print("最可能的是:%s",si.Best_Match)im=Image.open(si.Best_Match)im.show()

上面的文件就是下面import的template文件,下面是程序主体:

import template
from PIL import Image
import logging
import numpy as npdef judge_prime(num):import math# 质数大于 1if num > 1:# 找到其平方根( √ ),减少算法时间square_num = math.floor( num ** 0.5 )# 查找其因子for i in range(2, (square_num+1)): #将平凡根加1是为了能取到平方根那个值if (num % i) == 0:print(num, "是合数")print(i, "乘于", num // i, "是", num)return i,num // ielse:print(num, "是质数")return False,True# 如果输入的数字小于或等于 1,不是质数else:print(num, "既不是质数,也不是合数")return False,Falseraise(ValueError("输入的图片太小,只有1像素"))def SplitImg(img,part_size):"""part_size和图片源大小决定分成几份"""w, h = img.sizepw, ph = part_sizetemp=[]assert w % pw == h % ph == 0for j in range(0, h, ph):for i in range(0, w, pw):temp.append(img.crop((i, j, i+pw, j+ph)).copy())return tempclass PixelImg(template.similar):"""这个类的定义啥的基本大致都和template中的一样"""def __init__(self, *args, **kwargs):self.img=Noneself.ImSeq=[]self.ResultImg=Nonereturn super().__init__(*args, **kwargs)def Action(self):return super().Action()def FindReplanish(self):return super().FindReplanish()def FindIM(self):return super().FindIM()def _CalWeight(self, img):return super()._CalWeight(img)def sort_out(self,target):self.standard=targetreturn super().sort_out()def ProImg(self):self.img=Image.open(self.input)size=self._HowToDiv()self.log.info("the partion of output image is {}".format(size))self.ImSeq=self._AreaGet(self.img,size)result=[]for m,n in enumerate(self.ImSeq):result.append(self.sort_out(n))self._ReAsseamble(result,size)return resultdef _AreaGet(self,img,size=(16,16)):Sequence=SplitImg(img,size)temp=[]for b,i in enumerate(Sequence):temp.append(self._CalWeight(i))return tempdef _HowToDiv(self):const=(8,8)horizontal=judge_prime(self.img.size[0])vertical=judge_prime(self.img.size[1])self.img=self.img.resize((self.img.size[0]-self.img.size[0]%const[0],self.img.size[1]-self.img.size[1]%const[1]))assert self.img.size[0]%const[0]==0 and self.img.size[1]%const[1]==0return constif horizontal[0]==False:if vertical[0]!=False:self.img=self.img.resize((self.img.size[1],self.img.size[1]))if vertical[0]>vertical[1]:     #try to let the image div as muchreturn vertical[1],vertical[1]else:return vertical[0],vertical[0]else:self.img=self.img.resize((self.img.size[0]-self.img.size[0]%16,self.img.size[1]-self.img.size[1]%16))assert self.img.size[0]%16==0 and self.img.size[1]%16==0return 16,16elif vertical[0]==False:self.img=self.img.resize((self.img.size[0],self.img.size[0]))if horizontal[0]>horizontal[1]:     #try to let the image div as muchreturn horizontal[1],horizontal[1]else:return horizontal[0],horizontal[0]else:   #if the image size are not primeif horizontal[0]>horizontal[1]:     #try to let the image div as muchif vertical[0]>vertical[1]:     #try to let the image div as muchreturn horizontal[1],vertical[1]else:return horizontal[1],vertical[0]else:if vertical[0]>vertical[1]:     #try to let the image div as muchreturn horizontal[0],vertical[1]else:return horizontal[0],vertical[0]def _ReAsseamble(self,seq,BL_size):im=Image.new("RGB",self.img.size)matrix=(self.img.size[0]//BL_size[0],self.img.size[1]//BL_size[1])  #reduce the calculateationsize_control=list(matrix)control=0  #index of seq ,maybe the index is worse than ...x=0y=0for control ,SigImg in enumerate(seq):unname=Image.open(seq[control])unname=unname.resize(BL_size).convert("RGB")im.paste(unname,(x*BL_size[0],y*BL_size[1],(x+1)*BL_size[0],(y+1)*BL_size[1]))x+=1if x==matrix[0]:y+=1x=0'''    while(size_control[1]>0):while(size_control[0]>0):unname=Image.open(seq[control])unname=unname.resize(BL_size).convert("RGB")im.paste(unname,((matrix[1]-size_control[1])*BL_size[0],(matrix[0]-size_control[0])*BL_size[1],(matrix[1]-size_control[1]+1)*BL_size[0],(matrix[0]-size_control[0]+1)*BL_size[1]))size_control[0]-=1control+=1size_control[0]=matrix[0]size_control[1]-=1'''im.show()im.save("result.png","PNG")return imif __name__=="__main__":with open("info.log","w") as fw:passlogger = logging.getLogger('1')logger.setLevel(logging.INFO)f_handler = logging.FileHandler('info.log')f_handler.setLevel(logging.INFO)f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))logger.addHandler(f_handler)#si=PixelImg("捕获.PNG","D:\图片\桌面\合格品",logger)#si.FindIM()#si.Action()#si.save()si=PixelImg("load",logger)si.input="捕获.PNG"si.FindReplanish()si.ProImg()

写的还是很随意的。

效果如下:

原图:

之后也有试着用直方图或者余弦法替换里面的相似度算法,不过由于我的代码杂乱,同一名字的函数或者相似类实现方法有很大不同,最后问题出了一大堆,放弃了。

用python制作马赛克式/蒙太奇拼图(小图片作为像素拼成大图片)相关推荐

  1. Python 制作马赛克拼合图像

    Python 制作马赛克拼合图像 文章目录 Python 制作马赛克拼合图像 知识点 效果: 环境 原理 RGB 色彩空间 HSV 色彩空间 RGB 与 HSV 色彩空间的转换 马赛克图片拼合 数据准 ...

  2. Python制作简单的终端交互小游戏

    Python制作简单的终端交互小游戏 因为最近的集训课程中,老师让我们把python,java,nodejs都需要掌握,本人最常使用的是java,python许久没有用过,就想写一段逻辑来帮助自己复习 ...

  3. 利用python制作马赛克图

    目录 爬虫 拼图 先是看到 英雄联盟大拼图的文章,里面用爬虫爬了LOL官网所有英雄的皮肤图片,然后做了一个拼图,他的拼图用其他软件做的,然后我就想到python应该也能做拼图吧,然后就搜到 使用Pyt ...

  4. 基于Python制作的消消乐小游戏

    导语 哈喽,好久不见.消失人口上线更新一波每月必出的 python 制作小游戏系列文章.本期我们将制作一个消消乐小游戏,让我们愉快地开始吧 开发工具 Python 版本:3.6.4 相关模块: pyg ...

  5. Java、python制作马赛克图片

    最近发现这个马赛克图片很有趣,所以就在网上找了一个简单的python库来使用,因为都是封装好的,所以使用起来很简单. python库:photomosaic 准备图片 因为制作图片都是封装好的代码,所 ...

  6. 利用Python制作王者荣耀出装小助手,引来了老板的注意!

    导语 T_T并不玩这些游戏... 单纯来蹭个热点... 大概是因为蹭热点需要的技术含量比较低? 就这样吧~~~ 利用Python制作命令行版的王者荣耀出装小助手. Let's Go! 开发工具 Pyt ...

  7. 用python制作一款录屏小工具

    天我想学习记录的内容是 -- 如何用python实现录屏. 1 写在前面 作为一名测试,有时候经常会遇到需要录屏记录自己操作,方便后续开发同学定位.以前都是用ScreenToGif来录屏制作成动态图, ...

  8. python制作录屏软件_【Python成长之路】用python制作一款录屏小工具(1)

    哈喽大家好,我是鹏哥. 今天我想学习记录的内容是 --如何用python实现录屏. ~~~上课铃~~~ 1 写在前面 作为一名测试,有时候经常会遇到需要录屏记录自己操作,方便后续开发同学定位.以前都是 ...

  9. Python 列表推导式的实用小技巧

    1. 产生200个1000以内的随机数 >>> L1=[random.randrange(1,1000) for _ in range(200)] >>> type ...

最新文章

  1. 在CentOS 6.9 x86_64的nginx 1.12.2上安装第三方模块set-misc-nginx-module实录
  2. 网络系统传输负载测试
  3. 【转】Docker —— 从入门到实践
  4. python写空气质量提醒_Python数据可视化:2018年空气质量分析
  5. 定义一个结构体指针需要分配存储空间?
  6. 微软发布了Visual Stduio 2010 RTM版本的虚拟机vhd文件,包含样例和动手实验(免费)...
  7. centos 7.2安装 java_centos7.2 linux系统上安装java环境
  8. cf 189B - Counting Rhombi
  9. Java join()原理分析
  10. 1008 计算(a+b)/c的值
  11. Java Data使用DataFormat类简单格式化
  12. OKR组织敏捷目标和绩效管理第二课 O、KR和案例讲解
  13. 【Python】速度起飞!替代 pandas 的 8 个神库
  14. pdf在线翻译_24个PDF在线小工具,免费在线翻译PDF文档。
  15. nginx的location匹配字段后斜杠的作用
  16. 作为泛娱乐圈专属域名,.fans岂能错过这匹年末综艺“黑马”?
  17. 一步一步SEO 之 网站内容SEO
  18. 手机App开发的基础概念
  19. 数字游戏——数位dp问题
  20. 完全用Python工作

热门文章

  1. 今日总结:错误码配置,关于TXT文件下载问题
  2. CASS11解决细等线字体样式显示为问号
  3. 计算机编程中的aa是什么意思,output是什么意思 output的例句 编程中output表示输出参数...
  4. Vue详解及综合案例
  5. Fastadmin操作
  6. 默认使用Adobe Acrobat DC打开设置
  7. PyQt5 主题美化
  8. 【吉他入门零基础】超全吉他自学视频教程下载
  9. K8S+Jenkins+Harbor+Docker+gitlab集群部署
  10. 证件照片如何换背景底色,3个免费制作证件照的方法,简单易学