I am trying to preprocess a photo of the eye vessels by removing the black border and extraneous non-eye features in the image (Ex. see below for text and "clip") by replacing the black areas with the average pixel values from 3 random squares.
crop1 = randomCrop(image2, 50, 50) #Function that finds random 50x50 area
crop2 = randomCrop(image2, 50, 50)
crop3 = randomCrop(image2, 50, 50)
mean1 = RGB_Mean(crop1)
mean2 = RGB_Mean(crop2)
mean3 = RGB_Mean(crop3)
#RGB Mean
result = [statistics.mean(k) for k in zip(mean1, mean2, mean3)]
for i in range(len(image2[:,0, 0])):
for j in range(len(image2[0,:,0])):
thru_pixel = image2[i, j]
if (thru_pixel[0] < 50 and thru_pixel[1] < 50 and thru_pixel[2] < 50):
image2[i,j, :] = result
if (thru_pixel[0] > 190 and thru_pixel[1] > 190 and thru_pixel[2] > 190):
image2[i,j, :] = result
However, there is leftover noise around the border of the image, as well as leftover text and a clip at the bottom left.
Here's an example image.
Original :
and Post-Processing
You can see there's still left over black-gray border noise as well as text at the bottom right and a "clip" at the bottom left. Is there anything I could try to get rid of any of these artifacts while maintaining the integrity of the eye blood vessels?
Thank you for your time and help!
Assuming you want to isolate the eye blood vessels, here's an approach which can be broken down into two stages, one to remove the artifacts and another to isolate blood vessels
Beginning from your original image, we convert to grayscale and Otsu's threshold to obtain a binary image
Now we perform morph open to remove the artifacts (left). We inverse this mask to obtain the white border and then do a series of bitwise operations to get the removed artifacts image (right)
From here we adaptive threshold to get the veins
Note there is the unwanted border so we find contours and filter using a maximum threshold area. If a contour passes the filter, we draw it onto a blank mask
Finally we perform bitwise-and on the original image to get our result
Note we could have performed additional morph open after the adaptive threshold to remove the small particles of noise but the tradeoff is that it will remove vein details. I'll leave this optional step up to you
import cv2
import numpy as np
# Grayscale, Otsu's threshold, opening
image = cv2.imread('1.png')
blank_mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,15))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)
inverse = 255 - opening
inverse = cv2.merge([inverse,inverse,inverse])
removed_artifacts = cv2.bitwise_and(image,image,mask=opening)
removed_artifacts = cv2.bitwise_or(removed_artifacts, inverse)
# Isolate blood vessels
veins_gray = cv2.cvtColor(removed_artifacts, cv2.COLOR_BGR2GRAY)
adaptive = cv2.adaptiveThreshold(veins_gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,3)
cnts = cv2.findContours(adaptive, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 5000:
cv2.drawContours(blank_mask, [c], -1, (255,255,255), 1)
blank_mask = cv2.cvtColor(blank_mask, cv2.COLOR_BGR2GRAY)
final = cv2.bitwise_and(image, image, mask=blank_mask)
# final[blank_mask==0] = (255,255,255) # White version
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('removed_artifacts', removed_artifacts)
cv2.imshow('adaptive', adaptive)
cv2.imshow('blank_mask', blank_mask)
cv2.imshow('final', final)
cv2.waitKey()