PythonCV学习记录7——图片的轮廓检测

目录

零之前言

一.轮廓检测

1.简述

2.实现

①参数

②返回值

二.绘制轮廓

1.实现

三.轮廓的特征

1.矩

2.图像的重心

3.轮廓面积

4.轮廓周长

5.近似轮廓

6.凸包

7.边界矩形

①正矩形

②旋转矩形

8.最小外接圆

三.轮廓的性质

1.极点

2.轮廓匹配


零之前言

本节内容,书里的内容可能有些问题,需要额外的查询更多的博客,然后我又放出一位写的比较好的博客:https://blog.csdn.net/hjxu2016/article/details/77833336

一.轮廓检测

1.简述

轮廓检测主要是利用cv2.findContours()这个函数进行检测。且该函数只接受二值化的图片,也就是说只能用黑白的图,而非灰度图。

且很玄学,书上写的是它有三个返回值,而我实际上调用的时候却只有两个返回值。按大佬的说法,如果是三个返回值的话,第一个没用。

2.实现

im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

①参数

先看代码。前三行不必解释灰度处理,二值化。

着重就是对cv2.findContours()的解析了。三个参数:

-thresh:二值化后的图片,他们说用过FindContours后,传入的图片会被修改?我反正观察不明显。

第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
    cv2.RETR_EXTERNAL表示只检测外轮廓
    cv2.RETR_LIST检测的轮廓不建立等级关系
    cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
    cv2.RETR_TREE建立一个等级树结构的轮廓。

第三个参数method为轮廓的近似办法
    cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
    cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
    cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

②返回值

opencv2返回两个值:contours:hierarchy。注:opencv3会返回三个值,分别是img, countours, hierarchy。

-contours是一个 Python列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包含对象边界点(x,y)的坐标。

-hiararchy也是一个Python列表,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。所以可以看出每个轮廓有四个属性。

二.绘制轮廓

绘制轮廓,主要就是用cv2.drawContours()。它没有返回值,它的修改,就是传入函数的图片

1.实现

cv2.drawContours(img, contours,-1, (0,0,255), 3)

里面的参数分别是:

-img 图片。该函数没有返回值,所以会直接修改该img。

-contours 前面返回的轮廓列表

-轮廓索引。对于已知函数的轮廓可以从0开始对应列表的下标…… 或者可以-1可以绘制全部轮廓。

这是一个样例的轮廓代码:

import numpy as np
import cv2
im = cv2.imread('flash.png')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(im, contours, 0, (0,0,255), 3)
print(hierarchy)
cv2.imshow('1',im)
cv2.waitKey(0)

三.轮廓的特征

1.矩

这个矩,好像不是矩形的矩,而是一种特殊的数学含义?反正我是没有学到这个。嗷,百度到了一篇文章https://www.cnblogs.com/ronny/p/3985810.html或者自己百度查找。好难啊,我顶不住了。

通过调用

M = cv2.moments(contours[0])

可以得到矩M

2.图像的重心

公式:      

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

3.轮廓面积

area = cv2.contourArea(contours[0])
#亦或者
area = M['m00']

4.轮廓周长

这个函数的第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。

perimeter = cv2.arcLength(contours[0],True)

5.近似轮廓

将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定。使用的Douglas-Peucker算法,你可以到维基百科获得更多此算法的细节。
为了帮助理解,假设我们要在一幅图像中查找一个矩形,但是由于图像的种种原因,我们不能得到一个完美的矩形,而是一个“坏形状”(如下图所示)。
现在你就可以使用这个函数来近似这个形状()了。这个函数的第二个参数叫epsilon,它是从原始轮廓到近似轮廓的最大距离。它是一个准确度参数。选择一个好的 epsilon 对于得到满意结果非常重要。

epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)

你可以然后通过这样的覆盖contours的操作来画一条新轮廓

import numpy as np
import cv2
im = cv2.imread('flash.png')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
M = cv2.moments(cnt)
area = cv2.contourArea(cnt)
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
contours[0] = approx
cv2.drawContours(im, contours, 0, (0,0,255), 3)
cv2.imshow("1",im)
cv2.waitKey(0)

6.凸包

不想用,要用再百度

7.边界矩形

①正矩形

cnt = contours[0]
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

②旋转矩形

cnt = contours[0]
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(im,[box],0,(0,0,255),2)

8.最小外接圆

cnt = contours[0]
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)

三.轮廓的性质

就是有长宽比,方向等等等。自己看书

说两个我觉得牛逼的

1.极点

leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0]

2.轮廓匹配

import cv2
import numpy as np

img1 = cv2.imread('test.jpg',0)
img2 = cv2.imread('test.jpg',0)

ret, thresh = cv2.threshold(img1, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours[0]

ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print(ret)

这个返回值,越小越好

即使发生了旋转,ret的值的变化也不会太大。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

康娜喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值