2012-01-29 10 views
11

C'è qualche metodo/funzione nel wrapper python di Opencv che trova aree nere in un'immagine binaria? (come regionprops in Matlab) Fino ad ora ho caricato la mia immagine sorgente, trasformandola in un'immagine binaria tramite soglia e quindi invertendola per evidenziare le aree nere (che ora sono bianche).Python OpenCV - Trova aree nere in un'immagine binaria

non posso usare le librerie di terze parti come cvblobslob o cvblob

+1

+1 per La parola chiave "regionprops" che mi ha salvato ore di googling – Tarrasch

risposta

2

Dopo l'inversione immagine binaria a girare nero per le aree bianche, applicare la funzione cv.FindContours. Ti darà i confini della regione di cui hai bisogno.

In seguito è possibile utilizzare cv.BoundingRect per ottenere un rettangolo di delimitazione minimo attorno alla regione. Una volta ottenuti i vertici del rettangolo, è possibile trovarne il centro ecc.

Oppure per trovare il centroide della regione, utilizzare la funzione c.Moment dopo aver trovato i contorni. Quindi utilizzare cv.GetSpatialMoments in direzione xey. È spiegato nel manuale opencv.

Per trovare l'area, utilizzare la funzione cv.ContourArea.

24

Fondamentalmente, si utilizza la funzione findContours, in combinazione con molte altre funzioni che OpenCV offre in particolare per questo scopo.

Funzioni utili utilizzati (sorpresa, sorpresa, si tutte appaiono sulla pagina Structural Analysis and Shape Descriptors in OpenCV Docs):

codice di esempio (ho tutti gli oggetti di di regionprops tranne WeightedCentroid e EulerNumber Matlab - si potrebbe lavorare fuori EulerNumber utilizzando cv2.RETR_TREE in findContours e guardando la gerarchia risultante e sono sicuro che lo WeightedCentroid non sarebbe poi così difficile.

# 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]   
+0

È utile racchiuderlo in una funzione e restituire una sorta di struttura (ad esempio, numpy recarray) con le informazioni in essa contenute. Mentre ci sono, disegno anche un'immagine etichettata dove la regione 'i' ha intensità' i + 1' (questo per evitare che la regione 0 si fonda con lo sfondo). –

0

trasformarlo in immagine binaria usando soglia con il flag CV_THRESH_BINARY_INV, si ottiene soglia + inversione in un unico passaggio.

0

Se è possibile considerare l'utilizzo di un'altra libreria gratuita, è possibile utilizzare SciPy. Ha un modo molto conveniente di aree conteggio:

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 

Se necessario, è possibile utilizzare:

import cv2 as opencv 

image = opencv.inRange(image, lower_threshold upper_threshold) 

prima per ottenere un'immagine maschera, che contiene solo bianco e nero, dove il bianco sono gli oggetti in l'intervallo specificato.