【问题标题】:Binarize image data二值化图像数据
【发布时间】:2018-08-18 23:43:26
【问题描述】:

我有来自BrainWeb 的 10 次灰度脑部 MRI 扫描。它们存储为 4d numpy 数组brains,形状为(10, 181, 217, 181)。 10 个大脑中的每一个都由沿 z 平面(从头顶到颈部)的 181 个切片组成,其中每个切片在 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 像素强度表示白色(大脑)。

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

normalized_brains = brains/1.7976931348623157e+308

刚刚返回了一个零数组,在二值化步骤中也导致了一个零数组。

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

【问题讨论】:

  • 你的归一化是正确的,最后你得到了一个二进制图像,所以我想这也可以。但我不知道你在这里的意图是什么。对图像进行二值化的方法有数百万种,它们都有不同的目的。您在这里所做的是一种非常糟糕的抖动形式,有更好的方法可以获得以某种方式捕获原始灰度值的二进制图像。但它们的唯一用途是在非常有限的设备上进行视觉输出。那么,你想对二值图像做什么呢?
  • 我之所以想要对数据进行二值化,是因为我想尝试使用类似于here 的卷积变分自动编码器。
  • 将像素建模为二元变量时,模型的重建损失计算更简单

标签: python numpy image-processing computer-vision voxel


【解决方案1】:
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

【讨论】:

    【解决方案2】:

    您将图像转换为二进制图像的方法基本上相当于随机抖动,这是在二进制介质上创建灰度值错觉的糟糕方法。老式打印是一种二元媒体,他们已经微调了几个世纪以来在打印中表示灰度值照片的方法。这个过程被称为halftoning,部分是由纸上墨水的特性决定的,我们不必在二值图像中处理。

    那么人们在印刷之外想出了哪些方法呢?有序抖动(主要是Bayer matrix)和error diffusion dithering。在 Wikipedia 上阅读更多关于抖动的信息。几年前我写了一个blog post showing how to implement all of these methods in MATLAB

    我建议您为您的特定应用程序使用误差扩散抖动。这是 Floyd-Steinberg 算法在 MATLAB 中的一些代码(取自我上面喜欢的博客文章),我希望您可以将其翻译成 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] 范围。

    【讨论】:

      【解决方案3】:

      您是否尝试过对图像设置阈值?

      这是一个common way 用于二值化图像,而不是尝试应用随机二项分布。您可以尝试以下方法:

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

      根据图像值是小于还是大于您选择的阈值返回一个 0 和 1 的数组。

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

      如果这不起作用,您还可以尝试skimage filters 包中提供的阈值选项。

      【讨论】:

      • 阈值是否适用于 OP 的目的尚不清楚,因为 OP 没有指定目的。我建议您在问题明确之前不要回答问题,否则您可能会在问题明确后投反对票。
      • 我想要对数据进行二值化的原因是因为我想尝试使用类似于here 的卷积变分自动编码器。我在原始帖子中没有提到这一点,因为我有兴趣找出对图像数据进行二值化的有效方法
      猜你喜欢
      • 1970-01-01
      • 2018-01-03
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-23
      相关资源
      最近更新 更多