0. 前言
OpenCV作为计算机视觉库,其中一项基本功能就是绘制图形;OpenCV提供了绘制直线、圆、矩形、椭圆等的函数。在构建计算机视觉项目时,通常希望通过绘制一些图形来显式的标注图像。例如,在人脸检测算法中,会通过绘制一个矩形,突出显示计算图像中检测到的人脸。此外,如果开发人脸识别算法,除了绘制一个矩形突出显示检测到的人脸外,通常还会绘制文本标识检测到的人脸的身份。最后,项目可能还会需要输出一些调试信息,例如,可以显示检测到的人脸数量或处理时间(用于查看算法的性能)。本文,将介绍如何使用OpenCV库绘制图形和文本。
1. OpenCV 绘图基础
OpenCV 提供了许多绘制基本图形的函数,包括直线、矩形和圆形等;除此之外,使用 OpenCV,也可以绘制其它更多的基本图形。图像上绘制基本形状有许多实用的场景,常见的用例主要包括:
- 显示算法的一些中间结果
- 显示算法的最终结果
- 显示一些调试信息
在下图中,可以看到绘制了一个矩形检测框的图像,其中矩形用于显式标记检测到的人脸图像(人脸检测),文本信息用于显示其他相关的有用信息。算法 。通过这种方式,可以看到算法检测到人脸的位置:
在本文中,我们将学习如何绘制不同颜色的基本图形和文本。为了实现这一点,让我们首先简要描述一下不同颜色是如何构造的。我们可以建立一个颜色字典,使用颜色字典来定义要使用的主要颜色。下表列出了本文可能使用的颜色及其颜色值:
颜色名 | 颜色值 | 预览 |
blue | (255, 0, 0) | |
green | (0, 255, 0) | |
red | (0, 0, 255) | |
cyan | (255, 255, 0) | |
magenta | (255, 0, 255) | |
yellow | (0, 255, 255) | |
black | (0, 0, 0) | |
white | (255, 255, 255) | |
gray | (125, 125, 125) | |
dark_gray | (50, 50, 50) | |
light_gray | (220, 220, 220) |
从上表可以得出颜色字典的构造如下:
colors = {'blue': (255, 0, 0), 'green': (0, 255, 0), 'red': (0, 0, 255), 'cyan': (255, 255, 0), 'magenta': (255, 0, 255), 'yellow': (0, 255, 255), 'black': (0, 0, 0), 'white': (255, 255, 255), 'gray': (125, 125, 125), 'dark_gray': (50, 50, 50), 'light_gray': (220, 220, 220), 'rand': np.random.randint(0, high=256, size=(3,)).tolist()}
以上字典中定义了一些预定义的颜色,如果要使用特定颜色,例如红色 (red):
colors['red']
或者,可以使用 (0, 0, 255) 来得到红色。但是使用这个字典,不需要记住 RGB 颜色空间的色值,比数字三元组更容易使用。
除了使用字典外,另一种常见的方法是创建一个colors_constant.py文件来定义颜色。其中,每种颜色都由一个常量定义:
BLUE = (255, 0, 0)
GREEN = (0, 255, 0)
RED = (0, 0, 255)
YELLOW = (0, 255, 255)
MAGENTA = (255, 0, 255)
CYAN = (255, 255, 0)
LIGHT_GRAY = (220, 220, 220)
DARK_GRAY = (50, 50, 50)
在项目目录的其他文件中,这些常量可以通过以下代码引用:
import colors_constant as colors
print("red: {}".format(colors.RED))
此外,由于我们使用Matplotlib显示图形,因此我们需要通用函数show_with_matplotlib(),其带有两个参数的,第一个是要显示的图像,第二个是要图形窗口的标题。因为必须使用 Matplotlib 显示彩色图像,因此首先需要将 BGR 图像转换为 RGB。此函数的第二步也是最后一步是使用Matplotlib函数显示图像:
def show_with_matplotlib(img, title):
# 将 BGR 图像转换为 RGB
img_RGB = img[:, :, ::-1]
# 使用 Matplotlib 显示图形
plt.imshow(img_RGB)
plt.title(title)
plt.show()
为了演示colors常量和show_with_matplotlib()函数的使用,创建testing.py脚本进行测试:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def show_with_matplotlib(img, title):
# 将 BGR 图像转换为 RGB
img_RGB = img[:, :, ::-1]
# 使用 Matplotlib 显示图形
plt.imshow(img_RGB)
plt.title(title)
plt.show()
# 定义颜色字典:
colors = {'blue': (255, 0, 0), 'green': (0, 255, 0), 'red': (0, 0, 255), 'yellow': (0, 255, 255),
'magenta': (255, 0, 255), 'cyan': (255, 255, 0), 'white': (255, 255, 255), 'black': (0, 0, 0),
'gray': (125, 125, 125), 'rand': np.random.randint(0, high=256, size=(3,)).tolist(),
'dark_gray': (50, 50, 50), 'light_gray': (220, 220, 220)}
# 创建画布
image = np.zeros((500, 500, 3), dtype="uint8")
# 修改画布背景颜色
image[:] = colors['rand']
# 利用 colors 字典绘制直线
separation = 40
for key in colors:
cv2.line(image, (0, separation), (500, separation), colors[key], 15)
separation += 40
# 显示图形
show_with_matplotlib(image, 'Dictionary with some predefined colors')
在上例中,创建了一个大小为 500 x 500的图像,具有 3 个通道(彩色图像),数据类型为 uint8 (8 位无符号整数),原始背景为黑色:
image = np.zeros((500, 500, 3), dtype="uint8")
如果,希望将背景颜色,例如将背景颜色修改为随机色rand,则执行以下操作:
image[:] = colors['rand']
接下来,使用cv2.line()函数(这里仅作示例使用,有关此函数具体使用方式,将在下节进行详细介绍)绘制一些直线,每条线条都使用colors字典填充颜色。
separation = 40
for key in colors:
cv2.line(image, (0, separation), (500, separation), colors[key], 10)
separation += 40
最后,使用创建的show_with_matplotlib()函数绘制图像:
show_with_matplotlib(image, 'Dictionary with some predefined colors')
接下来,将详细介绍在 OpenCV 中基本图形的绘制。
2. OpenCV绘制图形
本节,将了解如何使用OpenCV函数绘制图形。首先,介绍基本图形的绘制,然后将详细介绍更高级的图形绘制。
2.1 基本图形的绘制
OpenCV 中的基本图形,包括直线、矩形和圆形等,它们是最常见和最容易绘制的形状。绘制图形的第一步是创建一个容纳绘制图形的画布。为此,将创建具有 3 个通道(以正确显示 BGR 图像)和 uint8 类型(8 位无符号整数)的 500 x 500 的黑色背景图像:
image = np.zeros((500, 500, 3), dtype="uint8")
然后使用颜色字典将背景设置为浅灰色:
image[:] = colors['gray']
一切准备就绪,接下来,我们准备绘制基本形状。需要注意的是,OpenCV 提供的大多数绘图函数都有共同的参数,因此首先总结介绍这些参数,如下表所示:
参数 | 说明 |
---|---|
img | 要绘制图形的画布图像 |
color | 用于绘制图形的颜色(BGR 三元组) |
thickness | 如果此值为正,则为图形轮廓的粗细;否则,将绘制填充形状 |
lineType | 图形边线的类型。 OpenCV 提供了三种类型的线:cv2.LINE_4 :四连接线,cv2.LINE_8 :八连接线,cv2.LINE_AA :抗锯齿线 |
shift | 表示与定义图形的某些点的坐标相关的小数位数 |
上述参数中,lineType的cv2.LINE_AA选项可产生更好的绘图质量,但绘制速度较慢。八连接线和四连接线都是非抗锯齿线,使用Bresenham算法绘制。而抗锯齿线使用高斯滤波算法。
2.1.1 直线
我们要了解的第一个函数是直线绘制函数cv2.line(),函数用法如下:
img = cv2.line(img, pt1, pt2, color, thickness=1, lineType=8, shift=0)
此函数在img图像上画一条连接pt1和pt2的直线:
cv2.line(image, (0, 0), (500, 500), colors['magenta'], 3)
cv2.line(image, (0, 500), (500, 0), colors['cyan'], 10)
cv2.line(image, (250, 0), (250, 500), colors['rand'], 3)
cv2.line(image, (0, 250), (500, 250), colors['yellow'], 10)
绘制图形后,调用show_with_matplotlib(image, ‘cv2.line()’)函数显示图像:
2.1.2 矩形
矩形绘制函数cv2.rectangle()用法如下:
img = cv2.rectangle(img, pt1, pt2, color, thickness=1, lineType=8, shift=0)
此函数根据矩形左上角点pt1和 右下角点pt2绘制矩形:
cv2.rectangle(image, (10, 50), (60, 300), colors['green'], 3)
cv2.rectangle(image, (80, 50), (130, 300), colors['blue'], -1)
cv2.rectangle(image, (150, 50), (350, 100), colors['red'], -1)
cv2.rectangle(image, (150, 150), (350, 300), colors['cyan'], 10)
绘制这些矩形后,调用show_with_matplotlib(image, ‘cv2.rectangle()’)函数显示图形:
Note:thickness 参数若为负值(例如 -1),则意味着将使用颜色填充图形。
2.1.3 圆形
圆形图形的绘制函数cv2.circle()用法如下:
img = cv2.circle(img, center, radius, color, thickness=1, lineType=8, shift=0)
此函数以点center为中心绘制一个半径为radius的圆:
cv2.circle(image, (50, 50), 40, colors['magenta'], 3)
cv2.circle(image, (150, 150), 40, colors['rand'], -1)
cv2.circle(image, (250, 250), 50, colors['yellow'], 5)
cv2.circle(image, (250, 250), 60, colors['yellow'], 2)
cv2.circle(image, (350, 350), 40, colors['cyan'], -2)
cv2.circle(image, (450, 450), 40, colors['blue'], 3)
绘制完这些圆形后,调用show_with_matplotlib(image, ‘cv2.circle()’)函数显示图像:
2.2 高级图形的绘制
在了解了常用基础图形的绘制之后,我们将介绍如何绘制剪裁线、箭头、椭圆和折线。再次,第一步是创建一个将在其上绘制图形的画布:
image = np.zeros((500, 500, 3), dtype="uint8")
image[:] = colors['gray']
接下来,您可以开始绘制新形状。
2.2.1 剪裁线
剪裁线绘制函数cv2.clipLine()使用方法如下:
retval, pt1_new, pt2_new = cv2.clipLine(imgRect, pt1, pt2)
cv2.clipLine()函数返回矩形内的线段(由输出点pt1_new和pt2_new定义),该函数根据定义的矩形imgRect裁剪线段。如果两个原始点pt1和pt2都在矩形之外,则retval为False;否则返回True:
cv2.line(image, (0, 0), (500, 500), colors['green'], 3)
cv2.rectangle(image, (100, 100), (300, 300), colors['blue'], 3)
ret, p1, p2 = cv2.clipLine((100, 100, 300, 300), (0, 0), (300, 300))
if ret:
cv2.line(image, p1, p2, colors['magenta'], 3)
ret, p1, p2 = cv2.clipLine((100, 100, 300, 300), (250, 150), (0, 400))
if ret:
cv2.line(image, p1, p2, colors['cyan'], 3)
调用show_with_matplotlib(image, ‘cv2.clipLine()’)函数后,在下图中,可以看到代码运行的结果:
2.2.2 箭头
箭头绘制函数cv2.arrowedLine()的用法如下:
cv2.arrowedLine(img, pt1, pt2, color, thickness=1, lineType=8, shift=0, tipLength=0.1)
此函数用于绘制箭头,箭头从pt1定义的点指向pt2定义的点。箭头尖端的长度可以由tipLength参数控制,该参数是根据线段长度(pt1和pt2之间的距离)的百分比定义的:
# 箭头尖端的长度为线段长度的 10%
cv2.arrowedLine(image, (50, 50), (450, 50), colors['cyan'], 3, 8, 0, 0.1)
# 箭头尖端的长度为线段长度的 30%
cv2.arrowedLine(image, (50, 200), (450, 200), colors['magenta'], 3, cv2.LINE_AA, 0, 0.3)
# 箭头尖端的长度为线段长度的 30%
cv2.arrowedLine(image, (50, 400), (450, 400), colors['blue'], 3, 8, 0, 0.3)
以上代码定义了三个箭头,除了箭头的大小不同外,使用了不同的lineType参数cv2.LINE_AA(也可以写 16 )和 8 (也可以写cv2.LINE_8),调用show_with_matplotlib(image, ‘cv2.arrowedLine()’)函数后,可以观察它们之间的区别:
2.2.3 椭圆
绘制椭圆的函数cv2.ellipse()用法如下:
cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness=1, lineType=8, shift=0)
此函数用于绘制不同类型的椭圆:angle参数(以度为单位)可以旋转椭圆;axes参数控制长短轴的大小;startAngle和endAngle参数用于设置所需的椭圆弧(以度为单位),例如,需要完整闭合的椭圆,则startAngle = 0、endAngle = 360:
cv2.ellipse(image, (100, 100), (60, 40), 0, 0, 360, colors['red'], -1)
cv2.ellipse(image, (100, 200), (80, 40), 0, 0, 360, colors['green'], 3)
cv2.ellipse(image, (100, 200), (10, 40), 0, 0, 360, colors['blue'], 3)
cv2.ellipse(image, (300, 300), (20, 80), 0, 0, 180, colors['yellow'], 3)
cv2.ellipse(image, (300, 100), (20, 80), 0, 0, 270, colors['cyan'], 3)
cv2.ellipse(image, (250, 250), (40, 40), 0, 0, 360, colors['magenta'], 3)
cv2.ellipse(image, (400, 100), (30, 60), 45, 0, 360, colors['rand'], 3)
cv2.ellipse(image, (400, 400), (30, 60), -45, 0, 360, colors['rand'], 3)
cv2.ellipse(image, (200, 400), (30, 60), -45, 0, 225, colors['rand'], -1)
调用show_with_matplotlib(image, ‘cv2.ellipse()’)函数后,可以在下图中看到所绘制的椭圆:
2.2.4 多边形
多边形绘制函数cv2.polylines()用法如下:
cv2.polylines(img, pts, isClosed, color, thickness=1, lineType=8, shift=0)
cv2.polylines()函数用于绘制多边形。其中关键参数是pts,用于提供定义多边形的数组,这个参数的形状是(number_vertex, 1, 2),可以通过使用np.array创建坐标(np.int32类型)来定义它,然后对其进行整形以适应pts参数所需形状。如果要创建一个三角形,代码如下所示:
pts = np.array([[400, 5], [350, 200], [450, 200]], np.int32)
pts = pts.reshape((-1, 1, 2))
print("shape of pts '{}'".format(pts.shape))
cv2.polylines(image, [pts], True, colors['green'], 3)
另一个重要参数是isClosed,如果此参数为 True ,则多边形将被绘制为闭合的;否则,第一个顶点和最后一个顶点之间的线段将不会被绘制,从而产生开放的多边形:
pts = np.array([[400, 250], [350, 450], [450, 450]], np.int32)
pts = pts.reshape((-1, 1, 2))
print("shape of pts '{}'".format(pts.shape))
cv2.polylines(image, [pts], False, colors['green'], 3)
以同样的方式,创建五边形和矩形,最后调用show_with_matplotlib(image, ‘cv2.polylines()’)函数,可以在下图中看到绘制完成的多边形:
2.3 绘图函数中的shift参数
上述图形绘制函数通过使用shift参数,可以与像素坐标相关的亚像素精度工作,此时坐标将作为定点数(被编码为整数)传递。
定点是指为整数(小数点左侧)和小数部分(小数点右侧)保留固定位数。
因此,shift参数用于指定小数位数(在小数点右侧),真实点坐标计算如下:
例如,使用以下代码绘制了两个半径为 200 的圆。其中之一使用shift = 2的值来提供亚像素精度。在这种情况下,应该将原点和半径都乘以因子 4 ():
shift = 2
factor = 2 ** shift
print("factor: '{}'".format(factor))
cv2.circle(image, (int(round(249.99 * factor)), int(round(249.99 * factor))), 200 * factor, colors['red'], 1, shift=shift)
cv2.circle(image, (249, 249), 200, colors['green'], 1)
如果shift = 3,则因子的值将为 8 (),依此类推。乘以 2 的幂与将对应于整数二进制表示的位向左移动 1 位,这样就可以将图形浮点坐标上。
为了更方便的使用浮点坐标,也可以对绘图函数进行封装,以cv2.circle()为例创建函数draw_float_circle(),它可以使用shift参数属性来处理浮点坐标:
def draw_float_circle(img, center, radius, color, thickness=1, lineType=8, shift=4):
factor = 2 ** shift
center = (int(round(center[0] * factor)), int(round(center[1] * factor)))
radius = int(round(radius * factor))
cv2.circle(img, center, radius, color, thickness, lineType, shift)
draw_float_circle(image, (250, 250), 200, colors['red'], 1, 8, 0)
draw_float_circle(image, (249.9, 249.9), 200, colors['green'], 1, 8, 1)
draw_float_circle(image, (249.99, 249.99), 200, colors['blue'], 1, 8, 2)
draw_float_circle(image, (249.999, 249.999), 200, colors['yellow'], 1, 8, 3)
调用show_with_matplotlib(image, ‘cv2.circle()’)函数,可以看到绘制完成的图像:
2.4 绘图函数中的 lineType 参数
另一个绘图函数中常见的参数是lineType,它可以采用三个不同的值。虽然我们已经简单了解了这三种类型之间的差异。但是为了更清楚地看到它,可以绘制了三条具有相同粗细和倾斜度的线,仅lineType参数值不同:
image = np.zeros((20, 20, 3), dtype="uint8")
image[:] = colors['gray']
cv2.line(image, (5, 0), (20, 15), colors['yellow'], 1, cv2.LINE_4)
cv2.line(image, (0, 0), (20, 20), colors['red'], 1, cv2.LINE_AA)
cv2.line(image, (0, 5), (15, 20), colors['green'], 1, cv2.LINE_8)
show_with_matplotlib(image, 'LINE_4 LINE_AA LINE_8')
在上图中,yellow = cv2.LINE_4、red = cv2.LINE_AA、green = cv2.LINE_8,可以清楚地看到使用三种不同线型绘制线条时的区别。
3. 文本
OpenCV 也可用于在图像中渲染文本。接下来,将介绍如何使用cv2.putText()函数绘制文本,然后介绍OpenCV中所有的可用字体,最后,了解一些与文本绘制相关的其它OpenCV函数。
3.1 绘制文本
cv2.putText()函数的用法如下:
img = cv.putText(img, text, org, fontFace, fontScale, color, thickness=1, lineType= 8, bottomLeftOrigin=False)
此函数使用fontFace声明的字体类型和fontScale因子从org坐标(如果bottomLeftOrigin = False则为左上角,否则为左下角)开始绘制提供的文本字符串text。最后提供的参数lineType同样可以使用三个不同的可选值: cv2.LINE_4 、 cv2.LINE_8 和 cv2.LINE_AA:
cv2.putText(image, 'learn OpenCV-Python together', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, colors['cyan'], 2, cv2.LINE_4)
cv2.putText(image, 'learn OpenCV-Python together', (10, 230), cv2.FONT_HERSHEY_SIMPLEX, 0.9, colors['cyan'], 2, cv2.LINE_8)
cv2.putText(image, 'learn OpenCV-Python together', (10, 430), cv2.FONT_HERSHEY_SIMPLEX, 0.9, colors['cyan'], 2, cv2.LINE_AA)
show_with_matplotlib(image, 'cv2.putText()')
3.2 OpenCV 文本字体
OpenCV中所有可用的字体如下:
FONT_HERSHEY_SIMPLEX = 0
FONT_HERSHEY_PLAIN = 1
FONT_HERSHEY_DUPLEX = 2
FONT_HERSHEY_COMPLEX = 3
FONT_HERSHEY_TRIPLEX = 4
FONT_HERSHEY_COMPLEX_SMALL = 5
FONT_HERSHEY_SCRIPT_SIMPLEX = 6
FONT_HERSHEY_SCRIPT_COMPLEX = 7
由于所有这些字体都在 (0-7) 范围内,我们可以迭代并调用 cv2.putText() 函数,改变color、fontFace和org参数,使用所有可用字体进行绘制:
fonts = {0: "FONT HERSHEY SIMPLEX", 1: "FONT HERSHEY PLAIN", 2: "FONT HERSHEY DUPLEX", 3: "FONT HERSHEY COMPLEX",
4: "FONT HERSHEY TRIPLEX", 5: "FONT HERSHEY COMPLEX SMALL ", 6: "FONT HERSHEY SCRIPT SIMPLEX",
7: "FONT HERSHEY SCRIPT COMPLEX"}
index_colors = {0: 'blue', 1: 'green', 2: 'red', 3: 'yellow', 4: 'magenta', 5: 'cyan', 6: 'black', 7: 'dark_gray'}
image = np.zeros((650, 650, 3), dtype="uint8")
image[:] = colors['gray']
position = (10, 30)
for i in range(0, 8):
cv2.putText(image, fonts[i], position, i, 1.1, colors[index_colors[i]], 2, cv2.LINE_4)
position = (position[0], position[1] + 40)
cv2.putText(image, fonts[i].lower(), position, i, 1.1, colors[index_colors[i]], 2, cv2.LINE_4)
position = (position[0], position[1] + 40)
show_with_matplotlib(image, 'cv2.putText() using all OpenCV fonts')
结果如下:
3.3 其它与文本相关的函数
为了更好的进行文本的绘制,OpenCV还提供了其它与文本绘制相关的函数,这些函数不是用来绘制文本的,而是用来补充cv2.putText()函数。第一个函数是cv2.getFontScaleFromHeight():
retval = cv2.getFontScaleFromHeight(fontFace, pixelHeight, thickness=1)
此函数返回字体比例(这是在cv2.putText()函数中使用的参数fontScale),以得到提供的高度(以像素为单位)并考虑字体类型 (fontFace) 和thickness。
第二个函数是 cv2.getTextSize() :
retval, baseLine = cv2.getTextSize(text, fontFace, fontScale, thickness)
此函数根据以下参数:要绘制的text、字体类型 (fontFace)、scale和thickness,获取文本大小(宽度和高度)。此函数返回size和baseLine(它对应于相对于文本底部的基线的y坐标):
image = np.zeros((700, 700, 3), dtype="uint8")
image[:] = colors['gray']
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 2.5
thickness = 5
text = 'abcdefghijklmnopqrstuvwxyz'
circle_radius = 10
ret, baseline = cv2.getTextSize(text, font, font_scale, thickness)
text_width, text_height = ret
text_x = int(round((image.shape[1] - text_width) / 2))
text_y = int(round((image.shape[0] + text_height) / 2))
cv2.circle(image, (text_x, text_y), circle_radius, colors['green'], -1)
cv2.rectangle(image, (text_x, text_y + baseline), (text_x + text_width - thickness, text_y - text_height), colors['blue'], thickness)
cv2.circle(image, (text_x, text_y + baseline), circle_radius, colors['red'], -1)
cv2.circle(image, (text_x + text_width - thickness, text_y - text_height), circle_radius, colors['cyan'], -1)
cv2.line(image, (text_x, text_y + int(round(thickness/2))), (text_x + text_width - thickness, text_y + int(round(thickness/2))), colors['yellow'], thickness)
cv2.putText(image, text, (text_x, text_y), font, font_scale,colors['magenta'], thickness)
show_with_matplotlib(image, 'cv2.getTextSize() + cv2.putText()')
绘制结果如下图所示:
概括
本文介绍了OpenCV提供的与绘制图形和文本相关的函数。在图形方面,我们了解了如何绘制基本图形(直线、矩形和圆形等)以及高级图形(剪裁线、箭头、椭圆和多边形)。在文本方面,我们了解了如何绘制文本以及OpenCV库中的所有可用字体。
系列链接
OpenCV-Python实战(1)——OpenCV简介与图像处理基础
OpenCV-Python实战(2)——图像与视频文件的处理
OpenCV-Python实战(4)——OpenCV常见图像处理技术
OpenCV-Python实战(5)——OpenCV图像运算
OpenCV-Python实战(6)——OpenCV中的色彩空间和色彩映射
OpenCV-Python实战(7)——直方图详解
OpenCV-Python实战(8)——直方图均衡化
OpenCV-Python实战(9)——OpenCV用于图像分割的阈值技术
OpenCV-Python实战(10)——OpenCV轮廓检测
OpenCV-Python实战(11)——OpenCV轮廓检测相关应用
OpenCV-Python实战(12)——一文详解AR增强现实
OpenCV-Python实战(13)——OpenCV与机器学习的碰撞
OpenCV-Python实战(14)——人脸检测详解
版权声明:本文为博主盼小辉丶原创文章,版权归属原作者,如果侵权,请联系我们删除!
原文链接:https://blog.csdn.net/LOVEmy134611/article/details/119712265