In the image I would like to have only the lungs in black not the background. The background [Top black and bottom black area of the image] must be white not black. How can I do that in python?. Code that resuls in the image above from an original grayscale image ("image") is:
from skimage.filters import sobel
img = cv2.GaussianBlur(image, (5, 5), 0)
img = cv2.erode(img, None, iterations=2)
img = cv2.dilate(img, None, iterations=2)
elevation_map = sobel(img)
markers = np.zeros_like(image)
markers[image < 70] = 1
markers[image > 254] = 2
segmentation = skimage.morphology.watershed(elevation_map, markers)
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(segmentation, cmap=plt.cm.gray, interpolation='nearest')
ax.axis('off')
ax.set_title('segmentation')
CodePudding user response:
Assuming we have the segmentation
image as posted above, and we want to fill the surrounding background with while.
One option is iterating the borders, and apply floodFill
where pixel is black:
import cv2
import numpy as np
gray = cv2.imread('segmentation.png', cv2.IMREAD_GRAYSCALE) # Read image as grayscale
for x in range(gray.shape[1]):
# Fill dark top pixels:
if gray[0, x] == 0:
cv2.floodFill(gray, None, seedPoint=(x, 0), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
# Fill dark bottom pixels:
if gray[-1, x] == 0:
cv2.floodFill(gray, None, seedPoint=(x, gray.shape[0]-1), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
for y in range(gray.shape[0]):
# Fill dark left side pixels:
if gray[y, 0] == 0:
cv2.floodFill(gray, None, seedPoint=(0, y), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
# Fill dark right side pixels:
if gray[y, -1] == 0:
cv2.floodFill(gray, None, seedPoint=(gray.shape[1]-1, y), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
cv2.imshow('gray', gray)
cv2.waitKey()
cv2.destroyAllWindows()
Other option is use something as
For removing the black spot in the center (if needed), we may use connectedComponentsWithStats
, and fill the small "spot" according to the area.
Edit:
Example for incorporating the above solution with your code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import skimage.io
import skimage.color
import skimage.filters
from skimage.io import imread
from skimage.color import rgb2gray
from skimage.filters import sobel
import cv2
from skimage import data
image = cv2.imread('/content/drive/MyDrive/Covid_data/Training Set/covid/covid/ct_scan_100/22.jpg')
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax.axis('off')
ax.set_title('Original Image')
# Image in grayscale
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Blurring the image [img]
img = cv2.GaussianBlur(image, (5, 5), 0)
img = cv2.erode(img, None, iterations=2)
img = cv2.dilate(img, None, iterations=2)
#img = image
elevation_map = sobel(img)
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(elevation_map, cmap=plt.cm.gray, interpolation='nearest')
ax.axis('off')
ax.set_title('elevation_map')
# we find markers of the background and the coins based on the extreme parts of the histogram of grey values
markers = np.zeros_like(image)
# Choosing extreme parts of the histogram of grey values
markers[image < 70] = 1
markers[image > 254] = 2
#we use the watershed transform to fill regions of the elevation map starting from the markers determined above:
segmentation = skimage.morphology.watershed(elevation_map, markers)
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(segmentation, cmap=plt.cm.gray, interpolation='nearest')
ax.axis('off')
ax.set_title('segmentation')
#gray = cv2.imread('segmentation.png', cv2.IMREAD_GRAYSCALE) # Read image as grayscale
# Convert segmentation to uint8 image, where 255 is white and 0 is black (OpenCV style mask).
ret, gray = ret, gray = cv2.threshold(segmentation.astype(np.uint8), 1, 255, cv2.THRESH_BINARY)
for x in range(gray.shape[1]):
# Fill dark top pixels:
if gray[0, x] == 0:
cv2.floodFill(gray, None, seedPoint=(x, 0), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
# Fill dark bottom pixels:
if gray[-1, x] == 0:
cv2.floodFill(gray, None, seedPoint=(x, gray.shape[0]-1), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
for y in range(gray.shape[0]):
# Fill dark left side pixels:
if gray[y, 0] == 0:
cv2.floodFill(gray, None, seedPoint=(0, y), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
# Fill dark right side pixels:
if gray[y, -1] == 0:
cv2.floodFill(gray, None, seedPoint=(gray.shape[1]-1, y), newVal=255, loDiff=3, upDiff=3) # Fill the background with white color
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(gray, cmap=plt.cm.gray, interpolation='nearest')
ax.axis('off')
ax.set_title('gray')
Using: ret, gray = cv2.threshold(segmentation.astype(np.uint8), 1, 255, cv2.THRESH_BINARY)
Replaces all the white pixels in segmentation
with 255
and all the black pixels with 0
.