img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)#-1表示显示所有轮廓,123表示第123个轮廓
cv_show(res,'res')
代码解析
这段代码用于在图像上检测并绘制轮廓。以下是每一步的解析:
- 读取图像
:
img = cv2.imread('contours.png')
- 使用OpenCV读取名为contours.png的图像。
- 转换为灰度图
:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- 将彩色图像转换为灰度图,以便进行阈值处理。
- 二值化处理
:
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
- 使用固定阈值对灰度图进行二值化处理,生成二值图像thresh。
- 查找轮廓
:
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
- cv2.findContours函数用于查找二值图像中的轮廓。
- cv2.RETR_TREE:检索所有层级的轮廓。
- cv2.CHAIN_APPROX_NONE:存储所有的轮廓点。
- 绘制轮廓
:
draw_img = img.copy() res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
- img.copy():创建图像的副本,避免修改原图像。
- cv2.drawContours用于绘制轮廓:
- contours:要绘制的轮廓集合。
- -1:绘制所有轮廓。
- (0, 0, 255):轮廓线条颜色(红色)。
- 2:线条厚度。
- 显示结果
:
cv_show(res, 'res')
- 使用自定义函数cv_show显示结果图像res。
- 确保定义了cv_show,或者使用cv2.imshow替代。
def cv_show(image, title): cv2.imshow(title, image) cv2.waitKey(0) cv2.destroyAllWindows()
代码应用
- 边缘检测与分析
:
- 该代码可以用于图像中物体的边缘检测和分析。
- 形状识别
:
- 通过分析轮廓的形状,可以进行简单的形状识别和分类。
注意事项
- 确保输入图像路径正确。
- 调整阈值参数以适应不同的图像类型和对比度。
cnt = contours[0]
#面积
cv2.contourArea(cnt)
#周长,True表示闭合的
cv2.arcLength(cnt,True)
这段代码用于计算指定轮廓的面积和周长。以下是每一步的解析:
1. 选择轮廓
cnt = contours[0]
- contours 是之前用 cv2.findContours 函数检测到的所有轮廓。
- cnt = contours[0] 表示选择第一个轮廓。
2. 计算轮廓面积
cv2.contourArea(cnt)
- cv2.contourArea(cnt) 用于计算给定轮廓 cnt 的面积。
- 返回值是一个浮点数,表示轮廓内的像素总数。
3. 计算轮廓周长
cv2.arcLength(cnt, True)
- cv2.arcLength(cnt, True) 用于计算给定轮廓 cnt 的周长。
- cnt 是指定的轮廓。
- 第二个参数 True 表示轮廓是闭合的。如果轮廓不是闭合的,应传 False。
完整代码示例
结合之前的代码:
import cv2 # 读取图像 img = cv2.imread('contours.png') # 转换为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 选择第一个轮廓 cnt = contours[0] # 计算面积 area = cv2.contourArea(cnt) print("Contour Area: ", area) # 计算周长 perimeter = cv2.arcLength(cnt, True) print("Contour Perimeter: ", perimeter) # 绘制轮廓 draw_img = img.copy() res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # 显示结果 def cv_show(image, title): cv2.imshow(title, image) cv2.waitKey(0) cv2.destroyAllWindows() cv_show(res, 'res')
应用场景
- 轮廓分析
:
- 面积和周长是基本的几何特征,可以用于分析和分类不同的形状和物体。
- 形状识别
:
- 通过计算面积和周长,可以进一步计算形状特征,比如圆度、长宽比等,以识别和分类不同形状的物体。
- 图像处理
:
- 在图像增强、物体检测等任务中,这些几何特征可以提供有价值的信息。
注意事项
- 确保轮廓 cnt 是有效的。如果 contours 为空,尝试其他预处理方法提高轮廓检测的效果。
- 调整阈值参数 127,以适应不同的图像对比度和亮度。
轮廓近似
轮廓近似,用最少的线来代替,在几个点之间的直线,如果能用更少的点来表示,就采用更少的点。
轮廓近似是图像处理中常用的技术,用于简化轮廓,减少轮廓点的数量,从而用更少的直线段来表示轮廓。这种技术在形状识别和分析中非常有用。OpenCV 提供了一个函数 cv2.approxPolyDP 来执行轮廓近似。
轮廓近似算法
cv2.approxPolyDP 基于道格拉斯-普克曲线简化算法(Douglas-Peucker algorithm)。其基本思想是用少量的点来近似一个给定的轮廓曲线,使得近似后的曲线在视觉上和原始曲线非常接近。
代码示例
以下是如何使用 OpenCV 进行轮廓近似的示例代码:
import cv2 import numpy as np # 读取图像 img = cv2.imread('contours.png') # 转换为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 选择第一个轮廓 cnt = contours[0] # 计算轮廓的周长 epsilon = 0.01 * cv2.arcLength(cnt, True) # 进行轮廓近似 approx = cv2.approxPolyDP(cnt, epsilon, True) # 绘制原始轮廓和近似轮廓 draw_img = img.copy() cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2) # 红色表示原始轮廓 cv2.drawContours(draw_img, [approx], -1, (0, 255, 0), 2) # 绿色表示近似轮廓 # 显示结果 def cv_show(image, title): cv2.imshow(title, image) cv2.waitKey(0) cv2.destroyAllWindows() cv_show(draw_img, 'Approximated Contours')
参数说明
- cnt:要进行近似的轮廓。
- epsilon:近似精度,表示原始轮廓到近似轮廓的最大距离。该值越小,近似结果越精细。通常,epsilon 的值可以设置为轮廓周长的百分比,如 0.01 * cv2.arcLength(cnt, True)。
- True:表示轮廓是闭合的。
结果
- 红色轮廓:表示原始轮廓。
- 绿色轮廓:表示近似后的轮廓。
应用场景
- 形状简化
:
- 通过轮廓近似,可以将复杂的形状简化为简单的多边形,这对于形状分析和识别非常有用。
- 形状匹配
:
- 近似后的轮廓可以用于形状匹配和比较,减少计算复杂度。
- 图像压缩
:
- 将复杂的轮廓简化为少量的直线段,可以用于图像数据的压缩和传输。
注意事项
- 选择合适的 epsilon 值非常重要。epsilon 过大可能导致轮廓过度简化,失去原有形状的特征。epsilon 过小则可能无法起到简化作用。
- 在实际应用中,可以通过实验调整 epsilon 值,以获得最优结果。

epsilon = 0.15*cv2.arcLength(cnt,True) #主要进行调参的函数
approx = cv2.approxPolyDP(cnt,epsilon,True)
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,'res')
这段代码旨在对轮廓进行近似,然后绘制近似后的轮廓。通过调整 epsilon 参数,可以控制轮廓近似的精度。以下是每一步的解析:
1. 计算近似参数 epsilon
epsilon = 0.15 * cv2.arcLength(cnt, True)
- epsilon 是近似精度参数。
- cv2.arcLength(cnt, True) 返回轮廓 cnt 的周长。
- 0.15 是一个比例系数,表示原始轮廓到近似轮廓的最大距离。这个值可以根据需要进行调整。
2. 进行轮廓近似
approx = cv2.approxPolyDP(cnt, epsilon, True)
- cv2.approxPolyDP 执行轮廓近似。
- cnt 是要进行近似的轮廓。
- epsilon 是近似精度。
- True 表示轮廓是闭合的。
3. 绘制近似轮廓
draw_img = img.copy() res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
- draw_img = img.copy() 创建图像的副本,避免修改原图像。
- cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2) 绘制近似后的轮廓:
- draw_img 是要绘制轮廓的图像。
- [approx] 是近似后的轮廓。
- -1 表示绘制所有层级的轮廓。
- (0, 0, 255) 是轮廓线条的颜色(红色)。
- 2 是线条厚度。
4. 显示结果
cv_show(res, 'res')
- 使用自定义函数 cv_show 显示结果图像 res。
完整代码示例
为了让代码更完整,这里包括了前面的所有步骤:
import cv2 import numpy as np # 自定义显示函数 def cv_show(image, title): cv2.imshow(title, image) cv2.waitKey(0) cv2.destroyAllWindows() # 读取图像 img = cv2.imread('contours.png') # 转换为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 选择第一个轮廓 cnt = contours[0] # 计算近似参数 epsilon epsilon = 0.15 * cv2.arcLength(cnt, True) # 进行轮廓近似 approx = cv2.approxPolyDP(cnt, epsilon, True) # 绘制近似轮廓 draw_img = img.copy() res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2) # 显示结果 cv_show(res, 'res')
调参建议
- 0.15 的调整: 这个值是一个经验值,可以根据实际情况进行调整。值越大,轮廓近似的程度越高,轮廓会变得更加简化;值越小,轮廓近似的程度越低,轮廓会更加接近原始形状。
- 实验性调整: 在实际应用中,你可以通过实验调整这个值,查看不同 epsilon 值下的效果,找到最佳的近似参数。
应用场景
- 形状识别和分析: 通过近似后的轮廓,可以更容易地进行形状识别和分析,因为简化的轮廓减少了计算复杂度。
- 图像压缩: 简化后的轮廓可以用于图像数据的压缩和传输。
- 对象检测: 在对象检测中,简化后的轮廓可以提高检测的速度和准确性。

图中白色的是原图像,红色的是轮廓近似。
边界矩形
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')
你的代码旨在读取图像、进行预处理、查找轮廓,然后在图像上绘制一个包围轮廓的矩形。以下是每一步的详细解析及改进的代码示例。
代码解析
- 读取图像
img = cv2.imread('contours.png')
- 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- 二值化处理
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
- 查找轮廓
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
注意: 从 OpenCV 4.0 开始,cv2.findContours 只返回两个值:contours 和 hierarchy。在旧版本中返回三个值。
- 选择第一个轮廓
cnt = contours[0]
- 计算包围轮廓的矩形
x, y, w, h = cv2.boundingRect(cnt)
- 绘制矩形
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
- 显示结果
cv_show(img, 'img')
下面是改进后的完整代码:
完整代码示例
import cv2 import numpy as np # 自定义显示函数 def cv_show(image, title): cv2.imshow(title, image) cv2.waitKey(0) cv2.destroyAllWindows() # 读取图像 img = cv2.imread('contours.png') # 转换为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 (适用于 OpenCV 4.0 及以上版本) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 选择第一个轮廓 cnt = contours[0] # 计算包围轮廓的矩形 x, y, w, h = cv2.boundingRect(cnt) # 绘制矩形 img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 显示结果 cv_show(img, 'img')
关键点说明
- cv2.findContours
返回值
- 在 OpenCV 4.0 及以上版本中,cv2.findContours 只返回 contours 和 hierarchy,而不是 binary。
- 因此,你的代码中的 binary, contours, hierarchy 会引发错误,需要改为 contours, hierarchy = cv2.findContours(...)。
- cv2.boundingRect
- cv2.boundingRect(cnt) 返回的 (x, y, w, h) 分别是矩形的左上角坐标 (x, y) 和矩形的宽度 w 及高度 h。
- 绘制矩形
- cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) 绘制的矩形颜色为绿色 (0, 255, 0),线条宽度为 2。
应用场景
- 目标检测:绘制包围目标的矩形框,用于目标检测和识别。
- 形状分析:通过计算包围矩形的宽和高,可以进行形状分析和统计。
- 图像标注:将感兴趣的区域用矩形框标注出来,便于后续处理和分析。
注意事项
- 选择适当的阈值 127 以适应不同的图像对比度和亮度。
- 如果图像中有多个轮廓,可以选择其他轮廓进行绘制。你可以通过遍历 contours 列表来处理所有轮廓。
