Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV - Getting All Blob Pixels

I have this image:

enter image description here

I've been using the opencv feature SimpleBlobDetector to identify the blobs of white pixels on the black background. Code is below.

blobDetectorParameters = cv2.SimpleBlobDetector_Params()
blobDetectorParameters.filterByArea = True
blobDetectorParameters.minArea = 1
blobDetectorParameters.maxArea = 100
blobDetectorParameters.minDistBetweenBlobs = 1
blobDetectorParameters.filterByCircularity = False
blobDetectorParameters.filterByColor = False
blobDetectorParameters.filterByConvexity = False
blobDetectorParameters.filterByInertia = False

detector = cv2.SimpleBlobDetector_create(blobDetectorParameters)
keypoints = detector.detect(image)
imageWithKeypoints = cv2.drawKeypoints(image, keypoints, numpy.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("Keypoints", imageWithKeypoints)
cv2.waitKey(0)  

Which correctly identifies the blobs as shown in the image below:

enter image description here

The question: I want to be able to have a list of all the blob pixels in order to paint them out. I can't seem to find a way, using the SimpleBlobDetector, to return the pixels of all blobs. I can get the keypoints (returned via detect), but I believe those correspond to the blob centers.

I should also add that I only want to paint blobs of a certain size out, which is why a blanket method of grabbing all the white pixels is not ideal.

Is there any function related to the SimpleBlobDetector (or elsewhere within OpenCV) to return all pixels related to all blobs?

Thank you in advance for your help.

like image 719
Antillies Avatar asked Dec 02 '19 18:12

Antillies


People also ask

What is OpenCV blob?

Blob stands for Binary Large Object and refers to the connected pixel in the binary image. The term "Large" focuses on the object of a specific size, and that other "small" binary objects are usually noise. There are three processes regarding BLOB analysis.

How do you detect an ellipse in OpenCV?

To identify circles, ellipses, or in general, any shape in which the pixels are connected we use the SimpleBlobDetector() function of OpenCV.


1 Answers

You can use np.column_stack + np.where on the binary image to obtain the coordinates of all points. For this example I colored each point green onto a new mask. Here's the result

enter image description here

Here's the (x,y) coordinates of each pixel

[[ 28  32]
 [ 28  33]
 [ 29  33]
 [ 31  25]
 [ 31  26]
 [ 37  43]
 [ 37  44]
 [ 37  45]
 [ 38  43]
 [ 38  44]
 [ 38  45]
 [ 85  96]
 [118 116]
 [118 118]
 [119 116]
 [119 117]
 [120 116]
 [121  87]
 [121 115]
 [122  87]
 [122 115]
 [123  87]
 [123  97]
 [123 115]
 [124  87]
 [124  97]
 [124 115]
 [125  93]
 [125  95]
 [125  96]
 [125 114]
 [125 115]
 [126  94]
 [126  95]
 [126  96]
 [126 113]
 [126 114]
 [127  90]
 [127  94]
 [127  95]
 [127  96]
 [127 112]
 [127 113]
 [128  90]
 [128  91]
 [128  95]
 [128 102]
 [128 103]
 [128 104]
 [128 111]
 [128 112]
 [129 101]
 [129 102]
 [129 103]
 [129 104]
 [130  84]
 [130  85]
 [130 101]
 [130 102]]

Code

import numpy as np 
import cv2

image = cv2.imread('1.png')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

coords = np.column_stack(np.where(thresh > 0))
for coord in coords:
    mask[coord[0], coord[1]] = (36,255,12)

print(coords)
cv2.imshow('mask', mask)
cv2.waitKey()

Update: You can use contour area filtering to achieve your desired result. Specifically, we can use cv2.findContours() to grab the contours of all the blobs then filter using contour area with cv2.contourArea(). If the contour passes some minimum threshold area, then we draw it otherwise we ignore the contour. We can draw the blob with cv2.drawContours(), by passing in -1 for the last parameter, we fill in the contour, otherwise any positive value will draw the outline of the blob. Here's an example:

import numpy as np 
import cv2

image = cv2.imread('1.png')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
threshold_area = 0.5
for c in cnts:
    area = cv2.contourArea(c)
    if area > threshold_area:
        cv2.drawContours(mask, [c], -1, (36,255,12), -1)

cv2.imshow('mask', mask)
cv2.waitKey()
like image 176
nathancy Avatar answered Sep 28 '22 05:09

nathancy