Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to leave only the largest blob in an image?

I have a binary image of a brain. I only want to leave the blob in the center and remove the surrounding "noise" that is in this circular looking shape.

Here's an example image:

brain mr

I tried using OpenCV and getting countours, but that failed miserably. I also don't need a bounding rectangle box, at all, I just want to leave the center blob in the image, as it looks in the image I provided, and remove the surrounding noise/circle. Is this possible?

like image 598
BorkoP Avatar asked Jun 13 '19 23:06

BorkoP


2 Answers

I assume, you want to keep the actual brain ("blob in the center") and get rid of the skull ("noise circular looking shape").

Unfortunately, you didn't show any code, so I'm not sure, what failed for you in using contours, but here's my suggestion:

import cv2
import numpy as np

# Read input
img = cv2.imread('images/t6igVVk.png', cv2.IMREAD_GRAYSCALE)

# Generate intermediate image; use morphological closing to keep parts of the brain together
inter = cv2.morphologyEx(img, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))

# Find largest contour in intermediate image
cnts, _ = cv2.findContours(inter, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnt = max(cnts, key=cv2.contourArea)

# Output
out = np.zeros(img.shape, np.uint8)
cv2.drawContours(out, [cnt], -1, 255, cv2.FILLED)
out = cv2.bitwise_and(img, out)

cv2.imshow('img', img)
cv2.imshow('inter', inter)
cv2.imshow('out', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

The final output out.png looks like this:

Output

I do some morphological closing (morphologyEx, getStructuringElement) on the input image to keep the actual parts of the brain together. On that intermediate image, I look for the largest contour. In my findContours call, I use theRETR_EXTERNAL mode to only get all "external contours". That means, when later drawing this contour, it'll be also filled in the middle (i.e. the lateral ventricles). So, finally I just use a bitwise_and on both images to fix that. That also fixes the too large parts from the intermediate image as well.

Hope that helps!

like image 173
HansHirse Avatar answered Nov 10 '22 10:11

HansHirse


By using cv2.morphologyEx I was loosing a lot of details from my binary image. I am using the following code to just keep the largest white area of an image -

import skimage
from skimage import measure

labels_mask = measure.label(input_mask)                       
regions = measure.regionprops(labels_mask)
regions.sort(key=lambda x: x.area, reverse=True)
if len(regions) > 1:
    for rg in regions[1:]:
        labels_mask[rg.coords[:,0], rg.coords[:,1]] = 0
labels_mask[labels_mask!=0] = 1
mask = labels_mask

Input image:

enter image description here

Output image:

enter image description here

like image 41
Malgo Avatar answered Nov 10 '22 11:11

Malgo