I am working on a project which predicts that the MRI has tumor or not, now the next step is to draw a bounding rectangle around the tumor. I want to extract the tumor from the MRI and bound the tumor inside a rectangle..

For some of the MRI images the I cannot separate the the tumor from MRI, calculated the threshold using OTSU method separately but its not working properly.

Computing threshold:

img = cv.imread(path,0)
blur = cv.GaussianBlur(img,(5,5),0)
# find normalized_histogram, and its cumulative distribution function
hist = cv.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.sum()
Q = hist_norm.cumsum()
bins = np.arange(256)
fn_min = np.inf
thresh = -1
for i in range(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
    q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
    if q1 < 1.e-6 or q2 < 1.e-6:
    b1,b2 = np.hsplit(bins,[i]) # weights
    # finding means and variances
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2
    # calculates the minimization function
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i
# find otsu's threshold value with OpenCV function
ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )

The main code:

import numpy as np
import cv2
import matplotlib.pyplot as plt

def show_image(title, image):
    cv2.imshow(title, image)

def show_image_plt(title, image, cmap = None):

def cvt_image_colorspace(image, colorspace = cv2.COLOR_BGR2GRAY):
    return cv2.cvtColor(image, colorspace)

def median_filtering(image, kernel_size=3):
    :param image: grayscale image
    :param kernel_size: kernel size should be odd number
    :return: blurred image

    return cv2.medianBlur(image, kernel_size)

def apply_threshold(image, **kwargs):
    :param image: image object
    :param kwargs: threshold parameters - dictionary
    threshold_method = kwargs['threshold_method']
    max_value = kwargs['pixel_value']
    threshold_flag = kwargs.get('threshold_flag', None)
    if threshold_flag is not None:
        ret, thresh1 = cv2.adaptiveThreshold(image, max_value, threshold_method,cv2.THRESH_BINARY, kwargs['block_size'], kwargs['const'])
        ret, thresh1 = cv2.threshold(image, kwargs['threshold'], max_value, threshold_method)
    return thresh1

def sobel_filter(img,x,y,kernel_size = 3):
    return cv2.Sobel(img, cv2.CV_8U, x,y, ksize=kernel_size)

#image = cv2.imread(path)
image = cv2.imread(path, 1)
cv2.imwrite("orig.jpg", image)
show_image('Original image', image)

#Step one - grayscale the image
grayscale_img = cvt_image_colorspace(image)
#show_image('Grayscaled image', grayscale_img)

#Step two - filter out image
median_filtered = median_filtering(grayscale_img,5)
#show_image('Median filtered', median_filtered)

#testing threshold function

otsu_image = apply_threshold(median_filtered, **{"threshold" : 93,
                                                 "pixel_value" : 255,
                                                 "threshold_method" : cv2.THRESH_BINARY + cv2.THRESH_OTSU})


th2 = cv2.adaptiveThreshold(median_filtered,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
th3 = cv2.adaptiveThreshold(median_filtered,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
show_image('Image after adaptive thresholding', th2)
show_image('Image after adaptive thresholding 2', th3)


#Step 3a - apply Sobel filter
img_sobelx = sobel_filter(median_filtered, 1, 0)
img_sobely = sobel_filter(median_filtered, 0, 1)

# Adding mask to the image
img_sobel = img_sobelx + img_sobely+grayscale_img
#show_image('Sobel filter applied', img_sobel)

#Step 4 - apply threshold
# Set threshold and maxValue
threshold = 160
maxValue = 255

# Threshold the pixel values
thresh = apply_threshold(img_sobel,  **{"threshold" : 93,
                                                 "pixel_value" : 255,
                                                 "threshold_method" : cv2.THRESH_BINARY})
#show_image("Thresholded", thresh)

#Step 3b - apply erosion + dilation
#apply erosion and dilation to show only the part of the image having more intensity - tumor region
#that we want to extract
erosion = cv2.morphologyEx(median_filtered, cv2.MORPH_ERODE, kernel)
#show_image('Eroded image', erosion)

dilation = cv2.morphologyEx(erosion, cv2.MORPH_DILATE, kernel)
#show_image('Dilatated image', dilation)

# apply thresholding
new_thresholding = apply_threshold(dilation,  **{"threshold" : 93,
                                                 "pixel_value" : 255,
                                                 "threshold_method" : cv2.THRESH_BINARY})
cv2.imwrite("res.jpg", new_thresholding)
show_image('Threshold image after erosion + dilation', new_thresholding)
pts = np.argwhere(new_thresholding>0)
y1,x1 = pts.min(axis=0)
y2,x2 = pts.max(axis=0)
new_thresholding_rect= cv2.rectangle(new_thresholding,(x1,y1),(x2,y2),(255,0,0),2)
show_image('Threshold image after erosion + dilation + Rectangle',new_thresholding_rect)
print (y1,x1)
print (y2,x2)

show_image('Bounded tumor',final_image)

Original MRI Resultant image

  • $\begingroup$ I think this relates to SO more than here. $\endgroup$ – Farhood ET Apr 23 '20 at 5:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.