1.图像的轮廓
轮廓是指图形或物体的外边缘线条,简单的几何图形是由平滑的线构成的容易识别,但不规则图形的轮廓由许多个点构成,识别起来比较困难。Opencv提供了findContours()方法来判断图像的边缘,之后将边缘的点封装成数组返回,语法结构如下:
contours, hierarchy = cv2.findContours(image, mode, method)
参数说明:
image:被检测的图像,必须是8位单通道二值图像,若原始图像是彩色的,必须转化为灰度图像,并经过二值化阈值处理
mode:轮廓的检索模式(下表)
method:检测轮廓时使用的方法(下表)
返回值说明:
contours:检测出的所有轮廓,list类型每一个元素都是某个轮廓的像素坐标数组
hierarchy:轮廓之间的层次关系
OpenCV还提供了drawContours()方法用来绘制轮廓,语法结构如下 :
参数说明:
image
:要绘制轮廓的图像。这个图像应该是单通道(灰度图)或三通道(彩色图)的。contours
:轮廓点集,通常是由cv2.findContours()
方法返回的第二个参数(在某些版本的OpenCV中,返回值可能有所不同,但contours
始终是轮廓点集的列表)。contourIdx
:指定要绘制的轮廓索引。如果是-1,则绘制所有轮廓。color
:轮廓的颜色。对于灰度图,它是一个标量值;对于彩色图,它是一个BGR元组(即颜色顺序是蓝、绿、红)。thickness
:轮廓线的粗细。如果为负数(如cv2.FILLED
),则轮廓内部将被填充。lineType
:线条的类型,例如cv2.LINE_8
、cv2.LINE_AA
等。如果未指定,默认为cv2.LINE_8
。hierarchy
:轮廓的层次结构,由cv2.findContours()
返回(在某些版本的OpenCV中可能返回)。如果不需要,可以设置为None
。maxLevel
:绘制轮廓的最大层级数,仅当hierarchy
非空时才有效。如果为0,则只绘制指定的轮廓;如果为1,则绘制该轮廓及其直接子轮廓;依此类推。offset
:轮廓点集的偏移量。这是一个可选参数,表示在绘制轮廓时,轮廓点集中的所有点都要加上这个偏移量。
1.1绘制几何图像的轮廓
操作用图:
操作代码示例:
import cv2
img = cv2.imread(r"C:\Users\cgs\Desktop\pictures\5(9).jpg") # 读取原图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 彩色图像转为变成单通道灰度图像
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 灰度图像转为二值图像
# 检测图像中出现的所有轮廓,记录轮廓的每一个点
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# 绘制所有轮廓,宽度为5,颜色为红色
cv2.drawContours(img, contours, -1, (0, 0, 255), 5)
cv2.imshow("img", img) # 显示绘制结果
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
1.2绘制不规则的轮廓
操作用图像:
操作代码示例:
import cv2
img = cv2.imread(r"C:\Users\cgs\Desktop\pictures\5(10).jpg") # 读取原图
cv2.imshow("img", img) # 显示原图
img = cv2.medianBlur(img, 5) # 使用中值滤波去除噪点
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 原图从彩图变成单通道灰度图像
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 灰度图像转化为二值图像
cv2.imshow("binary", binary) # 显示二值化图像
# 获取二值化图像中的轮廓极轮廓层次数据
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img, contours, -1, (0, 0, 255), 2) # 在原图中绘制轮廓
cv2.imshow("contours", img) # 显示绘有轮廓的图像
cv2.waitKey()
cv2.destroyAllWindows()
效果图像:
2.轮廓拟合
拟合是指将平面上的一系列点用一条光滑的曲线连接起来,轮廓的拟合就是值将凹凸不平的轮廓用平整的几何图形体现出来
2.1矩形包围框
retval = cv2.boundingRect(array)
参数说明:
array:轮廓数组
返回值说明:
retval: 返回一个包含四个整数的元组 (x, y, w, h),具体含义如下:
x: 矩形的左上角的 x 坐标。
y: 矩形的左上角的 y 坐标。
w: 矩形的宽度。
h: 矩形的高度。
操作用图像:
操作代码示例:
import cv2
img = cv2.imread(r"C:\Users\cgs\Desktop\pictures\6(1).png") # 读取原图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 从彩色图像变成单通道灰度图像
# 将灰度图像进行二值化阈值处理
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取二值化图像中的轮廓极轮廓层次数据
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(contours[0]) # 获取第一个轮廓的最小矩形边框,记录坐标和宽高
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2) # 绘制红色矩形
cv2.imshow("img", img) # 显示绘制结果
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
2.2圆形包围框
center, radius = cv2.minEnclosingCircle(points)
参数说明:
center:元组类型,包含两个浮点值(圆心横坐标和纵坐标)
radius;浮点类型,最小圆形包围框半径
操作代码示例:
import cv2
img = cv2.imread(r"C:\Users\cgs\Desktop\pictures\6(1).png") # 读取原图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 从彩色图像变成单通道灰度图像
# 将灰度图像进行二值化阈值处理
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取二值化图像中的轮廓极轮廓层次数据
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
center, radius = cv2.minEnclosingCircle(contours[0]) # 获取最小圆形边框的圆心点和半径
x = int(round(center[0])) # 圆心点横坐标转为近似整数
y = int(round(center[1])) # 圆心点纵坐标转为近似整数
cv2.circle(img, (x, y), int(radius), (0, 0, 255), 2) # 绘制圆形
cv2.imshow("img", img) # 显示绘制结果
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
3.凸包
在OpenCV中,凸包(Convex Hull)是一个计算几何中的概念,用于描述一个点集的最外层凸多边形。具体来说,凸包是指完全包含原有轮廓,并且仅由轮廓上的点所构成的多边形,其特点是每一处都是凸的,即在凸包内连接任意两点的直线都在凸包的内部,并且任意连续3个点的内角小于180度。
语法结构如下:
hull = cv2.convexHull(points, clockwise=None, returnPoints=True)
参数说明
- points:这是输入的点集,通常是一个NumPy数组,形状为
(N, 1, 2)
或(N, 2)
,其中N
是点的数量,每个点由两个元素(通常是x和y坐标)表示。- clockwise(可选):该参数指定凸包的输出方向。如果为
True
,则凸包的方向是顺时针的;如果为False
,则为逆时针。如果未指定(即None
),则凸包的方向由凸包算法的内部实现决定。- returnPoints(可选):如果为
True
,则返回凸包上的点。如果为False
,则返回凸包索引(即原始点集中的索引)。在大多数情况下,你会希望这个参数为True
。返回值
- hull:如果
returnPoints=True
,则hull
是一个NumPy数组,包含凸包上的点。这些点按凸包轮廓的顺序排列。- 如果
returnPoints=False
,则hull
是一个包含索引的数组,这些索引指向原始点集中的点,按凸包轮廓的顺序排列。
操作代码示例:
import cv2img = cv2.imread(r"C:\Users\cgs\Desktop\pictures\6(1).png") # 读取原始图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转为灰度图像
ret, binary = cv2.threshold(gray, 127, 225, cv2.THRESH_BINARY) # 二值化阈值处理
# 检测图像中出现的所有轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0]) # 获取轮廓的凸包
cv2.polylines(img, [hull], True, (0, 0, 255), 2) # 绘制凸包
cv2.imshow("img", img) # 显示图像
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
4.Canny边缘检测
Canny边缘检测算法是一种非常流行的边缘检测算法,由John F. Canny在1986年提出。该算法旨在在噪声抑制和边缘检测之间取得最佳平衡,通常通过以下步骤实现:
噪声去除:首先,使用高斯滤波器平滑图像以去除噪声。这一步很重要,因为边缘检测对噪声很敏感。
计算梯度强度和方向:然后,计算图像中每个像素点的梯度强度和方向。这通常使用Sobel算子或其他梯度算子来完成。
非极大值抑制:在得到梯度强度和方向后,算法会对每个像素位置进行非极大值抑制。这一步的目的是保留局部梯度最大的点,作为边缘点。
双阈值处理和边缘连接:最后,算法使用两个阈值(高阈值和低阈值)来检测和连接边缘。首先,通过高阈值得到一个边缘图像,这个图像可能包含一些不连续的边缘片段。然后,通过检查由低阈值得到的边缘图像中哪些边缘片段可以连接到高阈值边缘图像中的边缘片段,来连接和恢复这些边缘。
Canny()方法语法结构:
edges = cv2.Canny(image, threshold1, threshold2,apertureSize, L2gradient)
image:要进行边缘检测的输入图像,应为灰度图。
threshold1:第一个阈值,用于边缘连接时的低阈值。
threshold2:第二个阈值,用于检测边缘时的高阈值。
apertureSize:可选参数,Sobel算子孔径大小
L2gradient:可选参数,计算图像梯度的标识
返回值说明:
edges:输出的边缘图像,与输入图像具有相同的尺寸和类型
操作用图像:
操作代码示例:
import cv2
img = cv2.imread(r"C:\Users\cgs\Desktop\pictures\5(5).jpg") # 读取原图
r1 = cv2.Canny(img, 10, 50); # 使用不同的阈值进行边缘检测
r2 = cv2.Canny(img, 100, 200);
r3 = cv2.Canny(img, 400, 600);cv2.imshow("img", img) # 显示原图
cv2.imshow("r1", r1) # 显示边缘检测结果
cv2.imshow("r2", r2)
cv2.imshow("r3", r3)
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
5.霍夫变换
霍夫变换(Hough Transform)是一种图像处理技术,用于检测图像中的几何形状,尤其是直线和圆等常见形状。它特别适用于处理有噪声的图像数据,因为它能够在特征空间中找到形状,即使在图像中这些形状可能是断裂的或者被遮挡的。
5.1 直线检测
OpenCV中的HoughLinesP()方法
HoughLinesP()
是 OpenCV 中用于直线检测的函数之一,与HoughLines()
相比,HoughLinesP()
能够直接返回直线的两个端点,这对于后续处理(如绘制直线)更为方便。
lines = cv2.HoughLinesP(image, rho, theta, threshold, minLineLength=0, maxLineGap=0)
参数说明:
image: 输入图像,应该是边缘检测后的二值图像(通常是Canny边缘检测的结果)。
rho:检测直线使用的半径步长,值为1时,表示检测所有可能的半径步长
theta: 以弧度为单位的θ的精度。
threshold: 累加器平面的阈值参数。只有那些获得足够交点的曲线才被返回。
minLineLength: 最小线段长度。比这个长度短的线段将被拒绝。
maxLineGap: 线段上最大间隔,用于将同一行上的点连接成线段。如果间隔大于此值,则视为两条线段。
操作用图像:
操作代码示例:
import cv2
import numpy as npimg = cv2.imread(r"C:\Users\cgs\Desktop\pictures\pen.jpg") # 读取原图
o = img.copy() # 复制原图
o = cv2.medianBlur(o, 5) # 使用中值滤波进行降噪
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY) # 从彩色图像变成单通道灰度图像
binary = cv2.Canny(o, 50, 150) # 绘制边缘图像
# 检测直线,精度为1,全角度,阈值为15,线段最短100,最小间隔为18
lines = cv2.HoughLinesP(binary, 1, np.pi / 180, 15, minLineLength=100, maxLineGap=18)
for line in lines: # 遍历所有直线x1, y1, x2, y2 = line[0] # 读取直线两个端点的坐标cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2) # 在原始图像上绘制直线
cv2.imshow("canny", binary) # 显示二值化边缘图案
cv2.imshow("img", img) # 显示绘制结果
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
5.2圆环检测
OpenCV中的HoughCircles()方法
在OpenCV中,
HoughCircles()
函数用于实现基于霍夫变换的圆环检测。它返回图像中检测到的圆的参数(圆心和半径)
cv2.HoughCircles(image, method, dp, minDist, param1=100, param2=100, minRadius=0, maxRadius=0)
参数说明:
image:原始图像
method:检测圆的方法。目前OpenCV中唯一实现的方法是cv2.HOUGH_GRADIENT,它基于边缘的梯度信息。
dp:累加器分辨率与图像分辨率的反比。例如,如果dp=1,则累加器和输入图像具有相同的分辨率。dp=2,累加器分辨率是图像分辨率的一半。
minDist:检测到的圆心之间的最小距离。如果参数设置得太小,则可能会错误地检测到多个相邻的圆。
param1:Canny边缘检测器的高阈值(第一阶段)。记住,低阈值是高阈值的一半。
param2:累加器阈值,即识别为圆所需的投票数。参数值越高,检测到的圆越完美。
minRadius:圆半径的最小值。
maxRadius:圆半径的最大值。
返回值说明:
circles:函数返回一个包含圆参数(x, y, radius)的NumPy数组,每个圆占用数组的一行。如果未找到圆,则返回None。
操作用图像:
操作代码示例:
import cv2
import numpy as npimg = cv2.imread(r"C:\Users\cgs\Desktop\pictures\6(2).jpg") # 读取原图
o = img.copy() # 复制原图
o = cv2.medianBlur(o, 5) # 使用中值滤波进行降噪
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY) # 从彩色图像变成单通道灰度图像
# 检测圆环,圆心最小间距为70,Canny最大阈值为100,投票数超过25。最小半径为10,最大半径为50
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 70, param1=100, param2=25, minRadius=10, maxRadius=50)
circles = np.uint(np.around(circles)) # 将数组元素四舍五入成整数
for c in circles[0]: # 遍历圆环结果x, y, r = c # 圆心横坐标、纵坐标和圆半径cv2.circle(img, (x, y), r, (0, 0, 255), 3) # 绘制圆环cv2.circle(img, (x, y), 2, (0, 0, 255), 3) # 绘制圆心
cv2.imshow("img", img) # 显示绘制结果
cv2.waitKey()
cv2.destroyAllWindows()
操作效果图像:
有关轮廓检测的内容就到这里了,感谢大家的观看!!!