发现你的身形——OpenCV图像轮廓

文章目录

    • 写在最前
    • 轮廓发现算法
    • 边缘检测
    • 写在最后

写在最前

我的意思不是说你长得很胖,emmmm,而是你的轮廓很大。
——五星上将詹姆斯下士如是说

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

发现你的身形——OpenCV图像轮廓_第2张图片

轮廓发现算法

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图像轮廓_第3张图片

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

发现你的身形——OpenCV图像轮廓_第4张图片

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

# 轮廓发现
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 轮廓绘制
cv2.drawContours(img, contours_new, -1, (0, 0, 255), 3)

发现你的身形——OpenCV图像轮廓_第5张图片

现在快乐鱼就被惨遭“分尸”了,嘴巴上多了一条大口子。而说回正事,上面的代码中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 Canny
threshold = 100
# Detect edges using Canny
canny_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图像轮廓_第6张图片

发现你的身形——OpenCV图像轮廓_第7张图片

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

均值模糊,边缘检测,周长,面积等都是十分有用的操作,至于怎么用则需要根据实际情况进行调整。

边缘检测

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

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

发现你的身形——OpenCV图像轮廓_第8张图片
发现你的身形——OpenCV图像轮廓_第9张图片

写在最后

大概写到这个时候感觉确实可以出个专栏了,所以正式规划了《漫谈计算机视觉》,频率大概会一周一更,大概会从OpenCV将其,然后一直串到这两年各个计算机视觉领域比较经典深度神经网络。同时代码会开源,之后代码和有关数据前往FontTian的Github下载即可,包括之前的内容都会穿上去,项目位置在这:https://github.com/FontTian/Gossipage_About_CV。

你可能感兴趣的:(漫谈计算机视觉,【机器学习】OpenCV,python,人工智能,计算机视觉,opencv,图像轮廓)