OpenCV 图像轮廓

Posted 小白白AI学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV 图像轮廓相关的知识,希望对你有一定的参考价值。

上一节最后,我们说过这一次我们将会讲解真正的OpenCV图像轮廓有关知识。轮廓发现的具体实现有多种方式,不过其的使用在OpenCV中的使用并不困难,不过想用好还需要多点基础知识。这里我们会首先讲一讲OpenCV中的轮廓发现算法,然后再讲一讲其他可以用于轮廓发现的特殊方法。这里我们主要使用了两种来自于OpenCV官方的图片,第一张是彩色快乐鱼,第二张是水果分尸图不对,应该是果缤纷才对。\(^o^)/~

OpenCV(三) 图像轮廓


OpenCV(三) 图像轮廓
轮廓发现算法


OpenCV中的轮廓发现算法来自于1985的一篇论文《TopologicalStructural Analysis of Digitized Binary Images by Border Following》,这篇论文主要讲了两种可有效利用于轮廓发现的边界跟踪算法,其中第一种是区分二值图像边界之间的保卫关系(surroundness relations)第二种是第一种算法的变形,只跟踪最外层轮廓。对于具体内容这里不再过多描述,你可以自行查阅。至于具体的使用,我们直接使用OpenCV中的函数findContours即可。


由于OpenCV中的轮廓发现借鉴于论文《 Analysis of Digitized Binary Images by Border Following》,所以其只能接受二值化之后的图像,也就是说我们需要先对原始图像进行二值化处理,这里需要使用函数cvtColor将图片进行类型转化,具体代码如下:


# 灰度图像gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化ret, binary = cv2.threshold(gray, 175, 255, cv2.THRESH_BINARY)


其中COLOR_BGR2GRAY的作用一如其名,就是将BGR图像转化为GRAY(灰度图,又名遗照)


OpenCV(三) 图像轮廓

OpenCV(三) 图像轮廓

之后我们就可以使用 cv2.threshold方法进行二值化处理,就这样一条彩色的快乐鱼就变成了一张黑白的快乐鱼遗照了。其中要注意的是,阈值是由我们自己选定的(这里是175),我们也可以通过修改阈值来获取新的二值化参数。


OpenCV(三) 图像轮廓

OpenCV(三) 图像轮廓

最终,我们就可以将二值化之后的图像传进轮廓发现算法,进行轮廓发现并绘制。代码与结果如下:


# 轮廓发现contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 轮廓绘制cv2.drawContours(img, contours_new, -1, (0, 0, 255), 3)



OpenCV(三) 图像轮廓


现在快乐鱼就被惨遭“分尸”了,嘴巴上多了一条大口子。而说回正事,上面的代码中drawContours函数就是绘制函数,第一个参数是需要绘制的原图像,第二个参数是之前我们使用算法发现的轮廓,第三个参数则表示绘制的轮廓索引,这里使用-1表示绘制所有轮廓,第四个参数则是绘制轮廓时线条的颜色,这里我们选择红色0。第五个参数则表示线条粗细度,如果是负值则在轮廓内部绘制。除此之外还有一个隐身的六娃lineType表示线条类型,因为有默认数值LINE_8,所以这里没有设置。


不过除了这些基本的操作外,我们还可以有很多其他的操作,比如借助之前我们学过的滤波函数对图像进行处理,去除那些意义不大的小色块,或者使用边缘检测算法如Canny先一步获取图形边缘(代替直接二值化哪一步),然后再进行轮廓发现,这些操作避免发现错误轮廓,同时我们也可以使用判断方法选择一定周长或者面积的轮廓。前者直接使用`cv.blur(src_gray, (3,3))`,以及函数`canny_output = cv.Canny(gray, threshold, threshold * 2)`即可,后者则需要几个opencv的函数进行配合,具体代码如下:

# Detect edges using Cannythreshold = 100# Detect edges using Cannycanny_output = cv2.Canny(gray, threshold, threshold * 2)
for i in range(len(contours)): # 计算轮廓所包含的面积 area = cv2.contourArea(contours[i]) # 计算轮廓的周长 perimeter = cv2.arcLength(contours[i], True)  if perimeter >= 10 and area >= 20: print("第{0}个轮廓的面积为{1},周长为{2}".format(i+1,area,perimeter))        contours_new.append(contours[i])



OpenCV(三) 图像轮廓
OpenCV(三) 图像轮廓






第一段代码的作用是使用Canny进行边缘检测(展示的图片也经过了均值模糊),然后得到一张只有边缘数据的图,这样就避免了之前直接二值化产生的像素阈值产生的本来不存在的误差,而第二行代码则是利用计算轮廓面积和计算轮廓周长的函数进行轮廓筛选。其实这里我们也可以选择不进行筛选直接进行获取,但是在一般情况下均值模糊,边缘检测,周长,面积等都是十分有用的操作,至于怎么用则需要根据实际情况进行调整。


OpenCV(三) 图像轮廓
边缘检测
OpenCV(三) 图像轮廓

这里还提到了边缘检测,边缘检测顾名思义就是检测图片的边缘。在一些特殊情况下其实边缘检测比直接轮廓获取有用,不过也有些时候图像分割的一些技术更有用一些。这几项技术的特点都是作用于图像中的区域对其进行处理。只不过在没有深度学习的时代,没有像目标检测,或者现代的更直接的自动进行图像分割的技术,只能使用各类算法进行手动操作,从不同的图片中手动设置不同的方法获取我们想要的信息。


Canny就是一种比较常见的边缘检测方法,下面就是一个例子。我们将会在下一节仔细的讲讲的边缘检测等有关图像处理技术。


OpenCV(三) 图像轮廓
OpenCV(三) 图像轮廓




OpenCV(三) 图像轮廓
写在最后

往期OpenCV链接如下:






OpenCV(三) 图像轮廓
END
OpenCV(三) 图像轮廓
OpenCV(三) 图像轮廓
小白白AI学习
-扫码关注我们-
点击在看,了解更多精彩内容



以上是关于OpenCV 图像轮廓的主要内容,如果未能解决你的问题,请参考以下文章

youcans 的 OpenCV 例程200篇194.寻找图像轮廓(cv.findContours)

youcans 的 OpenCV 例程200篇195.绘制图像轮廓(cv.drawContours)

求C++中利用opencv计算轮廓图像傅里叶描述子的代码

图像轮廓检测错误:OpenCV、C++

基于 OpenCV 实战:对象跟踪

(有代码有案例)vs2019 opencv 找到图像最大轮廓用GrabCut算法进行图像分割