opencv-python学习(6)--六个图像处理小项目

摘要

opencv的python图像处理学习笔记

转像素画、转字符画、图片九宫格、图片蒙太奇、幻影坦克、证件照裁剪。

部分代码参考互联网。

1.图像转像素画

效果如下

可莉像素

实现原理是通过将图片缩小10倍,然后用最邻近插值放大回原来的尺寸。

1
2
3
4
5
6
7
8
# 图片像素化
def pixel_image(self):
img = self.image.copy()
rows, cols = img.shape[:2]
img = cv2.resize(img,(cols//10,rows//10))
img = cv2.resize(img,(cols,rows),interpolation=cv2.INTER_NEAREST)
win_name = "pixel"
UIFunctions.wait_key(self,img,win_name)

其中wait_key函数内容是用opencv打开图片,然后接受一些保存等指令的函数。

2.图片转字符画

效果图

字符画

原理是把图片转为灰度,然后根据灰度值将像素替换为对应字重的字符最后保存为txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 转为字符画
def character_image(self):
img = UIFunctions.trun_gray(self,self.image)
rows, cols = img.shape[:2]
rows = rows//2
img = cv2.resize(img,(cols,rows))
lstChars = self.config.get('General','file_character_list')
output = self.config.get('General','file_save_path') + "\\character.txt"
g2c = 256/len(lstChars)

txt = ""
for i in range(rows):
for j in range(cols):
txt += lstChars[int(img[i,j]/g2c)]
txt += '\n'

with open(output, 'w') as f:
f.write(txt)
QMessageBox.information(None, '提示', 'character.txt输出成功',QMessageBox.Ok)

为了表现效果,这里将高缩了一半。output是文件路径,lstChars是自定义的字符。上图使用的字符串是

1
$B8&WM*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|1?-_+~<>i!lI,^`.

注意把字重大的放前面。

3.图片九宫格

图片九宫格是发朋友圈常用的一种格式,该项目可以辅助将一张图片切割成9张。

效果

图片九宫格

这个没啥说的就是切一下图片,因为懒得pip没用PIL库就直接对数组操作了。

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
# 九宫格
def ninegrid_image(self):
# 切片函数
def cut_image(img,width):
box_list = []
if len(img.shape) == 2:
for i in range(0, 3):
for j in range(0, 3):
box = img[i * width:(i+1) * width, j * width : (j + 1) * width]
box_list.append(box)
elif len(img.shape) == 3:
for i in range(0, 3):
for j in range(0, 3):
box = img[i * width:(i+1) * width, j * width : (j + 1) * width,:]
box_list.append(box)
return box_list

img = self.image.copy()
value, ok = QInputDialog.getInt(self, "输入窗口", "请输入裁剪后的边值像素(正方形):", 300, 0, 2000, 100)
if ok:
value = int(value)*3
img = cv2.resize(img,(value,value))
box_list = cut_image(img,value//3)
for i,box in enumerate(box_list):
save_name = self.config.get('General','file_save_path') + '\\ninegrid_image\\' + str(i+1)+'.png'
cv2.imwrite(save_name,box)
QMessageBox.information(None, '提示', 'ninegrid_image输出成功',QMessageBox.Ok)

4.图片蒙太奇

图片蒙太奇是指用一组图片去组合成一张大图的艺术效果。

图片有点大,放本地打开后再截图的图。

蒙太奇

代码主要参考CSDN蒙太奇照片制作(Opencv+Python)

原理是缩放待处理图片,然后匹配区块和图片的直方图找到最合适的,最后做一个融合让效果变好些。

理论上图库内容丰富越好。

5.幻影坦克

幻影坦克是现代互联网图片表示的艺术,缩略图上看是一张图,但实际点开就变成了另一张,常见于贴吧。

效果图

幻影坦克

原理参考b站小迷糊老师的视频《幻影坦克基础版

简单讲就是利用背景白色和黑色来叠加出不一样的图片。

灰度处理方面借用了《基于OpenCV实现的灰度图幻影坦克》一文的思路

代码

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
# 幻影坦克
def mirage_tank_image(self):
inside_pic = np.uint8(self.image.copy() * 0.35)
h,w = inside_pic.shape[:2]
get_filename_path, ok = QFileDialog.getOpenFileName(self,"选取表图",self.config.get('General','file_open_path'))
if ok:
out_pic = cv2.imread(get_filename_path)
# 调整表图大小 与里图一致
out_pic = cv2.resize(out_pic,(w,h))
# 如果强度小于100 拉到100
out_pic[out_pic<100] = 100
# 转变为灰度图
inside_pic = UIFunctions.trun_gray(self,inside_pic)
out_pic = UIFunctions.trun_gray(self,out_pic)
# 建立新的画布
new_pic = np.zeros((h,w,4), np.uint8)
# print(new_pic.shape)
# 遍历图片 套用公式
for i in range(h):
for j in range(w):
alpha = 255 - (out_pic[i,j]-inside_pic[i,j])
if alpha == 0:
alpha = 1
p_new = np.uint8(255*inside_pic[i,j]/alpha)
new_pic[i,j,0] = p_new
new_pic[i,j,1] = p_new
new_pic[i,j,2] = p_new
new_pic[i,j,3] = alpha
win_name = "tank"
UIFunctions.wait_key(self,new_pic,win_name)

6.证件照处理

如果你对证件照态度比较随便的话,可以直接用手机背靠墙拍一张,然后用这个方法处理,直接用打印机打印出来。

效果图

证件照

原理是建立对应大小的画布,然后把图片处理成1或2寸的,贴到对应位置。

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
# 证件照处理
def certificate_image(self):
# 1寸大小
WIDTH_1IN = 295
HEIGHT_1IN = 413
# 2寸大小
WIDTH_2IN = 413
HEIGHT_2IN = 626
# 5寸大小
WIDTH_5IN = 1500
HEIGHT_5IN = 1050
# 非全景6寸照片
WIDTH_6IN = 1950
HEIGHT_6IN = 1300
def cut_photo(photo,choice):
"""
将照片按照比例进行裁剪并缩放成1寸、2寸
:param photo: 待处理的照片
:param choice: <int> 1代表1寸,2代表2寸
:return: 处理后的照片
"""
h,w = photo.shape[:2]
rate = h / w
if choice == 1:
if rate < (HEIGHT_1IN/WIDTH_1IN):
cut = int((w - int(h / HEIGHT_1IN * WIDTH_1IN)) / 2)
cut_p = photo[:,cut:w-cut,:]
else:
cut = int((h - int(w / WIDTH_1IN * HEIGHT_1IN)) / 2)
cut_p = photo[cut:w-cut,:,:]
return cv2.resize(cut_p, (WIDTH_1IN, HEIGHT_1IN))
if choice == 2:
if rate < (HEIGHT_2IN/WIDTH_2IN):
cut = int((w - int(h / HEIGHT_2IN * WIDTH_2IN)) / 2)
cut_p = photo[:,cut:w-cut,:]
else:
cut = int((h - int(w / WIDTH_2IN * HEIGHT_2IN)) / 2)
cut_p = photo[cut:w-cut,:,:]
return cv2.resize(cut_p, (WIDTH_2IN, HEIGHT_2IN))

# 5寸照排版1
def layout_photo_5_1(photo):
photo = cut_photo(photo,1)
img = np.ones((HEIGHT_5IN,WIDTH_5IN, 3), np.uint8)*255
img[HEIGHT_5IN//2,:,:] = 128 # 横线
img[:,int(WIDTH_5IN*0.25),:] = 128 # 竖线1
img[:,int(WIDTH_5IN*0.5),:] = 128 # 竖线2
img[:,int(WIDTH_5IN*0.75),:] = 128 # 竖线3
# 确定位置放上图片
focus_point = [0.125 * WIDTH_5IN,0.25 * HEIGHT_5IN]
start_point = [focus_point[0] - 0.5 * WIDTH_1IN, focus_point[1] - 0.5 * HEIGHT_1IN]
end_point = [focus_point[0] + 0.5 * WIDTH_1IN, focus_point[1] + 0.5 * HEIGHT_1IN]
for i in range(0,2):
for j in range(0,4):
img[int(start_point[1]+0.5*i*HEIGHT_5IN):int(end_point[1]+0.5*i*HEIGHT_5IN),int(start_point[0]+j*WIDTH_5IN/4):int(end_point[0]+j*WIDTH_5IN/4),:] = photo
return img
# 5寸混合排版2
def layout_photo_5_mix(photo):
photo1 = cut_photo(photo,1)
photo2 = cut_photo(photo,2)
photo2 = np.rot90(photo2)
img = np.ones((HEIGHT_5IN,WIDTH_5IN, 3), np.uint8)*255
img[HEIGHT_5IN//2,:,:] = 128 # 横线
img[:,int(WIDTH_5IN*0.25),:] = 128 # 竖线1
img[:,int(WIDTH_5IN*0.5),:] = 128 # 竖线2
# 确定位置放上1寸图片
focus_point = [0.125 * WIDTH_5IN,0.25 * HEIGHT_5IN]
start_point = [focus_point[0] - 0.5 * WIDTH_1IN, focus_point[1] - 0.5 * HEIGHT_1IN]
end_point = [focus_point[0] + 0.5 * WIDTH_1IN, focus_point[1] + 0.5 * HEIGHT_1IN]
for i in range(0,2):
for j in range(0,2):
img[int(start_point[1]+0.5*i*HEIGHT_5IN):int(end_point[1]+0.5*i*HEIGHT_5IN),int(start_point[0]+j*WIDTH_5IN/4):int(end_point[0]+j*WIDTH_5IN/4),:] = photo1
# 确定位置放上2寸图片
focus_point2 = [0.75 * WIDTH_5IN, 0.25 * HEIGHT_5IN]
start_point2 = [focus_point2[0] - 0.5 * HEIGHT_2IN, focus_point2[1] - 0.5 * WIDTH_2IN]
end_point2 = [focus_point2[0] + 0.5 * HEIGHT_2IN, focus_point2[1] + 0.5 * WIDTH_2IN]
img[int(start_point2[1]):int(end_point2[1]),int(start_point2[0]):int(end_point2[0]),:] = photo2
img[int(start_point2[1]+ 0.5 * HEIGHT_5IN):int(end_point2[1]+ 0.5 * HEIGHT_5IN),int(start_point2[0]):int(end_point2[0]),:] = photo2
return img
# 6寸混合排版1
def layout_photo_6_mix(photo):
photo1 = cut_photo(photo,1)
photo2 = cut_photo(photo,2)
photo1 = np.rot90(photo1)
img = np.ones((HEIGHT_6IN,WIDTH_6IN, 3), np.uint8)*255
img[HEIGHT_6IN//2,:,:] = 128 # 横线1
img[HEIGHT_6IN//4,:WIDTH_6IN//2,:] = 128 # 横线2
img[int(HEIGHT_6IN*0.75),:WIDTH_6IN//2,:] = 128 # 横线2
img[:,int(WIDTH_6IN*0.25),:] = 128 # 竖线1
img[:,int(WIDTH_6IN*0.5),:] = 128 # 竖线2
img[:,int(WIDTH_6IN*0.75),:] = 128 # 竖线3
# 确定位置放上1寸图片
focus_point = [0.125 * WIDTH_6IN, 0.125 * HEIGHT_6IN]
start_point = [focus_point[0] - 0.5 * HEIGHT_1IN, focus_point[1] - 0.5 * WIDTH_1IN]
end_point = [focus_point[0] + 0.5 * HEIGHT_1IN, focus_point[1] + 0.5 * WIDTH_1IN]
for i in range(0,4):
for j in range(0,2):
img[int(start_point[1]+0.25*i*HEIGHT_6IN):int(end_point[1]+0.25*i*HEIGHT_6IN),int(start_point[0]+j*WIDTH_6IN/4):int(end_point[0]+j*WIDTH_6IN/4),:] = photo1
# 确定位置放上2寸图片
focus_point2 = [0.625 * WIDTH_6IN, 0.25 * HEIGHT_6IN]
start_point2 = [focus_point2[0] - 0.5 * WIDTH_2IN, focus_point2[1] - 0.5 * HEIGHT_2IN]
end_point2 = [focus_point2[0] + 0.5 * WIDTH_2IN, focus_point2[1] + 0.5 * HEIGHT_2IN]
for i in range(0,2):
for j in range(0,2):
img[int(start_point2[1]+0.5*i*HEIGHT_6IN):int(end_point2[1]+0.5*i*HEIGHT_6IN),int(start_point2[0]+j*WIDTH_6IN/4):int(end_point2[0]+j*WIDTH_6IN/4),:] = photo2

return img

img = self.image.copy()
items = ('1寸', '2寸', '5寸(8*1寸)', '5寸(4*1寸+2*2寸)', '6寸(8*1寸+4*2寸)')
item,ok = QInputDialog.getItem(self,"区域分割","选择需要分成几块",items,3,False)
if ok:
if item == '1寸':
img = cut_photo(img,1)
elif item == '2寸':
img = cut_photo(img,2)
elif item == '5寸(8*1寸)':
img = layout_photo_5_1(img)
elif item == '5寸(4*1寸+2*2寸)':
img = layout_photo_5_mix(img)
elif item == '6寸(8*1寸+4*2寸)':
img = layout_photo_6_mix(img)

win_name = "ID photo"
UIFunctions.wait_key(self,img,win_name)