OpenCV-Python 系列 二十一 | 轮廓特征
本文是全系列中第11 / 63篇:OpenCV-Python
- OpenCV-Python 系列 四 | 视频入门
- OpenCV-Python 系列 十二 | 图像的几何变换
- OpenCV-Python 系列 二十 | 轮廓:入门
- OpenCV-Python 系列 二十八 | 直方图4:直方图反投影
- OpenCV-Python 系列 三十六 | 哈里斯角检测
- OpenCV-Python 系列 四十四 | 特征匹配 + 单应性查找对象
- OpenCV-Python 系列 五十二 | 理解K近邻
- OpenCV-Python 系列 六十 | 高动态范围
- OpenCV-Python 系列 五 | OpenCV中的绘图功能
- OpenCV-Python 系列 十三 | 图像阈值
- OpenCV-Python 系列 二十一 | 轮廓特征
- OpenCV-Python 系列 二十九 | 傅里叶变换
- OpenCV-Python 系列 三十七 | Shi-tomas拐角检测器和益于跟踪的特征
- OpenCV-Python 系列 四十五 | 如何使用背景分离方法
- OpenCV-Python 系列 五十三 | 使用OCR手写数据集运行KNN
- OpenCV-Python 系列 六十一 | 级联分类器
- OpenCV-Python 系列 六 | 鼠标作为画笔
- OpenCV-Python 系列 十四 | 图像阈值
- OpenCV-Python 系列 二十二 | 轮廓属性
- OpenCV-Python 系列 三十 | 模板匹配
- OpenCV-Python 系列 三十八 | SIFT尺度不变特征变换
- OpenCV-Python 系列 四十六 | Meanshift和Camshift
- OpenCV-Python 系列 五十四 | 理解SVM
- OpenCV-Python 系列 六十二 | 级联分类器训练
- OpenCV-Python 系列 七 | 轨迹栏作为调色板
- OpenCV-Python 系列 十五 | 图像平滑
- OpenCV-Python 系列 二十三 | 轮廓:更多属性
- OpenCV-Python 系列 三十一 | 霍夫线变换
- OpenCV-Python 系列 三十九 | SURF简介(加速的强大功能)
- OpenCV-Python 系列 四十七 | 光流
- OpenCV-Python 系列 五十五 | 使用OCR手写数据集运行SVM
- OpenCV-Python 系列 六十三 | OpenCV-Python Bindings 如何工作?
- OpenCV-Python 系列 八 | 图像的基本操作
- OpenCV-Python 系列 十六 | 形态学转换
- OpenCV-Python 系列 二十四 | 轮廓分层
- OpenCV-Python 系列 三十二 | 霍夫圈变换
- OpenCV-Python 系列 四十 | 用于角点检测的FAST算法
- OpenCV-Python 系列 四十八 | 相机校准
- OpenCV-Python 系列 五十六 | 理解K-Means聚类
- OpenCV-Python 系列 一 | 系列简介与目录
- OpenCV-Python 系列 九 | 图像上的算术运算
- OpenCV-Python 系列 十七 | 图像梯度
- OpenCV-Python 系列 二十五 | 直方图-1:查找、绘制和分析
- OpenCV-Python 系列 三十三 | 图像分割与Watershed算法
- OpenCV-Python 系列 四十一 | BRIEF(二进制的鲁棒独立基本特征)
- OpenCV-Python 系列 四十九 | 姿态估计
- OpenCV-Python 系列 五十七 | OpenCV中的K-Means聚类
- OpenCV-Python 系列 二 | 安装OpenCV-Python
- OpenCV-Python 系列 十 | 性能衡量和提升技术
- OpenCV-Python 系列 十八 | Canny边缘检测
- OpenCV-Python 系列 二十六 | 直方图-2:直方图均衡
- OpenCV-Python 系列 三十四 | 交互式前景提取使用GrabCut算法
- OpenCV-Python 系列 四十二 | ORB(面向快速和旋转的BRIEF)
- OpenCV-Python 系列 五十 | 对极几何
- OpenCV-Python 系列 五十八 | 图像去噪
- OpenCV-Python 系列 三 | 图像入门
- OpenCV-Python 系列 十一 | 改变颜色空间
- OpenCV-Python 系列 十九 | 图像金字塔
- OpenCV-Python 系列 二十七 | 直方图-3:二维直方图
- OpenCV-Python 系列 三十五 | 理解特征
- OpenCV-Python 系列 四十三 | 特征匹配
- OpenCV-Python 系列 五十一 | 立体图像的深度图
- OpenCV-Python 系列 五十九 | 图像修补
目标
在本文中,我们将学习
– 如何找到轮廓的不同特征,例如面积,周长,质心,边界框等。
– 您将看到大量与轮廓有关的功能。
1. 特征矩
特征矩可以帮助您计算一些特征,例如物体的质心,物体的面积等。请查看特征矩上的维基百科页面。函数cv.moments()提供了所有计算出的矩值的字典。见下文:
import numpy as np
import cv2 as cv
img = cv.imread('star.jpg',0)
ret,thresh = cv.threshold(img,127,255,0)
contours,hierarchy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
print( M )
从这一刻起,您可以提取有用的数据,例如面积,质心等。质心由关系给出,$C_x = frac{M_{10}}{M_{00}}$ 和 $C_y = frac{M_{01}}{M_{00}}$。可以按照以下步骤进行:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
2. 轮廓面积
轮廓区域由函数cv.contourArea()或从矩M['m00']
中给出。
area = cv.contourArea(cnt)
3. 轮廓周长
也称为弧长。可以使用cv.arcLength()函数找到它。第二个参数指定形状是闭合轮廓(True
)还是曲线。
perimeter = cv.arcLength(cnt,True)
4. 轮廓近似
根据我们指定的精度,它可以将轮廓形状近似为顶点数量较少的其他形状。它是Douglas-Peucker算法的实现。检查维基百科页面上的算法和演示。
为了理解这一点,假设您试图在图像中找到一个正方形,但是由于图像中的某些问题,您没有得到一个完美的正方形,而是一个“坏形状”(如下图所示)。现在,您可以使用此功能来近似形状。在这种情况下,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。它是一个精度参数。需要正确选择epsilon才能获得正确的输出。
epsilon = 0.1*cv.arcLength(cnt,True)
approx = cv.approxPolyDP(cnt,epsilon,True)
下面,在第二张图片中,绿线显示了ε=弧长的10%时的近似曲线。第三幅图显示了ε=弧长度的1%时的情况。第三个参数指定曲线是否闭合。
5. 轮廓凸包
凸包外观看起来与轮廓逼近相似,但不相似(在某些情况下两者可能提供相同的结果)。在这里,cv.convexHull()函数检查曲线是否存在凸凹缺陷并对其进行校正。一般而言,凸曲线是始终凸出或至少平坦的曲线。如果在内部凸出,则称为凸度缺陷。例如,检查下面的手的图像。红线显示手的凸包。双向箭头标记显示凸度缺陷,这是凸包与轮廓线之间的局部最大偏差。
关于它的语法,有一些需要讨论:
hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]
参数详细信息:
– 点是我们传递到的轮廓。
– 凸包是输出,通常我们忽略它。
– 顺时针方向:方向标记。如果为True,则输出凸包为顺时针方向。否则,其方向为逆时针方向。
– returnPoints:默认情况下为True。然后返回凸包的坐标。如果为False,则返回与凸包点相对应的轮廓点的索引。
因此,要获得如上图所示的凸包,以下内容就足够了:
hull = cv.convexHull(cnt)
但是,如果要查找凸度缺陷,则需要传递returnPoints = False
。为了理解它,我们将拍摄上面的矩形图像。首先,我发现它的轮廓为cnt
。现在,我发现它的带有returnPoints = True
的凸包,得到以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]]]
,它们是四个角 矩形的点。现在,如果对returnPoints = False
执行相同的操作,则会得到以下结果:[[129],[67],[0],[142]]
。这些是轮廓中相应点的索引。例如,检查第一个值:cnt [129] = [[234,202]]
与第一个结果相同(对于其他结果依此类推)。
当我们讨论凸度缺陷时,您将再次看到它。
6. 检查凸度
cv.isContourConvex()具有检查曲线是否凸出的功能。它只是返回True还是False。没什么大不了的。
k = cv.isContourConvex(cnt)
7. 边界矩形
有两种类型的边界矩形。
7.a.直角矩形
它是一个矩形,不考虑物体的旋转。所以边界矩形的面积不是最小的。它是由函数cv.boundingRect()找到的。
令(x,y)
为矩形的左上角坐标,而(w,h)
为矩形的宽度和高度。
x,y,w,h = cv.boundingRect(cnt)
cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
7.b. 旋转矩形
这里,边界矩形是用最小面积绘制的,所以它也考虑了旋转。使用的函数是cv.minAreaRect()。它返回一个Box2D结构,其中包含以下细节 -(中心(x,y),(宽度,高度),旋转角度)。但要画出这个矩形,我们需要矩形的四个角。它由函数cv.boxPoints()获得
rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img,[box],0,(0,0,255),2)
两个矩形都显示在一张单独的图像中。绿色矩形显示正常的边界矩形。红色矩形是旋转后的矩形。
8. 最小闭合圈
接下来,使用函数**cv.minEnclosingCircle(*()查找对象的圆周。它是一个以最小面积完全覆盖物体的圆。
(x,y),radius = cv.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv.circle(img,center,radius,(0,255,0),2)
9. 拟合一个椭圆
下一个是把一个椭圆拟合到一个物体上。它返回内接椭圆的旋转矩形。
ellipse = cv.fitEllipse(cnt)
cv.ellipse(img,ellipse,(0,255,0),2)
10. 拟合直线
同样,我们可以将一条直线拟合到一组点。下图包含一组白点。我们可以近似一条直线。
rows,cols = img.shape[:2]
[vx,vy,x,y] = cv.fitLine(cnt, cv.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
附加资源
练习
原创文章,作者:磐石,如若转载,请注明出处:https://panchuang.net/2020/03/04/opencv-python-%e7%b3%bb%e5%88%97-%e4%ba%8c%e5%8d%81%e4%b8%80-%e8%bd%ae%e5%bb%93%e7%89%b9%e5%be%81/