Python照片合成

article/2025/9/18 12:06:51

文章目录

      • 前言
      • Github
      • 效果
      • 实现过程
      • 整体代码

前言

看电影的时候发现一个照片墙的功能,觉得这样生成照片挺好玩的,于是就动手用Python做了一下,觉得用来作照片纪念的效果可能会不错。

P:后面了解到我想做的功能叫蒙太奇拼图,所以这篇博客记录先留着,闲下来会去看一下蒙太奇拼图的算法

Github

https://github.com/jiandi1027/photo.git

效果

在这里插入图片描述
在这里插入图片描述

实现过程

1.获取图片文件夹的图片个数N,将底图拆分成XY块区域,且使X * Y<N
(为了保证整体的协调,会舍弃几张图片,比如5张时可能只取2
2的4张图片)

	# 打开图片 base = Image.open(baseImgPath)base = base.convert('RGBA')# 获取图片文件夹图片并打乱顺序files = glob.glob(imagesPath + '/*.*')  random.shuffle(files)# 图片数量num = len(files)# 底图大小x = base.size[0]y = base.size[1]# 每张图片数量 这个公式是为了xNum * yNum 的总图片数量<num又成比例的最大整数yNum = int((num / (y / x)) ** 0.5)if yNum == 0:yNum = 1xNum = int(num / yNum)# 图片大小 因为像素没有小数点 为防止黑边所以+1xSize = int(x / xNum) + 1ySize = int(y / yNum) + 1

在这里插入图片描述

2.遍历文件夹的图片,依次填充生成最终合成图

for file in files:fromImage = Image.open(file)i = int(num % xNum)j = int(num / xNum)out = fromImage.resize((xSize, ySize), Image.ANTIALIAS).convert('RGBA')toImage.paste(out, (i * xSize, j * ySize))toImage = toImage.convert('RGBA')img = Image.blend(base, toImage, 0.3)# 显示图片photo = ImageTk.PhotoImage(img)showLabel.config(image=photo)showLabel.image = photoif num < xNum * yNum:num = num + 1

3.生成结束后保存图片
toImage.save(‘generator.png’)
img.save(“final.png”)
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190805150649966.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoaWppYW5kaQ==,size_16,color_FFFFFF,t_70
4.建立可视化界面
在这里插入图片描述
5.Pyinstaller生成exe可执行文件
安装pyinstaller模块,执行命令生成exe文件

pyinstaller -F -w test.py (-w就是取消窗口)

整体代码

Python的语法和设计规范还没学过,所以代码规范代码复用之类的可能会有点不到位,本博文主要是一个思路与整体流程的记录。
后续又优化了一下一些特效,比如合成图片采用随机位置,增加黑白,流年等显示特效,透明度自选等。

import PIL.Image as Image
import glob
import random
import tkinter.filedialog
from tkinter.filedialog import askdirectory, Label, Button, Radiobutton, Entry
import threadingimport numpy as np
from PIL import ImageTkalpha = 0.3
imagesPath = ''# 滑动条回调 修改透明度
def resize(ev=None):global alphaalpha = scale.get() / 100# 黑白
def blackWithe(image):# r,g,b = r*0.299+g*0.587+b*0.114im = np.asarray(image.convert('RGB'))trans = np.array([[0.299, 0.587, 0.114], [0.299, 0.587, 0.114], [0.299, 0.587, 0.114]]).transpose()im = np.dot(im, trans)return Image.fromarray(np.array(im).astype('uint8'))# 流年
def fleeting(image, params=12):im = np.asarray(image.convert('RGB'))im1 = np.sqrt(im * [1.0, 0.0, 0.0]) * paramsim2 = im * [0.0, 1.0, 1.0]im = im1 + im2return Image.fromarray(np.array(im).astype('uint8'))# 旧电影
def oldFilm(image):im = np.asarray(image.convert('RGB'))# r=r*0.393+g*0.769+b*0.189 g=r*0.349+g*0.686+b*0.168 b=r*0.272+g*0.534b*0.131trans = np.array([[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]).transpose()# clip 超过255的颜色置为255im = np.dot(im, trans).clip(max=255)return Image.fromarray(np.array(im).astype('uint8'))# 反色
def reverse(image):im = 255 - np.asarray(image.convert('RGB'))return Image.fromarray(np.array(im).astype('uint8'))def chooseBaseImagePath():name = tkinter.filedialog.askopenfilename()if name != '':global baseImgPathbaseImgPath = namebaseImageLabel.config(text=name)baseImg = Image.open(baseImgPath)widthEntry.delete(0, tkinter.END)heightEntry.delete(0, tkinter.END)widthEntry.insert(0, baseImg.size[0])heightEntry.insert(0, baseImg.size[1])else:baseImageLabel.config(text="您没有选择任何文件")def chooseImagesPath():name = askdirectory()if name != '':global imagesPathimagesPath = nameImagesLabel.config(text=name)else:ImagesLabel.config(text="您没有选择任何文件")def thread_it(func, *args):# 创建t = threading.Thread(target=func, args=args)# 守护 !!!t.setDaemon(True)# 启动t.start()def test():MyThread(1, "Thread-1", 1).start()baseImgPath = ''def generator():baseImg = Image.open(baseImgPath)baseImg = baseImg.convert('RGBA')files = glob.glob(imagesPath + '/*.*')  # 获取图片random.shuffle(files)num = len(files)# 模板图片大小x = baseImg.size[0]y = baseImg.size[1]# 每张图片数量 这个公式是为了xNum * yNum 的总图片数量<num又成比例的最大整数yNum = int((num / (y / x)) ** 0.5)if yNum == 0:yNum = 1xNum = int(num / yNum)# 图片大小 因为像素没有小数点 为防止黑边所以+1xSize = int(x / xNum) + 1ySize = int(y / yNum) + 1# 生成数量的随机列表 用于随机位置合成图片l = [n for n in range(0, xNum * yNum)]random.shuffle(l)toImage = Image.new('RGB', (x, y))num = 1for file in files:if num <= xNum * yNum:num = num + 1else:breakfromImage = Image.open(file)temp = l.pop()i = int(temp % xNum)j = int(temp / xNum)out = fromImage.resize((xSize, ySize), Image.ANTIALIAS).convert('RGBA')toImage.paste(out, (i * xSize, j * ySize))toImage = toImage.convert('RGBA')img = Image.blend(baseImg, toImage, alpha)# 特效 但是会读取像素会降低效率choose = v.get()if choose == 1:img = blackWithe(img)elif choose == 2:img = fleeting(img)elif choose == 3:img = oldFilm(img)elif choose == 4:img = reverse(img)resize = img.resize((300, 300), Image.ANTIALIAS).convert('RGBA')# 显示图片photo = ImageTk.PhotoImage(resize)showLabel.config(image=photo)showLabel.image = phototoImage.save('generator.png')img = img.resize((int(widthEntry.get()),int(heightEntry.get())), Image.ANTIALIAS).convert('RGBA')img.save("final.png")resize.save("resize.png")class MyThread(threading.Thread):  # 继承父类threading.Threaddef __init__(self, threadID, name, counter):threading.Thread.__init__(self)self.threadID = threadIDself.name = nameself.counter = counterdef run(self):  # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数generator()root = tkinter.Tk()
root.title('generator')
root.geometry('500x550')
baseImageLabel = Label(root, text='')
baseImageLabel.place(x=10, y=10)
baseImageBtn = Button(root, text="选择底图", command=chooseBaseImagePath).place(x=10, y=30)
ImagesLabel = Label(root, text='')
ImagesLabel.place(x=10, y=60)
ImagesBtn = Button(root, text="选择合成图文件夹", command=chooseImagesPath).place(x=10, y=80)v = tkinter.IntVar()
v.set(0)
Radiobutton(root, variable=v, text='默认', value=0, ).place(x=10, y=120)
Radiobutton(root, variable=v, text='黑白', value=1, ).place(x=110, y=120)
Radiobutton(root, variable=v, text='流年', value=2, ).place(x=210, y=120)
Radiobutton(root, variable=v, text='旧电影', value=3, ).place(x=310, y=120)
Radiobutton(root, variable=v, text='反色', value=4, ).place(x=410, y=120)scaleLabel = Label(root, text='透明度').place(x=10, y=170)
scale = tkinter.Scale(root, from_=0, to=100, orient=tkinter.HORIZONTAL, command=resize)
scale.set(30)  # 设置初始值
scale.pack(fill=tkinter.X, expand=1)
scale.place(x=70, y=150)
Label(root, text='宽(像素)').place(x=180, y=170)
widthEntry = Entry(root, bd=1)
widthEntry.place(x=230, y=173, width=100)
Label(root, text='高(像素)').place(x=320, y=170)
heightEntry = Entry(root, bd=1)
heightEntry.place(x=370, y=173, width=100)generatorBtn = Button(root, text="生成", command=test).place(x=10, y=220)
showLabel = Label(root)
showLabel.place(x=100, y=220)
root.mainloop()

http://chatgpt.dhexx.cn/article/7SPO1NLJ.shtml

相关文章

Python:合成图片

简介&#xff1a;PIL库中Image库封装了很多对图片处理的函数&#xff0c;支持对图片进行合成等操作。 相关攻略&#xff1a; python: ocr简单示例 - 识别验证码 python&#xff1a;彩色照转黑白照 python&#xff1a;个性签名 Python&#xff1a;利用cv2模块对图片进行灰度…

如何编辑图片合成图片?让我们来看看这些合成方法

相信大家在日常出行的时候&#xff0c;都会遇到想要和自己的朋友合照这种情况&#xff0c;却会因为社恐而不敢去向他人求助或者不想麻烦他人。所以通常我们会在同一个场景中拍摄照片&#xff0c;然后通过后期编辑将这些图片组合在一起&#xff0c;那么有的朋友会问&#xff0c;…

信息流产品和内容推荐算法

&#xff08;一&#xff09;什么是信息流产品 当下&#xff0c;信息流&#xff08;资讯&#xff09;和短视频是唯一两个在用户领域保持好的增长事态的细分行业。像其他比较成熟的互联网细分行业&#xff0c;比如说移动社交&#xff0c;电商&#xff0c;OTO这个细分行业&#x…

O2O商城系统,适合本地电商发展的商城系统!

说起商城系统&#xff0c;最适合本地电商发展的要数O2O商城系统了&#xff0c;O2O商城系统有什么优势? 一、本地O2O商城系统对商家的好处 1、本地O2O商城系统对消费人群定位比较明确&#xff0c;针对性强&#xff0c;而且本地的人消费习惯都比较了解。这样也容易形成固定的…

[转]从本地电子商务中走出来,6个很好的O2O模式解析

谓O2O就是线上到线下&#xff08;Online to Offline&#xff09; 请看以下几个非常好的O2O模式&#xff1a; Uber Uber是一个允许你通过手机购买一个私家车搭乘服务的应用。其运作方式如下&#xff1a;下载Uber应用&#xff0c;发出打车请求&#xff1b;几分钟内一辆私家车来到…

Oauth2协议

Oauth2协议 Oauth2简介角色常用术语令牌类型特点 授权模式授权码模式&#xff08;Authorization Code&#xff09;简化授权模式&#xff08;Implicit&#xff09;密码模式&#xff08;Resource Owner PasswordCredentials&#xff09;客户端模式&#xff08;Client Credentials…

2021年中国医药O2O行业发展现状、发展问题及发展建议分析[图]

医药O2O模式指的是基于线下药店&#xff0c;利用现存资源&#xff0c;将门店的功能从售药转变为体验、提货和配送&#xff0c;贴合当地需求&#xff0c;完成和用户的最终接轨。 随着疫情防控成为常态化&#xff0c;医药电商与数字医疗也迎来了新的发展。医药的网上销售呈现出逐…

中国IT运维O2O市场发展研究及十四五前景规划分析报告2022-2027年

中国IT运维O2O市场发展研究及十四五前景规划分析报告2022-2027年 第1章:IT运维O2O的概念界定与内涵1.1 IT运维的概念界定与内涵 1.1.1 IT运维的概念 1.1.2 IT运维的演化历程 1.1.3 IT运维的内容 1.1.4 IT运维的流程 1.1.5 IT运维的价值 1.2 IT运维O2O的概念界定与内涵…

案例直播 | Pulsar Summit Asia 2022:Day 1 - 分论坛 1:腾讯、华为、有道、vivo、科大讯飞...

关于 Pulsar Summit Pulsar Summit 是 Apache Pulsar 社区年度盛会&#xff0c;它将分布在世界各地的 Apache Pulsar 项目 Contributor、Committer 和各企业 CTO/CIO、开发者、架构师、数据科学家&#xff0c;以及消息和流计算社区的精英召集在一起。于此盛会&#xff0c;大家分…

高德导航免费,那他靠什么收入?

来源 &#xff5c;一口Linux 一位工作了12年的软件工程师说&#xff1a;当你打开导航时&#xff0c;不需要任何费用&#xff0c;还会给高德公司带来丰厚的收入。当时我不信&#xff0c;去查了相关资料后&#xff0c;才知道这个行业不简单。 出门外出&#xff0c;对路线不熟时&a…

全球及中国前置汽车中冷器行业需求趋势分析及发展规划研究报告2021-2027年版

全球及中国前置汽车中冷器行业需求趋势分析及发展规划研究报告2021-2027年版 2020年,全球前置汽车中冷器市场规模达到了XX百万美元,预计2027年可以达到XX百万美元,年复合增长率(CAGR)为XX% (2021-2027)。中国市场规模增长快速,预计将由2020年的XX百万美元增长到2027年的X…

智能家居市场应采用精准营销策划模式

智能家居在全世界的发展都属于新鲜事物&#xff0c;在中国市场&#xff0c;智能家居行业参与进来的企业众多&#xff0c;包括跨国企业也包括本土的强势品牌都参与其中&#xff0c;唐太子、霍尼韦尔、莫顿、新加坡NICO、上海索博、广东安居宝、波创科技、海尔集团、天津瑞朗、联…

O2O营销结构思维导图模板分享

O2O营销是线上线下营销&#xff0c;随这互联网科技的发展&#xff0c;很多公司的业务从线下扩展到线上。但是在如此多行业的竞争下&#xff0c;怎样做好线上业务就成为最大的麻烦&#xff0c;下面是分享的O2O营销结构思维导图模板以及利用在线工具编辑思维导图的操作方法&#…

新项目从零到一DDD实战思考与总结

抱歉了&#xff0c;前面几篇DDD的文章我删除了&#xff0c;本篇是前面发表的几篇DDD的汇总&#xff0c;内容有修改。 领域驱动设计&#xff08;DDD&#xff09;是一种业务领域建模方法论、业务架构设计方法论&#xff0c;战略设计阶段从业务领域视角划分领域边界&#xff0c;抽…

设计模式 | 四、代理模式(静态代理、JDK动态代理、Cglib动态代理、手写动态代理核心部分)[ProxyPattern]

代理模式 源码&#xff1a;https://github.com/GiraffePeng/design-patterns 1、应用场景 在生活中&#xff0c;我们经常见到这样的场景&#xff0c;如&#xff1a;租房中介、售票黄牛、婚介、经纪人、快递、事务代理、非侵入式日志监听等&#xff0c;这些都是代理模式的实际…

23种设计模式 原型设计模式

原型模式的定义&#xff1a; 原型模式&#xff1a;使用原型实例指定待创建对象的类型&#xff0c;并且通过复制这个原型来创建新的对象。 原型模式的结构&#xff1a; 原型模式主要包含3个角色&#xff1a; &#xff08;1&#xff09;Prototype(抽象原型类)&#xff1a;声明克…

OTO模式 传统产业掘金互联网时代的利器

OTO模式 传统产业掘金互联网时代的利器 2013年10月16日 07:11 来源&#xff1a;中国经济网—《证券日报》 编者按&#xff1a;今年以来&#xff0c;一种新型的商业模式OTO模式迅速被国内众多传统企业所熟悉&#xff0c;很多传统企业借助OTO模式实现了从传统产业向互联网时…

OTO电子商务商业模式探析

一、前言 OTO&#xff08;O2O&#xff09;&#xff0c;即Online to Offline&#xff0c;是将线下商务机会与线上互联网结合在一起&#xff0c;让互联网成为线下交易前台的一种电子商务商业模式&#xff0c;简单来说就是“线上拉客&#xff0c;线下消费”。其核心理念是通过电子…

2020-1024

2020 - 1024 996

1024程序员节

1024是一种逐渐流行的回帖方式&#xff0c;常见于BBS、网络社区和论坛的网友交流中。其常见形式为"1024"、"1024顶"两种形式。 1024所表达的含义&#xff0c;类似于"顶"、"非常棒&#xff0c;一级棒" &#xff0c;还有表达回帖者的身…