Opencv学习(三)轮廓检测
什么是轮廓检测
轮廓检测就是在一张只有0和1的图片上绘制一系列的点,这些点就是图像中的曲线。函数findContours()就是从二值图像中寻找轮廓,在这个函数中,输入图像可以是从Canny()函数得到的有边缘像素的图像,或者是通过threshold()、adaptiveThreshold()处理后得到的图像。
比如下面这张0-9的原始图片
经过轮廓检测后得到的图片
如何进行轮廓检测
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\template.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.读取的原始图像
2.灰度图
3.二值图
4.绘制检测的轮廓
如果我想把每个数字用一个矩形框而不是绘制它的边框,该怎么解决?-----轮廓近似
什么是轮廓近似
将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定
比如在上面的几个数字中,我想把边界用矩形框住,此时就需要使用到轮廓近似
如何进行轮廓近似
假设我们要在一幅图像中查找一个矩形,但是由于图像的种种原因我们不能得到一个完美的矩形,而是一个“坏形状”,现在就可以使用这个函数来近似这个形状,第二个参数是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.直接绘制轮廓效果
2.轮廓近似后效果