opencv 轮廓检测

发布时间 2023-05-06 13:01:08作者: 贝壳里的星海

轮廓检测


轮廓检测的作用

  • 可以检测图图像或者视频中物体的轮廓
  • 计算多边形边界,形状逼近和计算感兴趣区域

为了更精确地提取轮廓,请使用二值图。也就是说,在使用轮廓提取函数前,请将源图片运用阈值进行二值化cv2.threshold()或者采用Canny边缘检测。
findContours 函数会修改源图片,如果希望在轮廓检测后继续使用源图片,务必提前保存在另一个变量中。
在OpenCV中,轮廓检测视作从黑色背景中提取白色的物体,所以,在结果中,白色表示物体,黑色表示背景。

cv2.findContours

查找并得到物体的轮廓

输入的是图像的二值图

contours,hierarchy=cv2.findContours(image, mode, method, contours=None, hierarchy=None, offset=None)

输入参数
- image=img    输入的是二值化图(黑白)
- mode         轮廓搜索模式
- method       轮廓近似方法
- contours

返回参数
- contours         轮廓本身 shape=(len,points,1,2) 四个维度列表
- hierarchy        每条轮廓对应的属性

mode 参数:
cv2.RETR_EXTERNAL     表示只检测外轮廓
cv2.RETR_LIST         检测的轮廓不建立等级关系
cv2.RETR_CCOMP        建立两个等级的轮廓
cv2.RETR_TREE         建立一个等级树结构的轮廓

method:
cv2.CHAIN_APPROX_NONE        存储所有的轮廓点
cv2.CHAIN_APPROX_SIMPLE      压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标
image = cv2.imread('math.jpg')
grayIma = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 将图像二值化,提高准确率
ret, image1 = cv2.threshold(grayIma, 127, 255, cv2.THRESH_BINARY)
ShowImage('image1', image1)

contours, hierarchy = cv2.findContours(iamge, mode, method) 

特征矩

特征矩可以帮助您计算一些特征,例如物体的质心,物体的面积等。请查看特征矩上的维基百科页面。函数cv.moments()提供了所有计算出的矩值的字典

import numpy as np
import cv2 as cv
img = cv.imread('star.jpg',0)
ret,thresh = cv.threshold(img,127,255,0)
contours,hierarchy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
print( M )

\[C_x = \frac{M_{10}}{M_{00}} \;\; C_y = \frac{M_{01}}{M_{00}} \]

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

cv2.drawContours

根据findcontours得到的轮廓,对轮廓进行绘制

img=drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

输入参数

image         幕布图像,目标图像
contours      轮廓本身  shape=(len,points,1,2)
contourIdx    轮廓索引  指示要绘制的轮廓的参数 -1代表所有
color         绘图颜色  BGR
thickness     线宽      -1表示填充
lineType      线的连通性
返回参数 
img 
drawimage = image.copy()
result1 = cv2.drawContours(drawimage, contours, -1, (0,255,0), 1)  # 绘制所有轮廓

完整案例

import cv2
import numpy as np
 
src = cv2.imread("main.jpg")
 
# Canny处理得到二值化图像
src = cv2.GaussianBlur(src, (5, 5), 5)
canny = cv2.Canny(src, 0,30)
 
# 轮廓检测
contours, hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 
# 注意这里第一个参数输入的是原始图像
cv2.drawContours(src, contours, -1, (0,0,255), 1)
 
cv2.imshow("src", src)
cv2.imshow("canny", canny)
cv2.waitKey()
cv2.destroyAllWindows()

轮廓特征

计算轮廓面积

cv2.contourArea(contour,oriented)

输入参数
contour  单个轮廓(points,1,2) >>> contours[0]
oriented 有方向的区间标识,默认false
返回参数 
面积

计算轮廓周长

计算轮廓的周长
cv2.arcLength(curve, closed) 
输入参数  
curve    单个轮廓(points,1,2) >>> contours[0]
closed   指定对象的形状是闭合还是打开的(曲线) true false
接受的参数为二值图,检索模式,有四种,method为轮廓的近似办法
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 

img = cv2.drawContours(img,contours,-1,(0,0,255),3)  
"""
计算轮廓的周长
cv2.arcLength(curve, closed) 
输入参数  
curve    单个轮廓(points,1,2) >>> contours[0]
closed   指定对象的形状是闭合还是打开的(曲线) true false
"""
res = cv2.contourArea(contours[0]) 
length= cv2.arcLength(contours[0],True)  

轮廓近似和凸包
???

边界矩形 >>> 正矩形框
"""
x, y, w, h = cv2.boundingRect(array)
输入参数
array   单个轮廓(points,1,2) >>> contours[0]
返回参数
x,y,w,h   x,y是矩阵左上点的坐标,w,h是矩阵的宽和高
"""

# 示例:   
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 画出contours
cv2.drawContours(bgr_img, contours, -1, (0, 0, 255), 3)
# 将所有的 contours 绘制正矩形框,并画出 
bounding_boxes = [cv2.boundingRect(cnt) for cnt in contours]
for bbox in bounding_boxes:
     [x , y, w, h] = bbox
     cv2.rectangle(bgr_img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imshow("name", bgr_img)
cv2.waitKey(0)

最小边界矩形 >>> 斜矩形框
"""
cv2.minAreaRect(points)
输入参数
points   单个轮廓(points,1,2) >>> contours[0]
返回参数
rect=((x,y)(w,h),D)  Box2D结构rect (最小外接矩形的中心(x,y),(宽度w,高度h),旋转角度--水平x方向逆时针,与之遇到的第一条边为宽,w,h不是以长短定义的)
"""
min_boundingbox = cv2.minAreaRect(contours[0])
min_boundingbox = ((x,y)(w,h),D)

# 获得最下外接矩形的四个顶点
"""
box = cv2.boxPoints(box)
输入参数
box       (中心(x,y), (宽,高), 旋转角度)
返回参数
boxpoint  矩形的四个顶点  boxpoint.shape=(4,2)type(point)=float
"""
boxpoint = cv2.boxPoints(min_boundingbox)
box = np.int0(box)   # 数据取整
img_box=cv2.drawContours(img, [box], 0, (0, 0, 255), 5) # 画图

参考资料

http://woshicver.com/

https://blog.csdn.net/weixin_43229348/article/details/125980463