赞
踩
目录
在本文中,我们将学习 - 如何找到轮廓的不同特征,例如面积,周长,质心,边界框等。 - 您将看到大量与轮廓有关的功能。
特征矩可以帮助您计算一些特征,例如物体的质心,物体的面积等。请查看特征矩上的维基百科页面。函数 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 )
从这一刻起,您可以提取有用的数据,例如面积,质心等。
质心由关系给出,cx=M10/M00 和 cy=M01/M00。可以按照以下步骤进行,第一个示例为简单的检测单个轮廓,第二个示例能检测图片中的多个轮廓。
- 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 )
-
- cx = int(M['m10']/M['m00'])
- cy = int(M['m01']/M['m00'])
-
- print('轮廓的质心坐标为:(%d,%d) '%cx %cy)
- import cv2
- import numpy as np
-
- # 读取图像
- image = cv2.imread('7.jpg')
-
- # 转换为灰度图像
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
-
- # 应用阈值来获取二值图像
- _, thresholded = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
-
- # 查找轮廓
- contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
-
- # 遍历每个轮廓
- for contour in contours:
- # 计算轮廓的矩
- M = cv2.moments(contour)
-
- # 检查矩是否存在(轮廓不为空)
- if M["m00"] != 0:
- # 计算质心
- cX = int(M["m10"] / M["m00"])
- cY = int(M["m01"] / M["m00"])
-
- # 在图像上绘制质心
- cv2.circle(image, (cX, cY), 5, (255, 0, 0), -1)
- cv2.putText(image, "centroid", (cX - 25, cY - 25), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
-
- # 显示结果图像
- cv2.imshow('Image with Centroids', image)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
轮廓区域由函数 cv.contourArea() 或从矩 M['m00']
中给出。
- 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 )
-
- area = cv.contourArea(cnt)
也称为弧长。可以使用 cv.arcLength() 函数找到它。第二个参数指定形状是闭合轮廓(True
)还是曲线。
- 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 )
-
- perimeter = cv.arcLength(cnt,True)
根据我们指定的精度,它可以将轮廓形状近似为顶点数量较少的其他形状。它是Douglas-Peucker算法的实现。检查维基百科页面上的算法和演示。
为了理解这一点,假设您试图在图像中找到一个正方形,但是由于图像中的某些问题,您没有得到一个完美的正方形,而是一个“坏形状”(如下图所示)。现在,您可以使用此功能来近似形状。在这种情况下,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。它是一个精度参数。需要正确选择epsilon才能获得正确的输出。
- 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 )
-
- epsilon = 0.1*cv.arcLength(cnt,True)
- approx = cv.approxPolyDP(cnt,epsilon,True)
在第二张图片中,绿线显示了ε=弧长的10%时的近似曲线。第三幅图显示了ε=弧长度的1%时的情况。第三个参数指定曲线是否闭合。
凸包外观看起来与轮廓逼近相似,但不相似(在某些情况下两者可能提供相同的结果)。在这里,cv.convexHull()函数检查曲线是否存在凸凹缺陷并对其进行校正。一般而言,凸曲线是始终凸出或至少平坦的曲线。如果在内部凸出,则称为凸度缺陷。例如,检查下面的手的图像。红线显示手的凸包。双向箭头标记显示凸度缺陷,这是凸包与轮廓线之间的局部最大偏差。
- 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 )
-
- 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]]
与第一个结果相同(对于其他结果依此类推)。
有两种类型的边界矩形。
它是一个矩形,不考虑物体的旋转。所以边界矩形的面积不是最小的。它是由函数cv.boundingRect()找到的。
令(x,y)
为矩形的左上角坐标,而(w,h)
为矩形的宽度和高度。
- 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 )
-
-
- x,y,w,h = cv.boundingRect(cnt)
- cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
这里,边界矩形是用最小面积绘制的,所以它也考虑了旋转。使用函数是 cv.minAreaRect()。它返回一个Box2D结构,其中包含以下细节 -(中心(x,y),(宽度,高度),旋转角度)。但要画出这个矩形,我们需要矩形的四个角。它由函数 cv.boxPoints() 获得:
- 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 )
-
-
- rect = cv.minAreaRect(cnt)
- box = cv.boxPoints(rect)
- box = np.int0(box)
- cv.drawContours(img,[box],0,(0,0,255),2)
两个矩形都显示在一张单独的图像中。绿色矩形显示正常的边界矩形。红色矩形是旋转后的矩形。
接下来,使用函数 cv.minEnclosingCircle() 查找对象的圆周。它是一个以最小面积完全覆盖物体的圆。
- 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 )
-
- (x,y),radius = cv.minEnclosingCircle(cnt)
- center = (int(x),int(y))
- radius = int(radius)
- cv.circle(img,center,radius,(0,255,0),2)
下一个是把一个椭圆拟合到一个物体上。它返回内接椭圆的旋转矩形。
- 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 )
-
- ellipse = cv.fitEllipse(cnt)
- cv.ellipse(img,ellipse,(0,255,0),2)
同样,我们可以将一条直线拟合到一组点。下图包含一组白点。我们可以近似一条直线。
- 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 )
-
- 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)
它是对象边界矩形的宽度与高度的比值。
- x,y,w,h = cv.boundingRect(cnt)
- aspect_ratio = float(w)/h
范围是轮廓区域与边界矩形区域的比值。
- area = cv.contourArea(cnt)
- x,y,w,h = cv.boundingRect(cnt)
- rect_area = w*h
- extent = float(area)/rect_area
坚实度是等高线面积与其凸包面积之比。
- area = cv.contourArea(cnt)
- hull = cv.convexHull(cnt)
- hull_area = cv.contourArea(hull)
- solidity = float(area)/hull_area
等效直径是面积与轮廓面积相同的圆的直径。
- area = cv.contourArea(cnt)
- equi_diameter = np.sqrt(4*area/np.pi)
取向是物体指向的角度。以下方法还给出了主轴和副轴的长度。
(x,y),(MA,ma),angle = cv.fitEllipse(cnt)
在某些情况下,我们可能需要构成该对象的所有点。可以按照以下步骤完成:
- mask = np.zeros(imgray.shape,np.uint8)
- cv.drawContours(mask,[cnt],0,255,-1)
- pixelpoints = np.transpose(np.nonzero(mask))
- #pixelpoints = cv.findNonZero(mask)
这里提供了两个方法,一个使用Numpy函数,另一个使用OpenCV函数(最后的注释行)。结果也是一样的,只是略有不同。Numpy给出的坐标是(行、列)
格式,而OpenCV给出的坐标是(x,y)
格式。所以基本上答案是可以互换的。注意,row = x, column = y
。
我们可以使用掩码图像找到这些参数。
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(imgray,mask = mask)
在这里,我们可以找到对象的平均颜色。或者可以是灰度模式下物体的平均强度。我们再次使用相同的掩码进行此操作。
mean_val = cv.mean(im,mask = mask)
极点是指对象的最顶部,最底部,最右侧和最左侧的点。
- 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])
例如,如果我将其应用于印度地图,则会得到以下结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。