二值化图像数据

Binarize image data

我有 10 个来自 BrainWeb 的灰度大脑 MRI 扫描。它们存储为 4d numpy 数组 brains,形状为 (10, 181, 217, 181)。 10 个大脑中的每一个都由 181 个沿 z 平面(从头顶到颈部)的切片组成,其中每个切片在 x(耳朵到耳朵)和 y(眼睛到眼睛)中的大小为 181 x 217 像素后脑勺)飞机分别。

所有的大脑都是dtype('float64')型。所有大脑的最大像素强度为 ~1328,最小为 ~0。例如,对于第一个大脑,我通过 brains[0].max() 给出 1328.338086605072brains[0].min() 给出 0.0003886114541273855 来计算。下面是 brain[0]:

的切片图

我想通过将像素强度从 [0, 1328] 重新调整为 {0, 1} 来对所有这些大脑图像进行二值化。 我的方法正确吗?

我首先将像素强度标准化为 [0, 1]

normalized_brains = brains/1328 

然后使用二项分布对每个像素进行二值化:

binarized_brains = np.random.binomial(1, (normalized_brains))

绘制的结果看起来正确:

0 像素强度代表黑色(背景),1 像素强度代表白色(大脑)。

我通过实施另一种方法对来自 的图像进行标准化进行了实验,但它只给了我一张黑色图像。这是因为np.finfo(np.float64)1.7976931348623157e+308,所以归一化步骤

normalized_brains = brains/1.7976931348623157e+308

刚刚返回了一个零数组,它在二值化步骤中也产生了一个零数组。

我是否使用正确的方法对图像进行二值化处理?

你试过图像上的阈值吗?

这是 common way 对图像进行二值化,而不是尝试应用随机二项分布。你可以尝试这样的事情:

binarized_brains = (brains > threshold_value).astype(int)

其中 returns 一个 0 和 1 的数组,根据图像值是小于还是大于您选择的阈值。

您必须尝试使用​​阈值来找到最适合您图像的阈值,但不需要先对其进行归一化。

如果效果不佳,您还可以尝试使用 skimage filters 包中提供的阈值选项。

您将图像转换为二进制图像的方法基本上相当于随机抖动,这是在二进制介质上创建灰度值幻觉的糟糕方法。 Old-fashioned 印刷品是一种二元媒体,他们有 fine-tuned 方法来表示 grey-value 几个世纪以来印刷的照片。这个过程称为 halftoning,部分由纸上墨水的特性决定,我们不必在二值图像中处理。

那么人们想出了哪些非印刷方法?有序抖动(主要是 Bayer matrix), and error diffusion dithering. Read more about dithering on Wikipedia. I wrote a blog post showing how to implement all of these methods in MATLAB 几年前。

我建议您为您的特定应用程序使用误差扩散抖动。这是 Floyd-Steinberg 算法在 MATLAB 中的一些代码(取自我的博客 post 喜欢上面),我希望你能把它翻译成 Python:

img = imread('https://i.stack.imgur.com/d5E9i.png');
img = img(:,:,1);

out = double(img);
sz = size(out);
for ii=1:sz(1)
   for jj=1:sz(2)
      old = out(ii,jj);
      %new = 255*(old >= 128); % Original Floyd-Steinberg
      new = 255*(old >= 128+(rand-0.5)*100); % Simple improvement
      out(ii,jj) = new;
      err = new-old;
         if jj<sz(2)
            % right
            out(ii  ,jj+1) = out(ii  ,jj+1)-err*(7/16);
         end
      if ii<sz(1)
         if jj<sz(2)
            % right-down
            out(ii+1,jj+1) = out(ii+1,jj+1)-err*(1/16);
         end
            % down
            out(ii+1,jj  ) = out(ii+1,jj  )-err*(5/16);
         if jj>1
            % left-down
            out(ii+1,jj-1) = out(ii+1,jj-1)-err*(3/16);
         end
      end
   end
end

imshow(out)

在应用抖动之前对图像重新采样大大改善了结果:

img = imresize(img,4);
% (repeat code above)
imshow(out)

注意 上述过程期望输入在 [0,255] 范围内。很容易适应不同的范围,比如 [0,1328] 或 [0,1],但也很容易将图像缩放到 [0,255] 范围。

IT is easy in OpenCV. as mentioned a very common way is defining a threshold, But your result looks like you are allocating random values to your intensities instead of thresholding it. 

import cv2
im = cv2.imread('brain.png', cv2.CV_LOAD_IMAGE_GRAYSCALE)
(th, brain_bw) = cv2.threshold(imy, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
th = (DEFINE HERE)
im_bin = cv2.threshold(im, th, 255, cv
cv2.imwrite('binBrain.png', brain_bw)

brain

binBrain