Python OpenCV - Найти черные области в двоичном изображении - PullRequest
14 голосов
/ 30 января 2012

Есть ли какой-нибудь метод / функция в оболочке Python Opencv, который находит черные области в двоичном изображении? (например, regionprops в Matlab) До сих пор я загружаю исходное изображение, преобразую его в двоичное изображение через порог и затем инвертирую, чтобы выделить черные области (которые теперь белые).

Я не могу использовать сторонние библиотеки, такие как cvblobslob или cvblob

Ответы [ 4 ]

24 голосов
/ 30 января 2012

Обычно вы используете функцию findContours в сочетании со многими другими функциями, которые OpenCV предоставляет для этой цели.

Используемые полезные функции (удивление, удивление, они все появляются на странице Структурный анализ и дескрипторы форм в Документах OpenCV):

пример кода (у меня есть все свойства из Matlab regionprops, за исключением WeightedCentroid и EulerNumber - вы можете работать EulerNumber, используя cv2.RETR_TREE в findContours и глядя на результирующая иерархия, и я уверен, что 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]        
2 голосов
/ 30 января 2012

После инвертирования двоичного изображения, чтобы превратить черное в белое, примените функцию cv.FindContours.Это даст вам границы области, в которой вы нуждаетесь.

Позже вы можете использовать cv.BoundingRect, чтобы получить минимальный ограничивающий прямоугольник вокруг области.Как только вы получили вершины прямоугольника, вы можете найти его центр и т. Д.

Или, чтобы найти центроид области, используйте функцию cv.Moment после нахождения контуров.Затем используйте cv.GetSpatialMoments в направлении x и y.Это объясняется в руководстве opencv.

Чтобы найти область, используйте функцию cv.ContourArea.

0 голосов
/ 10 января 2016

Если вы можете рассмотреть возможность использования другой бесплатной библиотеки, вы можете использовать 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)

, прежде чем получить изображение маски, которое содержит только черно-белое изображение, где белоеобъекты в заданном диапазоне.

0 голосов
/ 03 апреля 2013

Преобразуйте его в двоичное изображение, используя порог с флагом CV_THRESH_BINARY_INV, и вы получите порог + инверсию за один шаг.

...