4

I need to find the location of the below tumor in the image as left or right side of the brain.

current image

I tried using contours and Canny edge detection to detect the sides but seems like it is not working

# Find Canny edges 
edged = cv2.Canny(img, 30, 200) 
cv2.waitKey(0) 

# Finding Contours 
# Use a copy of the image e.g. edged.copy() 
# since findContours alters the image 
contours, hierarchy = cv2.findContours(edged,  
    cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 

cv2.imshow('Canny Edges After Contouring', edged) 
cv2.waitKey(0) 

print("Number of Contours found = " + str(len(contours))) 

# Draw all contours 
# -1 signifies drawing all contours 
cv2.drawContours(img, contours, -1, (0, 255, 0), 3) 

2 Answers 2

5

An approach is to perform color segmentation by taking advantage of the observation that the tumor is lighter in color. We begin by first extracting the brain ROI incase the brain is aligned to one side without being in the center of the image. From here convert the image to HSV color space, define a lower and upper color range, and then perform color thresholding with cv2.inRange(). This will give us a binary mask. From here we simply crop the left and right halves of the mask then count the pixels on each side using cv2.countNonZero(). The side that has the higher pixel count will be the side that has the tumor.


Otsu's threshold -> Detected brain ROI -> Extracted ROI

enter image description here enter image description here enter image description here

# Load image, grayscale, Otsu's threshold, and extract ROI
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
x,y,w,h = cv2.boundingRect(thresh)
ROI = image[y:y+h, x:x+w]

Resulting binary mask after color segmentation on extracted ROI

enter image description here

# Color segmentation on ROI
hsv = cv2.cvtColor(ROI, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 152])
upper = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower, upper)

Cropped left and right halves

enter image description here enter image description here

# Crop left and right half of mask
x, y, w, h = 0, 0, image.shape[1]//2, image.shape[0]
left = mask[y:y+h, x:x+w]
right = mask[y:y+h, x+w:x+w+w]

Pixel count on each half

Left pixels: 1252

Right pixels: 12

# Count pixels
left_pixels = cv2.countNonZero(left)
right_pixels = cv2.countNonZero(right)

Since there are more pixels on the left half, the tumor is therefore on the left half of the brain


Full code

import numpy as np
import cv2

# Load image, grayscale, Otsu's threshold, and extract ROI
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
x,y,w,h = cv2.boundingRect(thresh)
ROI = image[y:y+h, x:x+w]

# Color segmentation on ROI
hsv = cv2.cvtColor(ROI, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 152])
upper = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower, upper)

# Crop left and right half of mask
x, y, w, h = 0, 0, ROI.shape[1]//2, ROI.shape[0]
left = mask[y:y+h, x:x+w]
right = mask[y:y+h, x+w:x+w+w]

# Count pixels
left_pixels = cv2.countNonZero(left)
right_pixels = cv2.countNonZero(right)

print('Left pixels:', left_pixels)
print('Right pixels:', right_pixels)

cv2.imshow('mask', mask)
cv2.imshow('thresh', thresh)
cv2.imshow('ROI', ROI)
cv2.imshow('left', left)
cv2.imshow('right', right)
cv2.waitKey()

I used this HSV color thresholder script to determine the lower and upper color ranges

import cv2
import sys
import numpy as np

def nothing(x):
    pass

# Create a window
cv2.namedWindow('image')

# create trackbars for color change
cv2.createTrackbar('HMin','image',0,179,nothing) # Hue is from 0-179 for Opencv
cv2.createTrackbar('SMin','image',0,255,nothing)
cv2.createTrackbar('VMin','image',0,255,nothing)
cv2.createTrackbar('HMax','image',0,179,nothing)
cv2.createTrackbar('SMax','image',0,255,nothing)
cv2.createTrackbar('VMax','image',0,255,nothing)

# Set default value for MAX HSV trackbars.
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)

# Initialize to check if HSV min/max value changes
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

img = cv2.imread('1.jpg')
output = img
waitTime = 33

while(1):

    # get current positions of all trackbars
    hMin = cv2.getTrackbarPos('HMin','image')
    sMin = cv2.getTrackbarPos('SMin','image')
    vMin = cv2.getTrackbarPos('VMin','image')

    hMax = cv2.getTrackbarPos('HMax','image')
    sMax = cv2.getTrackbarPos('SMax','image')
    vMax = cv2.getTrackbarPos('VMax','image')

    # Set minimum and max HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Create HSV Image and threshold into a range.
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    output = cv2.bitwise_and(img,img, mask= mask)

    # Print if there is a change in HSV value
    if( (phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
        print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
        phMin = hMin
        psMin = sMin
        pvMin = vMin
        phMax = hMax
        psMax = sMax
        pvMax = vMax

    # Display output image
    cv2.imshow('image',output)

    # Wait longer to prevent freeze for videos.
    if cv2.waitKey(waitTime) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
Sign up to request clarification or add additional context in comments.

4 Comments

The approach you mentioned is really helpful. Do you think if the brain is aligned to one side without being on the center of jpg image this can work?
@ShaviPathirana check the update, it should now work if the brain is aligned anywhere in the image. It doesn't have to be in the center of the image. The only assumption is that there is only one brain per image
Is there a specific reason to use otsu thresholding than normal thresholding
Yes Otsu's will automatically calculate the threshold value so if the lighting conditions change, it will adapt correctly. You could also try adaptive thresholding. see here
0

canny and findContours is not a good solution for this kind of problem. If you want a simple solution, just use thresholding method. Otsu threshold will give you a good result too.

2 Comments

Beware that as there are three main levels (black background, gray tissue and white tumor, Otsu can pick the wrong threshold.
@YvesDaoust Black background can be ignored by putting non-zero pixels in an array and do Otsu on that array. Besides It's the simplest method not the best. It can be done by more complicated methods like active contour.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.