在 C++ 中读取 DICOM 并转换为 OpenCV

Posted

技术标签:

【中文标题】在 C++ 中读取 DICOM 并转换为 OpenCV【英文标题】:Read DICOM in C++ and convert to OpenCV 【发布时间】:2016-04-02 22:53:57 【问题描述】:

我想用 C++ 读取 DICOM 图像并使用 opencv 操作它们。

我设法使用 DCMTK 读取 dicom 图像,但是我不确定如何将其转换为 opencv Mat。

以下是我目前所拥有的:

DicomImage DCM_image("test.dcm");
cv::Mat image(int(DCM_image.getWidth()), int(DCM_image.getHeight()), CV_8U, (uchar*)DCM_image.getOutputData(8));

结果如下:

在 DICOM 查看器中,如下所示:

归一化后,变灰的图像如下:

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

我现在可以看到的主要问题是像素值范围(深度)的差异。

AFAIK,DICOM 可以有相当大的深度(16 位),而您正试图适应只有 8 位的 CV_8U。您可以使用DicomImage::getDepth() 获取DicomImage 实例的深度,然后创建一个具有适当深度的cv::Mat 来保存您的图像数据。

您可能还需要对数据进行规范化以最大限度地利用您的可用范围,以使带有cv::imshow() 的显示看起来符合预期。

所以:

在您的 DCM_image 上执行 DicomImage::getDepth() 创建一个具有足够深度的cv::Mat 来保存您的数据 缩放,如有必要

【讨论】:

我会试一试的。另外,规范化应该在将数据传输到opencv之前还是之后进行?如果之前,这是否也可以使用 getOutputData 来完成?谢谢 我认为如果选择适当的深度,没有任何区别。此外,根据我的经验,一些 DICOM 查看器有异常的标准化,这会导致数据超出范围(屏幕截图上的结构看起来完全是白色的,就像曝光过度一样)。因此,也许您希望以不同的方式规范化您的数据。 我正在创建 cv::mat 如下:cv::Mat test(int(DCM_image.getHeight()), int(DCM_image.getWidth()), CV_MAKETYPE(DCM_image.getDepth(), 1), (long*)DCM_image.getOutputData()); 但是输出仍然没有任何好处。知道为什么吗? 我检查了位深度,它是 17(在我看来这是一个奇怪的数字)。这次输出完全错误,甚至结构都不存在 那么我会避免使用 CV_MAKETYPE,并坚持使用 int of float 作为 Mat 的类型。但我不确定数据在 DCM_image 中的布局方式。我认为你最好参考 DCMTK 手册来找出 stride、padding 等,而不是试图猜测。【参考方案2】:

在对单色 DICOM 图像调用 DicomImage::getOutputData() 之前,应确保已选择适当的 VOI 转换(例如窗口中心和宽度)。这可以通过 DicomImage::setMinMaxWindow()、DicomImage::setWindow() 等来完成。请参阅DicomImage 类的文档。

但请注意,DicomImage::getOutputData() 始终返回渲染的像素数据,即不是存储在 DICOM 数据集中的原始像素数据。

【讨论】:

【参考方案3】:

U 需要读取 DICOM 图像编码中的数据类型并将其转换为 opencv 类型 Mat。 opencv 文档提供了有关其 Mat 标头的全部信息。

【讨论】:

更改了问题以向您展示我到目前为止所拥有的以及结果如何。谢谢 在您的 CV mat header 中,需要交换宽度和高度。结果与原版有多么不同。 你是对的。不过我更关心强度。我将发布一张图片,向您展示它在 DICOM 阅读器上的显示方式。

以上是关于在 C++ 中读取 DICOM 并转换为 OpenCV的主要内容,如果未能解决你的问题,请参考以下文章

C ++读取二进制文件并转换为十六进制

python 读取dicom tag 结果为空值

如何转换从文本文件中读取的整数并存储为具有16位整数的二进制文件?

Dicom Toolkit (DCMTK) - 如何获取窗口中心和宽度

如何在matlab中读取一组三维dicom图片

将十六进制转换为从文件 C++ 读取的 ASCII 的正确方法