Ask Your Question
0

removing noise using connected components

asked 2018-06-26 21:33:53 -0600

Shankar gravatar image

updated 2018-07-08 23:48:26 -0600

Hi all, I am running this in OpenCV 3.x and Python I have an image like this:image description Its an HSV thresholded output of a BGR image. I am trying to crop the roots alone. I have been able to successfully do dilation and erosion, then contour detection on certain images. But on others, while dilating the image, I have a lot of unwanted small white blobs which get dilated along with the other pixels and cause trouble when identifying the contours.

Normal morphological methods like blurring, eroding also destroy my root pixels which render the image useless. So basically I want to selectively target the other specks and fill them black so I can dilate better.

I have also tried connected components on opencv, converted the labels in terms of hue and got this: image description

Here is my code: img = cv2.imread('D:/plants/kevin/hsv.jpg',0) nlabel,labels,stats,centroids = cv2.connectedComponentsWithStats(img,connectivity=8)

    for l in range(1,nlabel):
        if stats[l,cv2.CC_STAT_AREA]<=1000:
            labels_small.append(l)
            areas_small.append(stats[l,cv2.CC_STAT_AREA])

    mask = np.ones_like(labels,dtype=np.uint8)

tstart = time.time()

for l in labels_small:
    mask[labels == l] = 0
    #img[labels == l] = 0


tend = time.time()
print 'time taken:' + str(tend-tstart) + 'secs'


im = Image.fromarray(mask)
im.convert('RGB').save("D:/plantcv2/kevin/cc_mask.jpg")

newHsv = copy.deepcopy(img)
cv2.bitwise_and(newHsv,newHsv,mask=mask)
cv2.imwrite('D:/plants/kevin/hsv_new.jpg',newHsv)

Is it possible to identify the connected components which have the least area and not part of the root and flood fill them black? Let me know what approaches would work. Thanks! :)

edit retag flag offensive close merge delete

Comments

Is it necessary to use connected components? Have you tried median filter? It is good for removing small splotches.

vahni gravatar imagevahni ( 2018-06-27 04:35:32 -0600 )edit

Yes. the problem is median blurring removes some pixels from the plant parts as well, thus making them lose their shape. If I dilate and crop it then, I wont be able to capture the whole root part..

So it is important for me to somehow identify the splotches in the background, but not close to the roots to be removed separately.

Shankar gravatar imageShankar ( 2018-06-27 11:01:15 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2018-06-26 22:26:19 -0600

Tetragramm gravatar image
Mat erase_mask = Mat::zeros(labels.rows, labels.cols, CV_8U);
for(int i = 1; i<num_components; ++i) //Iterate over labels
{
    Mat mask = labels == i; //Keep only the label in question
    int area = findNonZero(mask); //Find the area of the label
    if(area < area_threshold) //Your condition
       bitwise_or(erase_mask, mask, erase_mask); //Save the area to erase
}
labels.setTo(0, erase_mask);  //Actually erase them

Or you can use connectedComponentsWithStats and it will give you an area value. That would be faster, especially if you used the bounding box as an ROI. More complicated though, so I just gave you this.

edit flag offensive delete link more

Comments

Hi, Thanks for the suggestion! I have been indeed trying a similar approach with connectedStats method, but using Python. Sorry, that I didnt mention it before.

Anyway, here is what Im trying, but the mask Image always seems to be just zeros.`

nlabel,labels,stats,centroids = cv2.connectedComponentsWithStats(img,connectivity=8)
mask = np.zeros_like(labels,dtype=np.uint8)

for l in range(1,nlabel):
    if stats[l,cv2.CC_STAT_AREA]<=1000:
        labels_small.append(l)

mask[labels == labels_small] = 255
cv2.imwrite('mask.jpg',mask)

Is my approach right? But the mask is always just zeros.

Shankar gravatar imageShankar ( 2018-06-27 02:58:30 -0600 )edit

No, that doesn't look correct.

You can't do mask[labels == labels_small]

You have to do that for each element of the list labels_small.

Tetragramm gravatar imageTetragramm ( 2018-06-27 17:00:57 -0600 )edit

Okay, So I tried like this:

labX,labY = labels.shape
for i in range(labX):
    print 'X:'+str(i)
    for j in range(labY):
        print 'Y:'+str(j)
        if labels[i,j] in labels_small:
            mask[i,j] = 1

But this is taking very long. Any ways I can simplify this?

Shankar gravatar imageShankar ( 2018-07-02 02:13:39 -0600 )edit

Try iterating over the labels, not the pixel.

for l in labels_small
    mask[labels == l] = 255
Tetragramm gravatar imageTetragramm ( 2018-07-02 17:00:09 -0600 )edit

Hi @Tetragramm, I tried it like you said above. I am still getting plain black images for the mask when I try to save it as an RGB image using Image in PIL and also no changes to the gray image if i do a bitwise and with the mask. I have added my entire code above. Do have a look at it and let me know where am I going wrong. Also, the above operation takes about 400 seconds. Is it because I am running this on Python?

Shankar gravatar imageShankar ( 2018-07-04 02:13:10 -0600 )edit

You seem to be missing something. You create a mask of ones, and then do nothing with it. You never modify mask, or set anything to zero, and so forth.

Is that the correct code?

Tetragramm gravatar imageTetragramm ( 2018-07-05 17:59:49 -0600 )edit

Damn! yes! missed the main part of the code while copying! Fixed it above. pls have a look now! I am setting the values of the mask as zero based on the labels like you said above. Thanks

Shankar gravatar imageShankar ( 2018-07-05 19:07:19 -0600 )edit

Hmm, I don't see any changes to the post. Still no altering of mask.

Tetragramm gravatar imageTetragramm ( 2018-07-08 23:07:54 -0600 )edit

I don't know if I am doing anything wrong, or is there is some problem with the site. I have edited, saved and refreshed it. Looks updated now!

Shankar gravatar imageShankar ( 2018-07-08 23:52:00 -0600 )edit

Two things. First, you also need to set label == 0 to 0. Secondly, you're doing a bitwise_and, not a numpy logical operation. That means you need the value in mask to be 255, not 1.

Tetragramm gravatar imageTetragramm ( 2018-07-10 20:10:20 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-06-26 21:33:53 -0600

Seen: 6,355 times

Last updated: Jul 08 '18