[DICOM活久见] 序列内部的RescaleIntercept不同导致的问题

news2024/9/20 20:23:55

本文由Markdown语法编辑器编辑完成.

1. 背景:

本文记录在工作中遇到的一些比较罕见的dicom图像.
这对于在未来工作中, 处理图像时, 需要考虑方案的完整性, 会有很大的帮助.

本文介绍的, 是目前我工作10年来, 头一次见到的一个CT序列, 它的序列内的RescaleIntercept值, 不是完全相同的. 这会导致如果在生成体数据时, 如果按照第一层的RescaleIntercept的值, 来作为整个体数据的RescaleIntercept时, 会引起很大偏差的问题.

2. 问题描述:

在医学图像处理中, 我们通用会将一个序列内的所有dicom图像, 生成一个包含该序列内所有影像像素信息的体数据. 这样无论对于后期的读取, 计算, 都可以基于这个体数据来进行.

生成体数据, 主要是基于simpleITK提供的方法来进行, 大致逻辑如下:

def get_sitk_image_from_series(series_dataset_list: list):
    """
    根据series内每一张图像的信息, 得到包含一个序列内所有图像信息的np array.
    Args:
        series_dataset_list (str): 根据ImagePositionPatient的z值递增排序后的数组.
    """
    bottom_dicom = series_dataset_list[0]
    try:
        image_count = len(series_dataset_list)
        rows, cols = bottom_dicom.get("Rows"), bottom_dicom.get("Columns")
        rescale_intercept, rescale_slope = None, None
        if not bottom_dicom.get("RescaleIntercept") or not bottom_dicom.get("RescaleSlope"):
            rescale_intercept = 0.0
            rescale_slope = 1.0
        else:
            rescale_intercept, rescale_slope = bottom_dicom.get("RescaleIntercept"), bottom_dicom.get("RescaleSlope")
        series_array = np.zeros((image_count, rows, cols), dtype=np.int16)
        slice_location_list = list()
        for index, img_dataset in enumerate(series_dataset_list):
            img_pixel_array = img_dataset.pixel_array * rescale_slope + rescale_intercept
            slice_location_list.append(img_dataset.get("ImagePositionPatient")[-1])
            series_array[index] = img_pixel_array

        # origin direcation spacing
        top_dicom = series_dataset_list[-1]
        direction = cal_direction_with_orientation(bottom_dicom.get("ImageOrientationPatient", [1, 0, 0, 0, 1, 0]))
        sitk_img = sitk.GetImageFromArray(series_array)
        sitk_img.SetDirection(direction)
        sitk_img.SetOrigin(bottom_dicom.get("ImagePositionPatient"))
        z_spacing = (top_dicom.get("ImagePositionPatient")[-1] - bottom_dicom.get("ImagePositionPatient")[-1]) / (
            len(series_dataset_list) - 1
        )
        pixel_spacing = list(copy.deepcopy(img_dataset.get("PixelSpacing")))
        pixel_spacing.append(z_spacing)
        sitk_img.SetSpacing(pixel_spacing)
    except Exception:
        return None
    return sitk_img

def cal_direction_with_orientation(orientation):
    row_direction = np.array(orientation[:3])
    column_direction = np.array(orientation[3:])
    slice_direction = np.cross(row_direction, column_direction)
    row_direction /= np.linalg.norm(row_direction)
    column_direction /= np.linalg.norm(column_direction)
    slice_direction /= np.linalg.norm(slice_direction)
    return list(row_direction) + list(column_direction) + list(slice_direction)

这一段逻辑, 主要是将将一个序列内读入的, image_dataset的list, 构建出一个sitkImg, 然后再将sitkImg, 转存成为一个.mha, .niig.gz等体数据的文件.
这样就实现了, 将一系列二维的图像, 生成一个三维的体数据文件, 便于后续的读取和操作.

那么如何再将.mha的体数据, 还原为原始的dicom文件呢?
主要就是从.mha中, 读取出特定层数的像素信息, 然后再加上之前的dicom header信息, 就可以组合为一张一张dicom图像.
因为有时候, 也是需要读取单张dicom图像的.

那么现在问题来了. 在处理一套病例数据时, 发现经过这样的处理后, 返回的dicom文件, 出现了白图的情况. 但是如果只是查看.mha文件, 又是正常的.

那么究竟是哪里出了问题呢?

2.1 问题表现

通过从浏览器,可以查看到,通过.mha和dicom header,组合后生成的dicom图像.
在这里插入图片描述
在这里插入图片描述

第一幅图像,是经过还原后的异常图像.图像出现了很严重的反白现象;而第二幅图像,则是原始的dicom图像,非常正常.

那么我们再看一下,通过原始的dicom图像,生成的.mha是否正常.将生成的.mha文件,拖入slicer中,可以看到:![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2aee6e0732c946dfa9aa6bf86234cdb0.png

从slicer中看,体数据也是"没问题"的.
至少从大体上看,它是能够看到各个部位的轮廓的.

为了对比,我再把原始序列的dicoms文件,也加载到slicer里面看一下.
在这里插入图片描述

但是仔细观察,slicer加载: .mha和原始dicom后,图像的亮度是有差异的.
那么,观察左侧的图像的灰度范围,可以看出两者的差异:

图像类型灰度下限灰度上限
.mha-38969772
原始dicom-39869811

可以看出,两者之间的差异,主要体现在了灰度的最大值不同,差了大概40多.虽然不是很多,但是也是有差异的.
按理来说,这里的.mha文件,是原始的dicom文件,在仅保留像素的情况下,生成的.所以,生成的.mha文件,和原始的dicoms文件,加载到slicer里面,应该是完全一致,灰度的范围也是要完全一致,才可以的.

那么,现在的问题,就是需要定位,这相差的40的灰度值,是如何引起的.

2.2 问题定位:

通过查看生成.mha体数据的逻辑.
生成.mha文件前,需要先基于读取的dicoms的灰度信息,构建出一个sitk的Image, 然后将这个Image, 写成一个.mha文件.
那么问题的关键,就是构建这个sitk Image的逻辑了.

图像原始的灰度信息,是存在了:
pixel_array中.而构建sitk Image时,需要将pixel_array中的灰度,经过RescaleSlope和RescaleIntercept的调节,生成HU值.
计算的方式为:
HU = pixel_array * RescaleSlope + RescaleIntercept

对于CT图像来说,一般是两类型的值.而这个值的取值,又依赖于PixelRepresentation的值.

PixelRepresentationRescaleSlopeRescaleIntercept
11.00
01.0-1024

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2103360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu解压7z压缩包方法

0 Preface/Foreword 1 解压缩指令 1.1 环境安装和检查 环境:检测ubuntu环境是否装有7z工具,如果没有,需要手动安装,安装方法如下: sudo apt-update sudo apt-get install p7zip-full 检测工具是否安装成功&#xff…

qmt量化交易策略小白学习笔记第56期【qmt编程之期权数据--获取历史期权列表--原生Python】

qmt编程之获取期权数据 qmt更加详细的教程方法,会持续慢慢梳理。 也可找寻博主的历史文章,搜索关键词查看解决方案 ! 获取历史期权列表 函数能帮助用户获取历史期权列表, 包括某日历史在上交所上市的认购合约和认沽合约, 也包括已经退市的…

PTA单词首字母大写

作者 颜晖 单位 浙大城市学院 本题目要求编写程序,输入一行字符,将每个单词的首字母改为大写后输出。所谓“单词”是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个。 输入格式: 输入给出一行字符。 输出格式…

Css:属性选择器、关系选择器及伪元素

css的属性选择器&#xff1a; 注&#xff1a;属性值只能由数字&#xff0c;字母&#xff0c;下划线&#xff0c;中划线组成&#xff0c;并且不能以数字开头。 1、[属性] 选择含有指定属性的元素&#xff0c;用[]中括号表示。 <style> /*注意大小写区分 注意前后顺序 样…

电脑技巧:如何在Win11电脑上调整设置,让屏幕更加护眼?

目录 一、调整屏幕亮度 二、启用夜间模式 三、调整色彩设置 四、使用第三方护眼软件 五、保持良好的用眼习惯 总结 随着长时间使用电脑的人越来越多,护眼问题也变得越来越重要。Win11作为更新的操作系统,提供了更多的设置选项来帮助我们保护眼睛。本文将详细介绍如何在…

针对实验试服务器的使用问题【安装anaconda+Vscode连接+jupyther远程连接】

目录 一、Xshell连接 1-创建连接 2-安装anaconda 3-创建conda环境 4-修改下载镜像源 5-安装torch 二、VScoda连接服务器 1-下载插件Remote-ssh 用于远程连接服务器 2-配置文件 三、jupyther远程连接 四、师兄推荐的入门资料 1-python基础 2-机器学习 五、参考资料…

网络安全:键盘记录器

目录 什么是键盘记录器&#xff1f; 键盘记录器的类型 键盘记录器的工作原理 键盘记录器的有害影响 如何防止键盘记录器攻击&#xff1f; 在网络攻击的世界中&#xff0c;存在着许多形式的威胁&#xff0c;如前所述。 在本章中&#xff0c;我们将讨论网络攻击中的主要恶意…

基于mediamtx+ffmpeg实现视频推流,基于python-deffcode实现视频拉流

软件依赖&#xff1a;mediamtx、ffmpeg python包依赖&#xff1a;deffcode mediamtx下载地址&#xff1a;https://github.com/bluenviron/mediamtx/releases ffmeg下载地址&#xff1a;https://ffmpeg.org/download.html deffcode安装命令&#xff1a;pip install deffcode 1、…

HarmonyOS NEXT仓颉编程语言开发环境搭建(安装DevEco Studio Cangjie Plugin)

仓颉编程语言开发环境搭建主要是两部分&#xff1a; 安装最新版DevEco Studio&#xff1b;在DevEco Studio里面安装仓颉插件&#xff08;DevEco Studio Cangjie Plugin&#xff09;。 本文主要介绍DevEco Studio Cangjie Plugin的使用。 DevEco Studio Cangjie Plugin概述 …

【堆、快速选择排序】探寻TopK问题的解决方案

目录 前言 什么是TopK问题 建堆——优先级队列 快速选择排序QuickSelect 快速选择排序的时间复杂度 前言 TopK问题在面试中常常被问到 —— 比如&#xff0c;在10亿个整数里&#xff0c;找出最大的前100个。在海量数据中查找出重复出现的元素或者去除重复出现的元素也是常…

相亲交友小程序开发功能分析

相亲交友小程序的开发功能分析可以从用户端和管理后台两个主要方面来进行。 用户端功能 注册与登录&#xff1a; 用户可以通过手机号、微信号或其他第三方平台进行注册登录&#xff0c;简化注册流程。 实名认证&#xff1a; 引入实名认证机制&#xff0c;确保用户信息的真实…

统计学习与方法实战——K近邻算法

K近邻算法 K近邻算法备注k近邻模型算法距离度量 k k k值选择分类决策规则构造KDTree k k k近邻查找范围查询 代码结构总结 K近邻算法 备注 kNN是一种基本分类与回归方法. 多数表决规则等价于0-1损失函数下的经验风险最小化&#xff0c;支持多分类&#xff0c; 有别于前面的感…

深度学习——强化学习算法介绍

强化学习算法介绍 强化学习讨论的问题是一个智能体(agent) 怎么在一个复杂不确定的环境(environment)里面去极大化它能获得的奖励。 强化学习和监督学习 强化学习有这个试错探索(trial-and-error exploration)&#xff0c;它需要通过探索环境来获取对环境的理解。强化学习 ag…

嵌入式全栈开发学习笔记---C++(继承和派生)

目录 继承的概念inherit 继承的使用场景 继承的权限 继承对象的模型 继承中的构造和析构 初始化列表的第三个使用场景 场景1&#xff1a;类成员变量被const修饰&#xff1b; 场景2&#xff1a;类对象作为另一个类的成员变量&#xff0c;同时该类没有提供无参构造函数&a…

刷题记录-HOT 100(三)

链表 1、环形链表找环起始结点 使用快慢指针检测环&#xff1a; 初始化两个指针 slow 和 fast&#xff0c;都指向链表的头节点。slow 每次移动一步&#xff0c;fast 每次移动两步。如果 fast 和 slow 相遇&#xff08;即 fast slow&#xff09;&#xff0c;说明链表中存在环。…

探讨马丁格尔策略应用的3问和昂首平台的3答

问&#xff1a;为什么在使用马丁格尔策略时要如此谨慎?毕竟最大的市场波动可能根本不会发生。 答&#xff1a;让我们以一个具体的例子来说明这个问题。假设我们进行交易&#xff0c;计算出一个小于最大预期值的市场动量&#xff0c;比如说这个值为90便士。试想&#xff0c;如…

C#笔记6 网络编程基础,解释端口套接字,代码实例分析DNS,IPAddress等类

一、计算机网络基础 这一点毋庸置疑&#xff0c;想要写一个使用网络接口传输数据的程序&#xff0c;不知道计算机网络的基本知识是很难的。 局域网与广域网 所谓的WAN和LAN其实就是网络的一个范围界定。WAN为广域网&#xff0c;中间会包含更多的互联网设备&#xff0c;由无数…

OpenAI正在努力解决其面临的版权问题

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Web大学生网页作业成品——心理健康教育介绍网页设计与实现(HTML+CSS+JS)(4个页面)

&#x1f389;&#x1f389;&#x1f389; 常见网页设计作业题材有**汽车、环保、明星、文化、国家、抗疫、景点、人物、体育、植物、公益、图书、节日、游戏、商城、旅游、家乡、学校、电影、动漫、非遗、动物、个人、企业、美食、婚纱、其他**等网页设计题目, 可满足大学生网…

Redis Zset 类型:Score 属性在数据排序中的作用

Zset 有序集合 一 . zset 的引入二 . 常见命令2.1 zadd、zrange2.2 zcard2.3 zcount2.4 zrevrange、zrangebyscore2.5 zpopmax、zpopmin2.6 bzpopmax、bzpopmin2.7 zrank、zrevrank2.8 zscore2.9 zrem、zremrangebyrank、zremrangebyscore2.10 zincrby2.11 集合间操作交集 : zi…