I want to detect features inside an image (retina scan). The image consists of a retina scan inside a rectangular box with black background.
I am working with Python 3.6, and I am using Canny Edge Detection to detect features inside the image. I understand that the algorithm for canny edge detection uses edge gradients to find edges. While Canny Edge Detection gives me features inside the retina scan for a proper choice of threshold values, it always keeps the circular rim between the retina scan and the black background in the output image.
In the output image, I want to have only the features inside the image (retina scan), and not the outer rim. How can I do this? I am searching for solutions which use Python. I am also open to the use of techniques other than Canny Edge Detection if they help to achieve the required task.
Below is the actual image, and the output image that I get from Canny Edge Detection.
Below is the circular rim that I am talking about (highlighted in red.)
Given below is the expected output image:
My code is given underneath:
import cv2
import matplotlib.pyplot as plt
from matplotlib.pyplot import imread as imread
plt.figure(1)
img_DR = cv2.imread('img.tif',0)
edges_DR = cv2.Canny(img_DR,20,40)
plt.subplot(121),plt.imshow(img_DR)
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges_DR,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
You can find the image used in this code here.
Thanks in advance.
You could fix this in 3 steps:
1) Threshold your input image at a very low intensity, so your retina is the only foreground region. Looking at your image this should work just fine since you have no real black areas in your foreground region:
img = cv2.imread('retina.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,bin = cv2.threshold(gray,5,255,cv2.THRESH_BINARY)
2) Use erosion to remove a small margin from your foreground, you want to remove the part where your outer rim artifacts develop after you apply canny:
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(bin,kernel,iterations = 1)
(visualised in red: the eroded area)
3) Use this eroded image as a binary mask on your current result image. This will remove the outer border while keeping all inner structures intact:
edges_DR = cv2.Canny(img,20,40)
result = cv2.bitwise_and(edges_DR,edges_DR,mask = erosion)
You may have to experiment with the kernel size for the erosion to remove the full border but only the border. But generally, this should produce really good and robust results. Even if the orientation or size of your scan is not consistent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With