【问题标题】:remove pixel annotations in dicom image删除 dicom 图像中的像素注释
【发布时间】:2017-06-02 13:05:15
【问题描述】:

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

在这张图片中是“TRH RMLO”注解,但在其他图片中可能不同。大小也不同。图像被裁剪,但您看到组织从右侧开始。 我发现这些标记的存在扭曲了我的分析。

如何删除它们?

我像这样在 python 中加载图像

import dicom
import numpy as np

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

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

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

更新

添加了第二张图片

更新2: 这是两个原始的 dicom 文件。所有个人信息已被删除。编辑:删除

【问题讨论】:

  • 所以所有的标记都是不同的比例,不同的地方?
  • @bjd2385 是的,它们的位置不同,大小也不同。标记总是看起来相似,但文本略有不同(例如左/右)
  • 你能分享原始的DICOM图像吗?
  • @MarkSetchell 我添加了一个原始的 dicom 文件。

标签: python image numpy image-processing dicom


【解决方案1】:

好消息是,这些水印可能是一个孤立的全黑区域,这使得它更容易(尽管根据指示的用法删除它是有问题的;许可证的东西)。

如果不是专家,这里有一个想法。它可能是针对此问题量身定制的一些非常强大的方法的草图,但您必须确定实现复杂性和算法复杂性(非常依赖于图像统计)是否值得:

基本思路

  • 检测半交叉状边界 (4)
  • 根据这些计算定义的矩形
  • 将此矩形涂黑

步骤

0

二值化

1

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

2

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

3

  • 做一些连通分量计算得到一些垂直和水平线的对象

  • 现在你可以通过以下知识尝试不同的候选组件(8个真实组件)的选择

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

4 - 从这些边界计算矩形 - 将其扩大几个像素(超参数) - 涂黑那个矩形

这是基本方法。

另类

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

  • 要删除的内容位于图像的某个完全黑色的部分
  • 有点孤立;与医疗数据的距离很远

步骤

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

备选方案 2

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

【讨论】:

    【解决方案2】:

    如果这些注释在 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 );
    

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

    【讨论】:

    • 我认为它被烧录了。我在描述中添加了一个原始 dicom 文件。
    【解决方案3】:

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

    【讨论】:

    • 这是一个愚蠢的开始,但不要忘记多尺寸问题。
    【解决方案4】:

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

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

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

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

    当然,如果示例图片不具有代表性,您可能需要更加努力。让我们看看……

    如果简单阈值不适用于您的图像,我会查看“Hit and Miss Morphology”。基本上,您将图像阈值设置为纯黑白 - 大约 90%,然后您寻找特定的形状,例如标签上的角标记。所以,如果我们想在黑色背景上寻找一个白色矩形的左上角,我们用0表示“这个像素必须是黑色的”,1表示“这个像素必须是白色的” 和- 表示“我们不在乎”,我们会使用这种模式:

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

    希望您可以在那里看到一个白色矩形的左上角。在终端中会是这样的:

    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
    

    现在我们还想寻找右上角、左下角和右下角,所以我们需要旋转图案,ImageMagick 在添加&gt; 标志时很方便:

    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
    

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

    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"
    

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

    chmod +x HideMarker
    

    然后像这样运行它:

    ./HideMarker someImage.dcm  result.png
    

    【讨论】:

    • 这听起来是个好主意,因为我已经使用 imagemagick 将图像从 dcm 转换为 png。那么对于确实泛化到不同图像大小和不同位置的转换命令行的解决方案是什么?我将在我的 dcm 文件的一小部分样本上进行测试以进行检查。
    • 好的,我已经添加了一个脚本。
    • 不幸的是,这对于很多图像来说已经失败了。可能是因为这些图片中有更多的纯白色区域。我在上面的描述中添加了一个失败的 dicom
    • 或使用 homebrew 来安装 GNU Parallel 然后与parallel convert {} {}.png ::: *.dcm 并行执行
    • 或者,如果你使用我的脚本,parallel ./HideMarker {} {.}.png ::: *dcm
    【解决方案5】:

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

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

      ret,th = cv2.threshold(img,2,255, 0)

    2. 执行形态扩张:

    dilate = cv2.morphologyEx(th, cv2.MORPH_DILATE, kernel, 3)

    1. 为了加入差距,我使用了中值过滤:

    median = cv2.medianBlur(dilate, 9)

    现在您可以使用轮廓属性来消除最小轮廓并保留包含图像的其他轮廓。

    它也适用于第二张图片:

    【讨论】:

    • 非常好,谢谢。但是,有一些图像标记与组织重叠。它在那里不起作用。
    • @spore234 哦,我不知道。在这些情况下你将如何处理?您是否考虑过分析这些图像的 FFT 频谱?也许如果所有图像的相位谱都存在相关性,它们可以被剔除,这样当我们执行逆 FFT 时,我们只剩下组织部分。
    • 我接受的解决方案是在这个与组织部分重叠的区域上放置一个黑色方块。对于发生这种情况的少数情况,这是可以的。我猜你的解决方案会使整个图像变黑。
    【解决方案6】:

    更简单的仍然是可能的!!!。

    只需在 (img_array = img.pixel_array) 之后执行以下操作

    img_array[img_array > X] = Y

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

    例如: img_array[img_array > 4000] = 0

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多