I'm trying to clean some chest X-ray data to feed to a CNN. In my dataset are currently many images where the bones are shown in white (higher pixel value than the background), like so:
While others show the bones in a darker color than the background, like this:
Can you show me a way to label the two? I have no other external info about the image, though it can be assumed they are the same size (
Assuming they have the same size (about 1000x2000) and that the first row of pixels has more than 1 different values (i.e. is not a blank border), I've written this simple code to compare a middle-ish pixel to the top-left one (likely to be part of the background).
if img[0,0] > img[500, 500]: # if background lighter than center
img = 255 - img # make the image negative
As you can see even from these samples I posted, this comparison is not always a good indicator (sometimes there is a halo round the background or pixel in [500,500] can be similar to background). Is there some more reliable other way to detect if an image of this kind is negative or not?
Consider that in the dataset are some images with very few details and shading, such as
Following the suggestion from Christoph Rackwitz, I get good result with this approach:
def invert_if_negative(img):
img = my_contrast_stretch(img)
# assuming image has fixed size of (1396, 1676)
# corners
top_left = img[:200, :200].flatten()
top_right = img[:200, 1250:].flatten()
# more or less center
center = img[1000:1300, 500:800].flatten()
threshold = 120 # or computed from average
top_left = top_left > threshold
top_right = top_right > threshold
center = center > threshold
perc_white_corners = (sum(top_left) + sum(top_right)) / (len(top_left) + len(top_right))
perc_white_center = sum(center) / len(center)
if perc_white_corners > perc_white_center:
img = 255 - img
return img
def my_contrast_stretch(img):
if img.dtype == np.float64:
img = (img * 255).astype(np.uint8)
M=np.max(img)
m=np.min(img)
res = img - m
res = res * (255 / (M - m))
return res.astype(np.uint8)