删除dicom图像中的像素注释

时间:2017-01-18 08:32:06

标签: python image numpy image-processing dicom

我正在分析医学图像。所有图像都有一个带位置的标记。看起来像这样 enter image description here

此图像中的“TRH RMLO”注释,但在其他图像中可能有所不同。尺寸也各不相同。图像被裁剪,但您看到组织正在右侧开始。 我发现这些标记的存在会扭曲我的分析。

如何删除它们?

我像这样加载python中的图像

import dicom
import numpy as np

img = dicom.read_file(my_image.dcm)
img_array = img.pixel_array

然后图像是一个numpy数组。白色文本总是被大的黑色区域包围(黑色值为零)。标记在每个图像中处于不同的位置。

如何在不伤害组织数据的情况下删除白色文本。

更新

添加了第二张图片

enter image description here

UPDATE2 : 这是两个原始的dicom文件。所有个人信息均已删除。编辑:已删除

7 个答案:

答案 0 :(得分:4)

查看您提供的图像的实际像素值,您可以看到标记几乎是(99.99%)纯白色,这不会出现在图像的其他位置,因此您可以使用简单的99.99%阈值将其隔离

我更喜欢命令行中的 ImageMagick ,所以我会这样做:

convert sample.dcm -threshold 99.99% -negate mask.png

enter image description here

convert sample.dcm mask.png -compose darken -composite result.jpg

enter image description here

当然,如果样本图像不具代表性,您可能需要更加努力。我们来看看......

如果简单阈值对您的图像不起作用,我会查看“Hit and Miss Morphology”。基本上,您将图像阈值设置为纯黑色和白色 - 大约90%说,然后您查找特定形状,例如标签上的角标记。因此,如果我们想在黑色背景上查找白色矩形的左上角,我们使用0表示“此像素必须为黑色”,{{1表示“此像素必须为白色”1表示“我们不关心”,我们将使用此模式:

-

希望你能在那里看到一个白色矩形的左上角。在终端中就是这样:

0 0 0 0 0
0 1 1 1 1
0 1 - - -
0 1 - - -
0 1 - - -

现在我们还想查找右上角,左下角和右下角,因此我们需要旋转模式,当您添加{{1}时, ImageMagick 可以轻松完成标志:

convert sample.dcm -threshold 90% \
  -morphology HMT '5x5:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' result.png

enter image description here

希望您现在可以看到划分徽标角落的点,因此我们可以要求 ImageMagick 修剪所有无关黑色的图像,然后留下白点然后告诉我们边界框:

>

所以,如果我现在在这些坐标周围画一个红色框,你可以看到标签被检测到的位置 - 当然在实践中我会画一个黑盒子来覆盖它,但我在解释这个想法:

convert sample.dcm -threshold 90% \
   -morphology HMT '5x5>:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' result.png

enter image description here

如果您希望脚本自动执行此操作,我会使用类似的内容,将其保存为cconvert sample.dcm -threshold 90% \ -morphology HMT '5x5>:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' -format %@ info: 308x198+1822+427

convert sample.dcm -fill "rgba(255,0,0,0.5)" -draw "rectangle 1822,427 2130,625" result.png

然后你会这样做以使其可执行:

HideMarker

然后像这样运行:

#!/bin/bash
input="$1"
output="$2"

# Find corners of overlaid marker using Hit and Miss Morphology, then get crop box
IFS="x+" read w h x1 y1 < <(convert "$input" -threshold 90% -morphology HMT '5x5>:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' -format %@ info:)

# Calculate bottom-right corner from top-left and dimensions
((x1=x1-1))
((y1=y1-1))
((x2=x1+w+1))
((y2=y1+h+1))
convert "$input" -fill black -draw "rectangle $x1,$y1 $x2,$y2" "$output"

答案 1 :(得分:1)

如果这些注释位于DICOM文件中,则可以通过几种方式存储它们(请参阅https://stackoverflow.com/a/4857782/1901261)。只需从文件中删除60xx组属性即可清除当前支持的方法。

对于已弃用的方法(仍然常用),您可以手动清除未使用的高位注释,而不会弄乱其他图像数据。类似的东西:

int position = object.getInt( Tag.OverlayBitPosition, 0 );
if( position == 0 ) return;

int bit = 1 << position;
int[] pixels = object.getInts( Tag.PixelData );
int count = 0;
for( int pix : pixels )
{
   int overlay = pix & bit;
   pixels[ count++ ] = pix - overlay;
}
object.putInts( Tag.PixelData, VR.OW, pixels );

如果这些确实被刻录到图像数据中,您可能会在此处使用其他建议之一。

答案 2 :(得分:1)

我有另一个想法。这个解决方案是使用python在OpenCV中。这是一个相当的解决方案。

  1. 首先,获取图像的二进制阈值。

    ret,th = cv2.threshold(img,2,255, 0) enter image description here

  2. 进行形态膨胀:

  3. dilate = cv2.morphologyEx(th, cv2.MORPH_DILATE, kernel, 3) enter image description here

    1. 为了加入差距,我使用了中值过滤:
    2. median = cv2.medianBlur(dilate, 9) enter image description here

      现在,您可以使用轮廓属性消除最小轮廓并保留包含图像的另一个轮廓。

      它也适用于第二张图片:

      enter image description here

答案 3 :(得分:0)

好处是,这些水印可能是完全黑色的,这使得它更容易(尽管如果根据指定的用途删除它是有疑问的;许可证的东西)。

没有专家,这里有一个想法。它可能是针对这个问题量身定制的一种非常强大的方法的草图,但你必须决定实现的复杂性和安全性。算法复杂度(非常依赖于图像统计)是值得的:

基本理念

  • 像边框一样检测半十字(4)
  • 从这些
  • 计算定义的矩形
  • 遮挡此矩形

步骤

0

二值化

1

  • 使用一些基于渐变的边缘检测器来获取所有水平边
  • 可能有多个;您可以尝试给出最小长度(可能需要一些形态来连接基于源或算法中的噪声而未连接的像素)

2

  • 使用一些基于渐变的边缘检测器来获取所有水平边
  • 与上述相似,但方向不同

3

  • 进行一些连通分量计算以获得一些垂直和水平线的对象

  • 现在您可以尝试使用以下知识的不同候选组件(8个实际组件)

    • 这些组件中的两个可以用相同的线描述(斜率截距形式;线性回归问题) - &gt;与矩形接壤的线
    • 可能最好的4对选择(根据线性回归损失)是这个矩形的有效边界
    • 您可以添加假设,即垂直边框和水平边框彼此正交

4 - 从这些边框计算矩形 - 加宽几个像素(超参数) - 遮挡那个矩形

这是基本方法。

替代

这个工作要少得多,使用更专业的工具并在开幕式中假设事实:

  • 要移除的东西是在图像的一些完全黑色的部分
  • 它的孤立;与医疗数据的距离很高

步骤

  • 运行一些常规OCR以检测字符
  • 以某种方式获取占用的像素/边框(我不确定OCR工具会返回什么)
  • 计算一些外部矩形和遮光(使用一些预定义的扩大间隙;这个需要比上面的大得多)

备选方案2

仅限草图:我的想法是在图像上以某种方式使用类似binary-closing的东西来构建源像素的完全连接组件(同时填充小间隙/孔),这样我们就得到了一个大组件描述医学数据,一个描述水印。然后删除较小的一个。

答案 4 :(得分:0)

  
    

标记位于每张图像的不同位置。

  

我的假设:

  1. 标记始终是文本。
  2. 标记不在组织内
  3. =&GT;建议:

    1. 使用OCR查找位置(例如,使用Tesseract在本地查找,或使用OCR.space等在线API)。您将获得以JSON返回的单词的边界框:

                  "TextOverlay" : {
                      "Lines" : [
                          {
                              "Words": [
                                  {
                                  "WordText": "RMLO",
                                  "Left": 106,
                                  "Top": 91,
                                  "Height": 9,
                                  "Width": 11
                                  },
      
    2. 现在你有了坐标,你可以将矩形遮挡。

    3. 此解决方案符合Sascha的第二个选项。

答案 5 :(得分:0)

我确信这可以进行优化,但是......你可以创建4个大小为3x3或4x4的补丁,并使用注释文本周围框架的每个角落的像素值的确切内容对它们进行初始化。然后,您可以遍历整个图像(或者仅在黑色区域中进行一些智能初始化)并找到这些修补程序的完全匹配。在组织中你不太可能有相同的规则结构(90度角被0附近包围),所以这可能会给你一个边界框。

答案 6 :(得分:0)

更简单的一个仍然可能!!!。

在(img_array = img.pixel_array)

之后实现以下内容

img_array [img_array&gt; X] = Y

其中X是您希望在此之后消除的强度阈值。 Y也是您要考虑的强度值而不是。

例如: img_array [img_array&gt; 4000] = 0

用黑色强度0替换大于4000的白质。