如何使二值图像中的所有背景变白

How can I make all background white in a binary image

在图像中,我希望只有黑色的肺而不是背景。背景 [图像的顶部黑色和底部黑色区域] 必须是白色而不是黑色。我怎样才能在 python 中做到这一点?。从原始灰度图像(“图像”)生成上图的代码是:

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')

假设我们有上面发布的 segmentation 图片,我们想用 while 填充周围的背景。

一个选项是迭代边界,并应用 floodFill 其中像素为黑色:

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()

其他选项是使用 MATLAB imfill(BW,'holes')
用白色填充中心黑色。
在原始图像中,用 while 填充原始图像和填充图像都是黑色的:

import cv2
import numpy as np
from skimage.morphology import reconstruction

def imfill(img):
    # 
    # Use the matlab reference Soille, P., Morphological Image Analysis: Principles and Applications, Springer-Verlag, 1999, pp. 208-209.
    #  6.3.7  Fillhole
    # The holes of a binary image correspond to the set of its regional minima which
    # are  not  connected  to  the image  border.  This  definition  holds  for  grey scale
    # images.  Hence,  filling  the holes of a  grey scale image comes down  to remove
    # all  minima  which  are  not  connected  to  the  image  border, or,  equivalently,
    # impose  the  set  of minima  which  are  connected  to  the  image  border.  The
    # marker image 1m  used  in  the morphological reconstruction by erosion is set
    # to the maximum image value except along its border where the values of the
    # original image are kept:

    seed = np.ones_like(img)*255
    img[ : ,0] = 0
    img[ : ,-1] = 0
    img[ 0 ,:] = 0
    img[ -1 ,:] = 0
    seed[ : ,0] = 0
    seed[ : ,-1] = 0
    seed[ 0 ,:] = 0
    seed[ -1 ,:] = 0

    fill_img = reconstruction(seed, img, method='erosion')

    return fill_img

gray = cv2.imread('segmentation.png', cv2.IMREAD_GRAYSCALE)  # Read image as grayscale

fill_gray = imfill(gray)

# Fill with white where both gray and fill_gray are zeros
gray[(gray == 0) & (fill_gray == 0)] = 255;

cv2.imshow('gray', gray)
cv2.imshow('fill_gray', fill_gray)
cv2.waitKey()
cv2.destroyAllWindows()

我也考虑过使用 findContours 和层次结构来解决它,但它的编码有点多。


输出:

为了去除中心的黑点(如果需要),我们可以使用connectedComponentsWithStats,并根据面积填充小“点”。


编辑:

将上述解决方案与您的代码合并的示例:

#!/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')

使用:ret, gray = cv2.threshold(segmentation.astype(np.uint8), 1, 255, cv2.THRESH_BINARY)
segmentation 中的所有白色像素替换为 255,将所有黑色像素替换为 0