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
    40
    height, 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
    26
    height, 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
    43
    height, 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
    8
    img = 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
    26
    img = 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
    17
    img = 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
    26
    img = 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
    9
    img = 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
    14
    img = 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
    13
    img = 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
    24
    img = 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
    36
    img = 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
    18
    img1 = 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
    13
    imgBGR = 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 博客