python图片拼接
这两天看到一张图片,想用python来实现类似的图片拼接
先分析图片:
- 很明显,这张图片是由多张图片叠加拼接而成
- 从最后一张开始开始叠加,之后的每张图片都往上平移了一个固定的距离并且附着在原有的图片上
- 我们要做的就是控制这个距离,将所有需要的图片完成这个拼接
实操:
- 获取所有需要的图片的资源
1 def getAllImg(path):
2 result = []
3 filelist = os.listdir(path)
4 for file in filelist:
5 if os.path.isfile(os.path.join(path, file)):
6 if file.split('.')[1] in ('jpg', 'png'):
7 result.append(os.path.join(path, file))
8 return result
- 实现两张图片的拼接
1 result = '/root/lambda/static/result.png'
2
3
4 def join(png1, png2, size):
5 img1, img2 = Image.open(png1), Image.open(png2)
6 size1, size2 = img1.size, img2.size # 获取两张图片的大小
7 joint = Image.new('RGB', (size1[0], size1[1] + size2[1] - size))
8 # 新建一张新的图片
9 # 因为拼接的图片的宽都是一样,所以宽为固定值
10 # 高为两张图片的高相加再减去需要缩进的部分
11 loc1, loc2 = (0, 0), (0, size1[1] - size)
12 # 两张图片的位置
13 # a-------------
14 # | |
15 # | |
16 # | |
17 # | |
18 # | |
19 # b------------|
20 # | |
21 # | |
22 # | |
23 # | |
24 # |--------- --|
25
26 # 位置都是以该图片的左上角的坐标决定
27 # 第一张图片的左上角为a点,a的坐标为(0,0)
28 # 第二张图片的左上角为b点,a的横坐标为0,纵坐标为第一张图片的纵坐标减去第二张图片上移的size: (0, size[1]-size)
29
30 joint.paste(img2, loc2)
31 joint.paste(img1, loc1)
32 # 因为需要让第一张图片放置在图层的最上面,所以让第一张图片最后最后附着上图片上
33 joint.save(result)
- 循环递归调用
1 def start(items, size, first_path=None):
2 # 当first为None时,默认将第一张图片设置为图片列表的第一张图片,第二张图片设置为图片列表的第二张
3 # 当这两张图片合成后,将图片列表的已经合成的图片元素移除
4 # 然后将合成的图片设置为第一张图片,将剩余的没有合成的图片列表继续操作
5 # 当first_path不为None,将第一张图片设置为first_path,第二张图片设置为传进来的列表的第一个元素
6 # 合成之后,将刚刚使用的列表的元素删除
7 # 最后递归函数,知道列表为空
8 try:
9 if not first_path:
10 path1, path2 = items[0], items[1]
11 join(path1, path2, size)
12 items.remove(path1)
13 items.remove(path2)
14 return start(items, size, first_path=result)
15 else:
16 path2 = items[0]
17 join(first_path, path2, size)
18 items.remove(path2)
19 return start(items, size, first_path=result)
20 except:
21 pass
- 运行
1 if __name__ == '__main__':
2 s = getAllImg(path)
3 s.sort()
4 start(s, 100)
5 print('最后图片尺寸--->', Image.open(result).size)
- 效果展示
- 图片文件
- 1.png
- 2.png
- 3.png和1.png是同一张图片
- 最终效果图
- 这个中间的间隔是自己把握的,觉得不合适可以任意更换
- 完整代码
1 import os
2 from PIL import Image
3
4 result = '/root/lambda/static/result.png' # 图片保存路径
5
6
7 def join(png1, png2, size):
8 img1, img2 = Image.open(png1), Image.open(png2)
9 size1, size2 = img1.size, img2.size # 获取两张图片的大小
10 joint = Image.new('RGB', (size1[0], size1[1] + size2[1] - size))
11 # 新建一张新的图片
12 # 因为拼接的图片的宽都是一样,所以宽为固定值
13 # 高为两张图片的高相加再减去需要缩进的部分
14 loc1, loc2 = (0, 0), (0, size1[1] - size)
15 # 两张图片的位置
16 # a-------------
17 # | |
18 # | |
19 # | |
20 # | |
21 # | |
22 # b------------|
23 # | |
24 # | |
25 # | |
26 # | |
27 # |------------|
28
29 # 位置都是以该图片的左上角的坐标决定
30 # 第一张图片的左上角为a点,a的坐标为(0,0)
31 # 第二张图片的左上角为b点,a的横坐标为0,纵坐标为第一张图片的纵坐标减去第二张图片上移的size: (0, size[1]-size)
32
33 joint.paste(img2, loc2)
34 joint.paste(img1, loc1)
35 # 因为需要让第一张图片放置在图层的最上面,所以让第一张图片最后最后附着上图片上
36 joint.save(result)
37
38
39 def start(items, size, first_path=None):
40 # 当first为None时,默认将第一张图片设置为图片列表的第一张图片,第二张图片设置为图片列表的第二张
41 # 当这两张图片合成后,将图片列表的已经合成的图片元素移除
42 # 然后将合成的图片设置为第一张图片,将剩余的没有合成的图片列表继续操作
43 # 当first_path不为None,将第一张图片设置为first_path,第二张图片设置为传进来的列表的第一个元素
44 # 合成之后,将刚刚使用的列表的元素删除
45 # 最后递归函数,知道列表为空
46 try:
47 if not first_path:
48 path1, path2 = items[0], items[1]
49 join(path1, path2, size)
50 items.remove(path1)
51 items.remove(path2)
52 return start(items, size, first_path=result)
53 else:
54 path2 = items[0]
55 join(first_path, path2, size)
56 items.remove(path2)
57 return start(items, size, first_path=result)
58 except:
59 pass
60
61
62 path = '/root/lambda/' # 图片文件夹路径
63
64
65 def getAllImg(path):
66 result = []
67 filelist = os.listdir(path)
68 for file in filelist:
69 if os.path.isfile(os.path.join(path, file)):
70 if file.split('.')[1] in ('jpg', 'png'):
71 result.append(os.path.join(path, file))
72 return result
73
74
75 if __name__ == '__main__':
76 s = getAllImg(path)
77 s.sort()
78 start(s, 100)
79 print('最后图片尺寸--->', Image.open(result).size)