Opencv学习(三)轮廓检测

什么是轮廓检测

轮廓检测就是在一张只有0和1的图片上绘制一系列的点,这些点就是图像中的曲线。函数findContours()就是从二值图像中寻找轮廓,在这个函数中,输入图像可以是从Canny()函数得到的有边缘像素的图像,或者是通过threshold()、adaptiveThreshold()处理后得到的图像。

比如下面这张0-9的原始图片
image

经过轮廓检测后得到的图片
image

如何进行轮廓检测

findcontours函数

在opencv中使用函数findContours()来进行轮廓检测
下面是函数原型
python:cv.FindContours(image, storage, mode=CV_RETR_LIST, method=CV_CHAIN_APPROX_SIMPLE, offset=(0, 0))
C++: void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point())

findcontours参数介绍

1.image:原始图像,必须是8bit单通道图像,并且应该是二值图像,(如果不是--非0值被当做1,0值仍然是0)。该参数传入后会在原始图像上直接修改,因此,一般使用时传入原图像的副本

2.contours:被检测到的轮廓,是一个存储坐标点的向量。(在py中,作为第一个返回值。在c++中是一个传入传出参数。)

3.mode:轮廓检测方法。

| CV_RETR_EXTERNAL | 只检测外轮廓 |
| CV_RETR_LIST | 检测所有轮廓(内和外)但不建立任何层次关系 |
| CV_RETR_CCOMP | 检索所有轮廓并将它们组织成一个两级层次结构(顶层--外轮廓,底层--内轮廓) |
| CV_RETR_TREE | 检索所有轮廓并重建嵌套轮廓的完整层次结构 |

4.method:轮廓近似方法。

| CV_CHAIN_APPROX_NONE | 用绝对值存储所有轮廓点 |
| CV_CHAIN_APPROX_SIMPLE | 压缩水平、垂直和对角线段,只留下它们的端点。 |

5.offset:每个轮廓点移位的可选偏移量

drawContours函数

该函数用来绘制经过检测的轮廓
函数原型
Python: cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
C++: void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )

drawContours参数介绍

1.image:输入图像,(在C++中为输入输出参数)
2.contours:所有检测到的轮廓,每个元素作为一个Point存储在vector中
3.contourIdx:表示要绘制的轮廓参数,如果为-1就绘制所有轮廓
4.color:绘制的颜色,是一个Scalar
5.thickness:绘制线条的粗细
6.lineType:线条类型,常用LINE_AA
7~9 可选参数,没用过,不知道效果如何

注意事项:
1.一般是在读入的原始图像上进行绘制,如果在灰度图或者二值图上绘制,好像没有效果(上次很久绘制不出来,一直找不到原因,踩坑+1)
2.drawContours的第二个参数可以直接用-1。但是如果是在循环中,可以用循环因子来绘制每个轮廓,效果都是一样的

使用实例

#读取图像
template=cv2.imread("D:image	emplate.png")
imshow("image",template)
#化为灰度图
ref_template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
imshow("ref_gray",ref_template)
#化为二值图
ref_template=cv2.threshold(ref_template,10,255,cv2.THRESH_BINARY_INV)[1]
imshow("ref_threshold",ref_template)

#轮廓检测
##findContours 只接受二值图   RETR_EXTERNAL 只检测外轮廓   CHAIN_APPROX_SIMPLE 只保留终点坐标
#在opencv4中要用hierarchy接收,而不能直接取[1]
refCnts,hierarchy=cv2.findContours(ref_template.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#绘制轮廓
cv2.drawContours(template,refCnts,-1,(0,0,255),3)
imshow("draw_contours",template)

结果展示

1.读取的原始图像
image

2.灰度图
image

3.二值图
image

4.绘制检测的轮廓
image


如果我想把每个数字用一个矩形框而不是绘制它的边框,该怎么解决?-----轮廓近似

什么是轮廓近似

将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定
比如在上面的几个数字中,我想把边界用矩形框住,此时就需要使用到轮廓近似

如何进行轮廓近似

假设我们要在一幅图像中查找一个矩形,但是由于图像的种种原因我们不能得到一个完美的矩形,而是一个“坏形状”,现在就可以使用这个函数来近似这个形状,第二个参数是epsilon,它是从原始轮廓到近似轮廓的最大距离,它是一个准确度参数。

float peri = arcLength(threshCnts[i], true);//周长
//轮廓近似
approxPolyDP(threshCnts[i], contoursPoly[i], 0.02 * peri, true);
rectangle(cur_img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 0, 255), 2);

结果展示

1.直接绘制轮廓效果
image

2.轮廓近似后效果
image

原文地址:https://www.cnblogs.com/hongweijiang/p/14897132.html