DICOM图像中如何移除像素标注

5
我正在分析医学图像。所有的图像都有一个带有位置标记的标记。它看起来像这样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

更新2:以下是两个原始的DICOM文件。已删除所有个人信息。编辑:已删除。


那么所有的标记都是不同比例和不同位置的吗? - bjd2385
@bjd2385 是的,它们位于不同的位置并具有不同的大小。标记始终看起来相似,但文本略有不同(例如用于左/右)。 - spore234
你可以分享原始的DICOM图像吗? - Mark Setchell
@MarkSetchell 我添加了一个原始的 DICOM 文件。 - spore234
6个回答

5

看一下您提供的图像的实际像素值,您会发现标记几乎是(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

当然,如果样本图像不具有代表性,您可能需要更加努力。让我们看看这个...
如果简单阈值对您的图像无效,我会尝试使用“命中与失误形态学”技术。基本上,您将图像阈值设置为纯黑和白 - 大约在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 完成。
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 剪裁所有多余的黑色图像,只留下白色的点,并告诉我们边界框:

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

enter image description here

如果您想让脚本自动完成这个任务,我建议使用以下代码,并将其保存为 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

好的,我已经添加了一个脚本。 - Mark Setchell
可以运行了,太好了!顺便问一下,如何高效地将一个包含dcm图像的文件夹转换为png格式?当我执行convert *.dcm *.png时,我的内存会被填满,最终导致系统崩溃。通常我会在我们的服务器上进行操作,因为那里有足够的内存,但肯定有更好的方法。 - spore234
如果您没有使用我的脚本,请执行 magick mogrify -format png *dcm - Mark Setchell
1
或者使用homebrew安装GNU Parallel,然后使用parallel convert {} {}.png ::: *.dcm命令并行执行全部转换任务。 - Mark Setchell
1
如果您正在使用我的脚本,则可以使用以下命令:parallel ./HideMarker {} {.}.png ::: *dcm - Mark Setchell
显示剩余5条评论

2
我有另一个想法。这个解决方案使用Python中的OpenCV。这是一个相当的解决方案。
  1. 首先,获取图像的二进制阈值。
  2. ret,th = cv2.threshold(img,2,255,0) enter image description here

  3. 执行形态学膨胀:

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

  1. 为了连接间隙,我接着使用了中值滤波:

median = cv2.medianBlur(dilate, 9) enter image description here

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

它也适用于第二张图片:

enter image description here


非常好,谢谢。但是有一些图像中标记与组织重叠。在那里它无效。 - spore234
@spore234 哦,我不知道那个。你会如何处理这些情况?你有没有考虑分析这些图像的FFT频谱?也许如果所有图像的相位谱存在相关性,它们就可以被去除,这样当我们执行逆FFT时,只剩下组织部分。 - Jeru Luke
我接受的解决方案在这个区域放置了一个黑色正方形,与组织部分重叠。 对于它发生的少数情况来说,这是可以的。 我猜你的解决方案会将整个图像变黑。 - spore234

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

如果这些内容确实被烧入图像数据中,您可能需要使用这里的其他建议。

我认为它已经烧录了。我在描述中添加了一个原始的Dicom文件。 - spore234

0

好消息是,这些水印可能在一个完全黑色的隔离区域中,这使得去除它们更容易(尽管是否按照指示使用许可证仍然值得商榷)。

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

基本思路

  • 检测半十字形边界(4个)
  • 从这些计算定义的矩形
  • 将此矩形涂黑

步骤

0

二值化

1

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

2

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

3

  • 进行一些连通组件计算,以获取一些垂直和水平线的对象

  • 现在,您可以尝试不同的候选组件(8个真实组件),并具有以下知识:

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

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

这是基本方法。

替代方案

这种方法需要更少的工作量,使用更专业的工具,并假定开头的事实:

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

步骤

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

备选方案2

仅草图:想法是在图像上以某种方式使用binary-closing来构建完全连接的组件,从源像素中提取出医学数据和水印,同时填充小的间隙/孔洞,以便我们得到描述医学数据的一个大组件和一个水印组件。然后只需删除较小的组件即可。


0
我确定这可以进行优化,但是...您可以创建4个大小为3x3或4x4的补丁,并使用注释文本周围框架中每个单独角落的像素值的确切内容来初始化它们。然后,您可以迭代整个图像(或具有仅在黑区域中查找的一些智能初始化),并找到这些补丁的精确匹配。在组织中,很不可能出现相同的正常结构(由近0环绕的90度角),因此这可能会为您提供边界框。

这是一个不错的开始,但不要忘记多尺寸问题。 - Master DJon

-1

还有更简单的方法!!!

只需在 (img_array = img.pixel_array) 后实现以下内容:

img_array[img_array > X] = Y

X 是您想要消除的强度阈值。Y 是您想要考虑代替它的强度值。

例如: img_array[img_array > 4000] = 0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接