我是靠谱客的博主 积极手套,这篇文章主要介绍Python照片合成的方法详解,现在分享给大家,希望可以做个参考。

相关学习推荐:python教程

文章目录

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

前言

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

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

Github

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

效果

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

实现过程

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 打开图片 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 = 1 xNum = int(num / yNum) # 图片大小 因为像素没有小数点 为防止黑边所以+1 xSize = int(x / xNum) + 1 ySize = int(y / yNum) + 1
登录后复制

在这里插入图片描述

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 = photo if 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文件

复制代码
1
pyinstaller -F -w test.py (-w就是取消窗口)
登录后复制

整体代码

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import PIL.Image as Image import glob import random import tkinter.filedialog from tkinter.filedialog import askdirectory, Label, Button, Radiobutton, Entry import threading import numpy as np from PIL import ImageTk alpha = 0.3 imagesPath = '' # 滑动条回调 修改透明度 def resize(ev=None): global alpha alpha = scale.get() / 100 # 黑白 def blackWithe(image): # r,g,b = r*0.299+g*0.587+b*0.114 im = 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]) * params im2 = im * [0.0, 1.0, 1.0] im = im1 + im2 return 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.131 trans = np.array([[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]).transpose() # clip 超过255的颜色置为255 im = 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 baseImgPath baseImgPath = name baseImageLabel.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 imagesPath imagesPath = name ImagesLabel.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 = 1 xNum = int(num / yNum) # 图片大小 因为像素没有小数点 为防止黑边所以+1 xSize = int(x / xNum) + 1 ySize = int(y / yNum) + 1 # 生成数量的随机列表 用于随机位置合成图片 l = [n for n in range(0, xNum * yNum)] random.shuffle(l) toImage = Image.new('RGB', (x, y)) num = 1 for file in files: if num <= xNum * yNum: num = num + 1 else: break fromImage = 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 = photo toImage.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.Thread def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def 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()
登录后复制

以上就是Python照片合成的方法详解的详细内容,更多请关注靠谱客其它相关文章!

最后

以上就是积极手套最近收集整理的关于Python照片合成的方法详解的全部内容,更多相关Python照片合成内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(99)

评论列表共有 0 条评论

立即
投稿
返回
顶部