Opencv的python包装中有任何方法/函数可以在二进制图像中找到黑色区域吗? (比如Matlab中的 regionprops ) 到目前为止,我加载了我的源图像,通过阈值将其转换为二进制图像,然后反转它以突出显示黑色区域(现在是白色)。
我不能使用第三方库,例如cvblobslob或cvblob
答案 0 :(得分:24)
基本上,您使用findContours
函数,结合OpenCV为此特别提供的许多其他函数。
使用的有用功能(惊喜,惊喜,他们所有出现在OpenCV文档的Structural Analysis and Shape Descriptors页面上):
示例代码(我拥有Matlab的regionprops
除WeightedCentroid
和EulerNumber
之外的所有属性 - 您可以在{{EulerNumber
中使用cv2.RETR_TREE
来计算findContours
1}}并查看结果层次结构,我确信WeightedCentroid
也不会那么难。
# grab contours
cs,_ = cv2.findContours( BW.astype('uint8'), mode=cv2.RETR_LIST,
method=cv2.CHAIN_APPROX_SIMPLE )
# set up the 'FilledImage' bit of regionprops.
filledI = np.zeros(BW.shape[0:2]).astype('uint8')
# set up the 'ConvexImage' bit of regionprops.
convexI = np.zeros(BW.shape[0:2]).astype('uint8')
# for each contour c in cs:
# will demonstrate with cs[0] but you could use a loop.
i=0
c = cs[i]
# calculate some things useful later:
m = cv2.moments(c)
# ** regionprops **
Area = m['m00']
Perimeter = cv2.arcLength(c,True)
# bounding box: x,y,width,height
BoundingBox = cv2.boundingRect(c)
# centroid = m10/m00, m01/m00 (x,y)
Centroid = ( m['m10']/m['m00'],m['m01']/m['m00'] )
# EquivDiameter: diameter of circle with same area as region
EquivDiameter = np.sqrt(4*Area/np.pi)
# Extent: ratio of area of region to area of bounding box
Extent = Area/(BoundingBox[2]*BoundingBox[3])
# FilledImage: draw the region on in white
cv2.drawContours( filledI, cs, i, color=255, thickness=-1 )
# calculate indices of that region..
regionMask = (filledI==255)
# FilledArea: number of pixels filled in FilledImage
FilledArea = np.sum(regionMask)
# PixelIdxList : indices of region.
# (np.array of xvals, np.array of yvals)
PixelIdxList = regionMask.nonzero()
# CONVEX HULL stuff
# convex hull vertices
ConvexHull = cv2.convexHull(c)
ConvexArea = cv2.contourArea(ConvexHull)
# Solidity := Area/ConvexArea
Solidity = Area/ConvexArea
# convexImage -- draw on convexI
cv2.drawContours( convexI, [ConvexHull], -1,
color=255, thickness=-1 )
# ELLIPSE - determine best-fitting ellipse.
centre,axes,angle = cv2.fitEllipse(c)
MAJ = np.argmax(axes) # this is MAJor axis, 1 or 0
MIN = 1-MAJ # 0 or 1, minor axis
# Note: axes length is 2*radius in that dimension
MajorAxisLength = axes[MAJ]
MinorAxisLength = axes[MIN]
Eccentricity = np.sqrt(1-(axes[MIN]/axes[MAJ])**2)
Orientation = angle
EllipseCentre = centre # x,y
# ** if an image is supplied with the BW:
# Max/Min Intensity (only meaningful for a one-channel img..)
MaxIntensity = np.max(img[regionMask])
MinIntensity = np.min(img[regionMask])
# Mean Intensity
MeanIntensity = np.mean(img[regionMask],axis=0)
# pixel values
PixelValues = img[regionMask]
答案 1 :(得分:2)
反转二进制图像以将黑色变为白色区域后,应用cv.FindContours函数。它将为您提供所需区域的边界。
稍后您可以使用cv.BoundingRect获取区域周围的最小边界矩形。获得矩形顶点后,您可以找到它的中心等。
或者要找到区域的质心,找到轮廓后使用cv.Moment函数。然后在x和y方向使用cv.GetSpatialMoments。它在opencv手册中有解释。
要查找区域,请使用cv.ContourArea函数。
答案 2 :(得分:0)
使用带有CV_THRESH_BINARY_INV
标志的阈值将其转换为二进制图像,您只需一步即可获得阈值+反转。
答案 3 :(得分:0)
如果您可以考虑使用其他免费库,则可以使用SciPy
。它有一种非常方便的计算区域的方法:
from scipy import ndimage
def count_labels(self, mask_image):
"""This function returns the count of labels in a mask image."""
label_im, nb_labels = ndimage.label(mask_image)
return nb_labels
如有必要,您可以使用:
import cv2 as opencv
image = opencv.inRange(image, lower_threshold upper_threshold)
之前获取一个仅包含黑色和白色的蒙版图像,其中白色是给定范围内的对象。
答案 4 :(得分:0)
我知道这是一个老问题,但为了完整起见,我想指出 cv2.moments()
并不总是适用于小轮廓。在这种情况下,您可以使用 cv2.minEnclosingCircle()
它将始终返回中心坐标(和半径),即使您只有一个点。不过,我认为需要更多资源......