Python OpenCV - 在二值图像中查找黑色区域

14 投票
5 回答
28703 浏览
提问于 2025-04-17 11:54

在Python的OpenCV库中,有没有什么方法或者函数可以找到二值图像中的黑色区域?(就像Matlab中的regionprops一样)

到目前为止,我是先加载我的源图像,然后通过阈值处理把它变成二值图像,再把颜色反转,这样黑色区域就变成了白色区域。

我不能使用像cvblobslob或者cvblob这样的第三方库。

5 个回答

0

使用阈值和 CV_THRESH_BINARY_INV 这个标志,可以把图像转换成二进制图像,这样就能一步完成阈值处理和反转操作。

2

在把二进制图像的黑色区域变成白色之后,可以使用cv.FindContours函数。这个函数会告诉你需要的区域的边界。

接下来,你可以用cv.BoundingRect来获取这个区域的最小包围矩形。一旦你得到了这个矩形的四个角点,就可以找到它的中心点等等。

如果想要找到区域的重心,可以在找到轮廓后使用cv.Moment函数。然后在x和y方向上使用cv.GetSpatialMoments。这个在opencv的手册里有详细说明。

要计算区域的面积,可以使用cv.ContourArea函数。

25

基本上,你可以使用findContours这个函数,结合OpenCV提供的其他很多函数,来完成这个任务。

这里有一些有用的函数(没想到吧,它们出现在OpenCV文档的结构分析和形状描述符页面上):

示例代码(我有来自Matlab的regionprops的所有属性,除了WeightedCentroidEulerNumber - 你可以通过在findContours中使用cv2.RETR_TREE来计算EulerNumber,并查看结果的层次结构,我相信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]        

撰写回答