在 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的主要内容,如果未能解决你的问题,请参考以下文章
如何转换从文本文件中读取的整数并存储为具有16位整数的二进制文件?