A02-GUI 功能
使用 opencv 在图像上绘制形状的基本方法,包括直线、矩形、圆形、椭圆形、多边形,以及视频的读写
使用 OpenCV 绘制直线?
- 函数 cv.line () 用来在图像中绘制直线,函数 cv.arrowedLine () 用来在图像中绘制带箭头直线
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
40height, width, channels = 200, 120, 3
img = np.ones((height, width, channels), np.uint8)*160 # 创建黑色图像 RGB=0
# 注意 pt1, pt2 坐标的格式是 (x,y) 而不是 (y,x)
img1 = img.copy()
cv.line(img1, (0,0), (200,150), (0,0,255), 1) # 红色 R=255
cv.line(img1, (0,0), (150,200), (0,255,0), 1) # 绿色 G=255
cv.line(img1, (0,50), (200,50), (128,0,0), 2) # 深蓝色 B = 128
cv.line(img1, (0,100), (200,100), 128, 2) # color=128 等效于 (128,0,0)
cv.line(img1, (0,150), (200,150), 255, 2) # color=255 等效于 (255,0,0)
img2 = img.copy()
# img2 = cv.line(img2, (0,120), (100,180), (0,0,255), lineType=cv.FILLED) # cv.FILLED 非法
img2 = cv.line(img2, (0,80), (150,160), (0,0,255), lineType=cv.LINE_4) # 红色,cv.LINE_4
img2 = cv.line(img2, (0,40), (150,120), (0,0,255), lineType=cv.LINE_8) # 红色,cv.LINE_8
img2 = cv.line(img2, (0,0), (150,80), (0,0,255), lineType=cv.LINE_AA) # 红色,cv.LINE_AA
# 如果设置了 thickness,关键词 "lineType" 可以省略
img2 = cv.line(img2, (150,10), (20,50), (0,255,0), 1, cv.LINE_8) # 绿色
img2 = cv.line(img2, (150,60), (20,100), (0,255,0), 1, cv.LINE_AA) # 绿色
# 如果没有设置 thickness,则关键词 "lineType" 不能省略
img2 = cv.line(img2, (150,110), (30,150), (255,0,0), cv.LINE_8) # 蓝色, cv.LINE 被识别为线宽
img2 = cv.line(img2, (150,160), (30,200), (255,0,0), cv.LINE_AA) # 蓝色, cv.LINE 被识别为线宽
# img3 = img.copy()
# tipLength 指箭头部分长度与整个线段长度的比例
img3 = cv.arrowedLine(img.copy(), (10,0), (100,30), (0,0,255), tipLength=0.05) # 从 pt1 指向 pt2
img3 = cv.arrowedLine(img3, (10,50), (100,80), (0,0,255), tipLength=0.1)
img3 = cv.arrowedLine(img3, (10,100), (100,130), (0,0,255), tipLength=0.2) # 双向箭头
img3 = cv.arrowedLine(img3, (100,130), (10,100), (0,0,255), tipLength=0.2) # 双向箭头
img3 = cv.arrowedLine(img3, (10,150), (200,200), (0,0,255), tipLength=0.1) # 终点越界,箭头不显示
# 没有使用 img.copy(), 将直接改变 img,并相互影响
img4 = cv.line(img, (0,100), (150,100), (0,255,0), 1) # 水平线, y=100
img5 = cv.line(img, (75,0), (75,200), (0,0,255), 1) # 垂直线, x= 60
# 绘制直线可以用于灰度图像,参数 color 只有第一通道值有效,并被设为灰度值
gray = np.zeros((height, width), np.uint8) # 创建灰度图像
img6 = cv.line(gray, (0,10), (200,10), (0,255,255), 2)
img6 = cv.line(gray, (0,30), (200,30), (64,128,255), 2)
img6 = cv.line(gray, (0,60), (200,60), (128,64,255), 2)
img6 = cv.line(gray, (0,100), (200,100), (255,0,255), 2)
img6 = cv.line(gray, (20,0), (20,200), 128, 2)
img6 = cv.line(gray, (60,0), (60,200), (255,0,0), 2)
img6 = cv.line(gray, (100,0), (100,200), (255,255,255), 2)
show_images([img1,img2,img3,img4,img5,img6])
使用 OpenCV 绘制矩形?
- 函数 cv.rectangle () 用来在图像上绘制垂直于图像边界的矩形
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
26height, width, channels = 400, 300, 3
img = np.ones((height, width, channels), np.uint8)*160 # 创建黑色图像 RGB=0
img1 = img.copy()
cv.rectangle(img1, (0,20), (100,200), (255,255,255)) # 白色
cv.rectangle(img1, (20,0), (300,100), (255,0,0), 2) # 蓝色 B=255
cv.rectangle(img1, (300,400), (250,300), (0,255,0), -1) # 绿色,填充
cv.rectangle(img1, (0,400), (50,300), 255, -1) # color=255 蓝色
cv.rectangle(img1, (20,220), (25,225), (0,0,255), 4) # 线宽的影响
cv.rectangle(img1, (60,220), (67,227), (0,0,255), 4)
cv.rectangle(img1, (100,220), (109,229), (0,0,255), 4)
img2 = img.copy()
x, y, w, h = (50, 50, 200, 100) # 左上角坐标 (x,y), 宽度 w,高度 h
cv.rectangle(img2, (x,y), (x+w,y+h), (0,0,255), 2)
text = "({},{}),{}*{}".format(x, y, w, h)
cv.putText(img2, text, (x, y-5), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255))
# 绘制直线可以用于灰度图像,参数 color 只有第一通道值有效,并被设为灰度值
gray = np.zeros((height, width), np.uint8) # 创建灰度图像
img3 = cv.line(gray, (0,10), (300,10), 64, 2)
cv.line(img3, (0,30), (300,30), (128,128,255), 2)
cv.line(img3, (0,60), (300,60), (192,64,255), 2)
cv.rectangle(img3, (0,200), (30,150), 128, -1) # Gray=128
cv.rectangle(img3, (60,200), (90,150), (128,0,0), -1) # Gray=128
cv.rectangle(img3, (120,200), (150,150), (128,255,255), -1) # Gray=128
cv.rectangle(img3, (180,200), (210,150), 192, -1) # Gray=192
cv.rectangle(img3, (240,200), (270,150), 255, -1) # Gray=255
show_image([img1,img2,img3])
使用 OpenCV 绘制倾斜矩形?
- cv. rectangle 只能在图像上绘制垂直于边界的矩形。如果需要绘制倾斜的矩形,则要获得倾斜矩形的各个顶点坐标,通过绘制直线构造成为闭合的矩形
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
43height, width, channels = 600, 400, 3
img = np.ones((height, width, channels), np.uint8)*192 # 创建黑色图像 RGB=0
# 围绕矩形中心旋转
x, y, w, h = (100, 200, 200, 100) # 左上角坐标 (x,y), 宽度 w,高度 h
cx, cy = x+w//2, y+h//2 # 矩形中心
img1 = img.copy()
cv.circle(img1, (cx,cy), 4, (0,0,255), -1) # 旋转中心
angle = [15, 30, 45, 60, 75, 90] # 旋转角度,顺时针方向
for i in range(len(angle)):
ang = angle[i] * np.pi / 180
x1 = int(cx + (w/2)*np.cos(ang) - (h/2)*np.sin(ang))
y1 = int(cy + (w/2)*np.sin(ang) + (h/2)*np.cos(ang))
x2 = int(cx + (w/2)*np.cos(ang) + (h/2)*np.sin(ang))
y2 = int(cy + (w/2)*np.sin(ang) - (h/2)*np.cos(ang))
x3 = int(cx - (w/2)*np.cos(ang) + (h/2)*np.sin(ang))
y3 = int(cy - (w/2)*np.sin(ang) - (h/2)*np.cos(ang))
x4 = int(cx - (w/2)*np.cos(ang) - (h/2)*np.sin(ang))
y4 = int(cy - (w/2)*np.sin(ang) + (h/2)*np.cos(ang))
color = (30*i, 0, 255-30*i)
cv.line(img1, (x1,y1), (x2,y2), color)
cv.line(img1, (x2,y2), (x3,y3), color)
cv.line(img1, (x3,y3), (x4,y4), color)
cv.line(img1, (x4,y4), (x1,y1), color)
# 围绕矩形左上顶点旋转
x, y, w, h = (200, 200, 200, 100) # 左上角坐标 (x,y), 宽度 w,高度 h
img2 = img.copy()
cv.circle(img2, (x, y), 4, (0,0,255), -1) # 旋转中心
angle = [15, 30, 45, 60, 75, 90, 120, 150, 180, 225] # 旋转角度,顺时针方向
for i in range(len(angle)):
ang = angle[i] * np.pi / 180
x1, y1 = x, y
x2 = int(x + w * np.cos(ang))
y2 = int(y + w * np.sin(ang))
x3 = int(x + w * np.cos(ang) - h * np.sin(ang))
y3 = int(y + w * np.sin(ang) + h * np.cos(ang))
x4 = int(x - h * np.sin(ang))
y4 = int(y + h * np.cos(ang))
color = (30 * i, 0, 255 - 30 * i)
cv.line(img2, (x1, y1), (x2, y2), color)
cv.line(img2, (x2, y2), (x3, y3), color)
cv.line(img2, (x3, y3), (x4, y4), color)
cv.line(img2, (x4, y4), (x1, y1), color)
show_images([img1,img2])
使用 OpenCV 绘制圆形?
- 函数 cv.circle () 用来在图像上绘制圆形
1
2
3
4
5
6
7
8img = np.ones((400, 600, 3), np.uint8)*192
center = (0, 0) # 圆心坐标
cx, cy = 300, 200 # 圆心坐标
for r in range(200, 0, -20):
color = (r, r, 255-r)
cv.circle(img, (cx, cy), r, color, -1)
cv.circle(img, center, r, 255)
cv.circle(img, (600,400), r, color, 5)
使用 OpenCV 绘制椭圆?
- 函数 cv. ellipse () 用来在图像上绘制椭圆轮廓、填充椭圆、椭圆弧或填充椭圆扇区
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
26img = np.ones((600, 400, 3), np.uint8)*224
img1 = img.copy()
img2 = img.copy()
# (1) 半轴长度 (haf) 的影响
cx, cy = 200, 150 # 圆心坐标
angle = 30 # 旋转角度
startAng, endAng = 0, 360 # 开始角度,结束角度
haf = [50, 100, 150, 180] # 第一轴的半轴长度
has = 100 # 第二轴的半轴长度
for i in range(len(haf)):
color = (i*50, i*50, 255-i*50)
cv.ellipse(img1, (cx,cy), (haf[i],has), angle, startAng, endAng, color, 2)
angPi = angle * np.pi / 180 # 转换为弧度制,便于计算坐标
xe = int(cx + haf[i]*np.cos(angPi))
ye = int(cy + haf[i]*np.sin(angPi))
cv.circle(img1, (xe,ye), 2, color, -1)
cv.arrowedLine(img1, (cx,cy), (xe,ye), color) # 从圆心指向第一轴端点
text = "haF={}".format(haf[i])
cv.putText(img1, text, (xe+5,ye), cv.FONT_HERSHEY_SIMPLEX, 0.5, color)
# 绘制第二轴
xe = int(cx + has*np.sin(angPi)) # 计算第二轴端点坐标
ye = int(cy - has*np.cos(angPi))
cv.arrowedLine(img1, (cx, cy), (xe, ye), color) # 从圆心指向第二轴端点
text = "haS={}".format(has)
cv.putText(img1, text, (xe+5, ye), cv.FONT_HERSHEY_SIMPLEX, 0.5, color)
show_images([img1])
基于多段线段绘制椭圆?
- 如果需要对椭圆渲染进行更多控制,或者绘制粗略的椭圆边界,可以使用 cv. ellipse2Poly 检索曲线,然后使用多段线进行渲染或使用 fillPoly 进行填充
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17img = np.ones((400, 600, 3), np.uint8)*224
cx, cy = 100, 150
halfAxesLength = (70, 40)
angle, startAng, endAng = 30, 0, 360
delta = [10, 20, 30, 40]
for i in range(len(delta)):
color = (i*60, i*60, 255-i*60)
pts = cv.ellipse2Poly((cx+140*i, cy), halfAxesLength, angle, startAng, endAng, delta[i]) # (351,2)
points = np.array(pts)
cv.polylines(img, [points], True, color, thickness=1) # 绘制近似多边形
points[:,1] += 160
cv.fillPoly(img, [points], color) # 绘制填充近似多边形
text1 = "delta={}".format(delta[i])
text2 = "num={}".format(pts.shape)
cv.putText(img, text1, (140*i+25, 30), cv.FONT_HERSHEY_SIMPLEX, 0.5, 255)
cv.putText(img, text2, (140*i+25, 50), cv.FONT_HERSHEY_SIMPLEX, 0.5, 255)
show_images([img])
使用 OpenCV 绘制多线段和多边形?
- 函数 cv.polylines () 用来绘制多边形曲线或多段线;函数 cv.fillPoly () 用来绘制一个或多个填充的多边形区域;函数 cv.fillConvexPoly () 用来绘制一个填充的凸多边形
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
26img = np.ones((980, 400, 3), np.uint8)*224
img1 = img.copy()
img2 = img.copy()
img3 = img.copy()
img4 = img.copy()
# 多边形顶点
points1 = np.array([[200,100], [295,169], [259,281], [141,281], [105,169]], np.int)
points2 = np.array([[200,400], [259,581], [105,469], [295,469], [141,581]]) # (5,2)
points3 = np.array([[200,700], [222,769], [295,769], [236,812], [259,881],
[200,838], [141,881], [164,812], [105,769], [178,769]])
print(points1.shape, points2.shape, points3.shape) # (5, 2) (5, 2) (10, 2)
# 绘制多边形,闭合曲线
pts1 = [points1] # pts1 是列表,列表元素是形状为 (m,2) 的 numpy 二维数组
cv.polylines(img1, pts1, True, (0,0,255)) # pts1 是列表
cv.polylines(img1, [points2, points3], 1, 255, 2) # 可以绘制多个多边形
# 绘制多段线,曲线不闭合
cv.polylines(img2, [points1], False, (0,0,255))
cv.polylines(img2, [points2, points3], 0, 255, 2) # 可以绘制多个多段线
# 绘制填充多边形,注意交叉重叠部分处理
cv.fillPoly(img3, [points1], (0,0,255))
cv.fillPoly(img3, [points2, points3], 255) # 可以绘制多个填充多边形
# 绘制一个填充多边形,注意交叉重叠部分
cv.fillConvexPoly(img4, points1, (0,0,255))
cv.fillConvexPoly(img4, points2, 255) # 不能绘制存在自相交的多边形
cv.fillConvexPoly(img4, points3, 255) # 可以绘制凹多边形,但要慎用
show_images([img1,img2,img3,img4])
使用 OpenCV 绘制图像标记?
- 函数 cv. drawMarker 用来在图像上的指定位置绘制标记
1
2
3
4
5
6
7
8
9img = np.ones((600, 800, 3), np.uint8)*205
for i in range(7): # 7 种标记
cx = 100*(i+1)
color = (0,0,255)
cv.drawMarker(img, (cx, 100), color, markerType=i, markerSize=10)
cv.drawMarker(img, (cx, 200), color, markerType=i, markerSize=20)
cv.drawMarker(img, (cx, 300), color, markerType=i, markerSize=30)
cv.drawMarker(img, (cx, 400), color, markerType=i, markerSize=40)
cv.drawMarker(img, (cx, 500), color, markerType=i, markerSize=50)
使用 OpenCV 绘制多行倾斜文字水印?
- 先在黑色背景上添加图像或文字制作水印,再使用 cv. addWeight 函数,通过重叠混合把水印添加到原始图像上;也可以以水印图案或文字区域作为掩模,使用 cv. add 函数修改掩模区域的像素值,实现把水印添加到原始图像上
1
2
3
4
5
6
7
8
9
10
11
12
13
14img = cv.imread("../images/imgLena.tif", 1) # 加载原始图片
h, w = img.shape[0], img.shape[1]
# 生成文字水印
mark = np.zeros(img.shape[:2], np.uint8) # 黑色背景
for i in range(h//100):
cv.putText(mark, "youcans2022", (50,70+100*i), cv.FONT_HERSHEY_SIMPLEX, 1.5, 255, 2)
MAR = cv.getRotationMatrix2D((w//2,h//2), 45, 1.0) # 旋转 45 度
grayMark = cv.warpAffine(mark, MAR, (w,h)) # 旋转变换,默认为黑色填充
# 为图像添加水印 1
markC3 = cv.merge([grayMark, grayMark, grayMark])
imgMark1 = cv.addWeighted(img, 1, markC3, 0.25, 0) # 加权加法图像融合
# 为图像添加水印2
imgMark2 = cv.add(img, 64, mask=grayMark) # 以水印图案作为掩模
show_images([img,markC3,imgMark1,imgMark1])
使用 OpenCV 添加数字水印(盲水印)?
- 数字水印分为明水印和盲水印(blind watermark)。明水印包含的信息在观看图像或视频时可以看到。盲水印是以数字数据的方式嵌入图像中,在一般条件下是看不到的,需要特殊处理后才能提取到水印信息。盲水印也称为隐藏式水印,可以实现信息隐藏、版权认证、身份认证、数字签名等功能
- 最低有效位(Least significant bit)盲水印,是最简单方便的盲水印实现方法。该方法的原理是将数字水印信息保存为二值图像,嵌入到原始图像的最低位,即将原始图像的最低有效位替换为水印图像
1
2
3
4
5
6
7
8
9
10
11
12
13img = cv.imread("../images/imgLena.tif", 0) # 加载原始图片,单通道
watermark = cv.imread("../images/logoCV.png", 0) # # 加载水印图片,单通道
markResize = cv.resize(watermark, img.shape[:2]) # 调整图片尺寸与 img 大小相同
_, binary = cv.threshold(markResize, 175, 1, cv.THRESH_BINARY) # 0/1 二值图像
# 对原始图像嵌入水印
# img (g7,g6,...g1,0) AND 254(11111110) -> imgH7: (g7,g6,...g1,0)
imgH7 = cv.bitwise_and(img, 254) # 按位与运算,图像最低位 LSB=0
# imgH7: (g7,g6,...g1,0) OR b -> imgMark: (g7,g6,...g1,b)
imgMark = cv.bitwise_or(imgH7, binary) # (g7,g6,...g1,b)
# 从嵌入水印图像中提取水印
# extract = np.mod(imgMark, 2) # 模运算,取图像的最低位 LSB
extract = cv.bitwise_and(imgMark, 1) # 按位与运算,取图像的最低位 LSB
show_images([img,binary,imgMark,extract])
使用 OpenCV 对图像进行马赛克?
- 马赛克效果是广泛使用的图像和视频处理方法。将图像中指定区域的色阶细节劣化,造成色块模糊的效果,看上去像是一个个小格子组成的色块,称为马赛克。马赛克效果的主要目的是使特定区域的细节无法辨认,经常用于遮挡人物脸部、隐私信息
- 马赛克的方法很简单,将处理区域划分为一个个小方块,每个小方块内所有像素置为相同的或相似的像素值。马赛克方块的尺寸越大,图像越模糊,马赛克区域图像丢失的细节越多
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24img = cv.imread("../images/imgLena.tif", 1) # 加载原始图片,单通道
roi = cv.selectROI(img, showCrosshair=True, fromCenter=False)
x, y, wRoi, hRoi = roi # 矩形裁剪区域的位置参数
# x, y, wRoi, hRoi = 208, 176, 155, 215 # 矩形裁剪区域
imgROI = img[y:y+hRoi, x:x+wRoi].copy() # 切片获得矩形裁剪区域
print(x, y, wRoi, hRoi)
plt.figure(figsize=(9, 6))
plt.subplot(231), plt.title("Original image"), plt.axis('off')
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(232), plt.title("Region of interest"), plt.axis('off')
plt.imshow(cv.cvtColor(imgROI, cv.COLOR_BGR2RGB))
mosaic = np.zeros(imgROI.shape, np.uint8) # ROI 区域
ksize = [5, 10, 20] # 马赛克块的宽度
for i in range(3):
k = ksize[i]
for h in range(0, hRoi, k):
for w in range(0, wRoi, k):
color = imgROI[h,w]
mosaic[h:h+k,w:w+k,:] = color # 用顶点颜色覆盖马赛克块
imgMosaic = img.copy()
imgMosaic[y:y + hRoi, x:x + wRoi] = mosaic
plt.subplot(2,3,i+4), plt.title("Coding image (size={})".format(k)), plt.axis('off')
plt.imshow(cv.cvtColor(imgMosaic, cv.COLOR_BGR2RGB))
plt.imshow([mosaic])
使用 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
31
32
33
34
35
36img = cv.imread("../images/imgLena.tif", 1) # 加载原始图片,单通道
psw = 36 # 加密密钥,随机种子
# 对指定区域进行马赛克处理
# 选取指定区域
# roi = cv.selectROI(img, showCrosshair=True, fromCenter=False)
# x, y, wRoi, hRoi = roi # 矩形裁剪区域 (y:y+h, x:x+w) 的位置参数
x, y, wRoi, hRoi = 208, 176, 155, 215 # 矩形裁剪区域的位置参数
roi = img[y:y+hRoi, x:x+wRoi].copy() # 切片获得矩形裁剪区域
print(x, y, wRoi, hRoi)
# 指定区域马赛克处理
k = 10 # 马赛克块的宽度
markH2 = [192, 192, 192] # 192: 0b11000000
roiMosaic = np.zeros(roi.shape, np.uint8) # ROI 区域
np.random.seed(psw) # 设置随机种子为 psw
roiKey = np.random.randint(0, 256, roi.shape, np.uint8) # 生成 ROI 密钥
roiEncrypted = cv.bitwise_xor(roi, roiKey) # 用 roiKey 对 ROI 加密
for h in range(0, hRoi, k):
for w in range(0, wRoi, k):
color = roi[h, w] # 顶点颜色
# colorH2 = np.bitwise_and(color, markH2) # markH2:(0b11000000),color 取高两位
# mosaic[h:h+k, w:w+k, :] = colorH2 # 用顶点颜色覆盖马赛克块
colorH2 = np.bitwise_and(color, markH2) # 取顶点颜色的高两位,作为马赛克块颜色
block = roiEncrypted[h:h+k, w:w+k, :] >> 2 # 右移 2 位,保存像素特征(已加密)
roiMosaic[h:h+k, w:w+k, :] = block + colorH2 # 高两位载入马赛克颜色值,形成马赛克块
# 生成完整的马赛克加密图像
imgMosaic = img.copy()
imgMosaic[y:y+hRoi, x:x+wRoi] = roiMosaic
# 由马赛克加密图像和密钥 psw 重建原始图像
imgRebuilt = imgMosaic.copy()
roiExtract = imgMosaic[y:y+hRoi, x:x+wRoi] # 提取ROI 区域
roiExtract = roiExtract << 2 # 左移 2 位,恢复像素特征(已加密)
np.random.seed(psw) # 设置随机种子为 psw
roiKey = np.random.randint(0, 256, roi.shape, np.uint8) # 生成 ROI 密钥
roiDecrypt = cv.bitwise_xor(roiExtract, roiKey) # 用 roiKey 对 ROI 解密
imgRebuilt[y:y+hRoi, x:x+wRoi] = roiDecrypt # 生成完整的解密图像
show_images([img,imgMosaic,imgRebuilt,roi,roiMosaic,roiDecrypt])
如何认识 OpenCV 的线型 lineType?
- 有三个值可选:LINE_8(默认)、LINE_4、LINE_AA
- 8 连通域: 对每一个值为 1 的点若其八连通有一个点的值也为 1, 那么这两个点就归为一个物体(以下区域为 1 个物体)
- 4 连通域: 对每一个值为 1 的点若其四连通有一个点的值也为 1, 那么这两个点就归为一个物体 (以下区域为 3 个物体)
- 速度:LINE_8>LINE_AA
- 美观:LINE_AA>LINE_8
使用 OpenCV 在图像中添加非中文文字?
- OpenCV 不支持显示中文字符,使用 cv2.putText () 时添加的文本字符串不能包含中文字符(包括中文标点符号)
- 在图像中添加中文字符,可以使用 python+opencv+PIL 实现,或使用 python+opencv+freetype 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18img1 = cv2.imread("../images/imgLena.tif") # 读取彩色图像(BGR)
text = "OpenCV2021, youcans@xupt"
fontList = [cv2.FONT_HERSHEY_SIMPLEX,
cv2.FONT_HERSHEY_SIMPLEX,
cv2.FONT_HERSHEY_PLAIN,
cv2.FONT_HERSHEY_DUPLEX,
cv2.FONT_HERSHEY_COMPLEX,
cv2.FONT_HERSHEY_TRIPLEX,
cv2.FONT_HERSHEY_COMPLEX_SMALL,
cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
cv2.FONT_HERSHEY_SCRIPT_COMPLEX,
cv2.FONT_ITALIC]
fontScale = 1 # 字体缩放比例
color = (255, 255, 255) # 字体颜色
for i in range(10):
pos = (10, 50*(i+1))
imgPutText = cv2.putText(img1, text, pos, fontList[i], fontScale, color)
show_images([img1])
使用 OpenCV 在图像中添加中文文字?
- OpenCV 不支持显示中文字符,使用 cv2. putText () 时添加的文本字符串不能包含中文字符(包括中文标点符号)。在图像中添加中文字符,可以使用 python+opencv+PIL 实现,或使用 python+opencv+freetype 实现
1
2
3
4
5
6
7
8
9
10
11
12
13imgBGR = cv2.imread("../images/imgLena.tif") # 读取彩色图像(BGR)
from PIL import Image, ImageDraw, ImageFont
if (isinstance(imgBGR, np.ndarray)): # 判断是否 OpenCV 图片类型
imgPIL = Image.fromarray(cv2.cvtColor(imgBGR, cv2.COLOR_BGR2RGB))
text = "OpenCV2021, 中文字体"
pos = (50, 20) # (left, top),字符串左上角坐标
color = (255, 255, 255) # 字体颜色
textSize = 40
drawPIL = ImageDraw.Draw(imgPIL)
fontText = ImageFont.truetype("font/simsun.ttc", textSize, encoding="utf-8")
drawPIL.text(pos, text, color, font=fontText)
imgPutText = cv2.cvtColor(np.asarray(imgPIL), cv2.COLOR_RGB2BGR)
show_images([imgPutText])
参考:
【OpenCV 例程 300 篇】210. 绘制直线也会有这么多坑?_opencv 绘制直线_youcans_的博客 - CSDN 博客
【OpenCV 例程 200 篇】212. 绘制倾斜的矩形_opencv 画斜矩形_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】213. 绘制圆形_opencv 绘制圆形_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】214. 绘制椭圆的参数详解_opencv 椭圆_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】215. 基于多段线绘制近似椭圆_cv 绘制椭圆边界框_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】216. 绘制多段线和多边形_opencv 画多边形_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】254.OpenCV 绘制图像标记_opencv 编码标记点_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】217. 鼠标交互获取多边形区域(ROI)_opencv 鼠标选择 roi 区域_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】218. 多行倾斜文字水印_opencv 文字水印_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】219. 添加数字水印(盲水印)_视频加盲水印_youcans_的博客 - CSDN 博客
【OpenCV 例程 300 篇】220. 对图像进行马赛克处理_opencv 去马赛克_youcans_的博客 - CSDN 博客
【OpenCV 例程 200 篇】22. 图像添加非中文文字(cv2.putText)_cv2 添加文字_youcans_的博客 - CSDN 博客
【OpenCV 例程 200 篇】23. 图像添加中文文字(ImageDraw.Draw)_opencv 写中文_youcans_的博客 - CSDN 博客