当前位置: 首页 > 编程日记 > 正文

CT片居然可以这么玩:用头部CT断层扫描片复原三维头像

作者:天元浪子

来源:Python作业辅导员

前言

CT是现代医学影像的主力设备,寻常百姓并不陌生。通常,一张CT片由多张连续断层扫描的图像组成。在医生眼中,CT片展示了人体器官的形态和性质,是判断病人健康状况的重要依据。对于普通人而言,CT片则像天书,几无大用。不过呢,总有不甘寂寞喜欢折腾的程序员,把看似无用的CT片玩出了新花样——用头部CT断层扫描片成功复原出了逼真的三维头像。

CT是如何变成三维头像的呢?

说白了,其实很简单,只需要3步:

  1. 准备一套头部CT断层扫描片。怎么准备?要么去网上找(我就是从网上下载的),要么自己扫描胶片。

  2. 按照断层顺序逐张读入图片,并垂直堆叠成一个numpy数组。

  3. 导入3D工具库WxGL,调用capsule函数,绘制三维头像。

我手头这套头部CT断层扫描片共有109张,是侧卧位的水平断层扫描,从一侧开始至另一侧结束。下图从左至右分别是第11张、第21张、第55张、第89张、第99张。不难看出,中间的一张面积最大,是鼻梁正中的断层图片,鼻尖朝向图片上方,越往两侧的图片,面积越小。

有了CT断层扫描片,接下来就是打开文件读取数据了。做这一步之前需要先导入pillow模块和numpy模块。假定CT文件保存在:

D:\XufiveGithub\wxgl\res\headCT这个路径下,每个文件名都以head+序号的方式命名,下面是读取数据的代码。

>>> from PIL import Image
>>> import numpy as np
>>> base_dir = r'D:\XufiveGithub\wxgl\res\headCT'
>>> data = list()
>>> for i in range(109):im = np.array(Image.open(r'%s\head%d.png'%(base_dir, i)))data.append(im)>>> data = np.stack(data, axis=0)

其实,读取数据的代码可以写得更简洁,使用列表推导式,只用一行就可以了。

>>> data = np.stack([np.array(Image.open(r'%s\head%d.png'%(base_dir, i))) for i in range(109)], axis=0)
>>> data.shape
(109, 256, 256, 4)

从data.shape可以看出,总共有109个断层,每个断层分辨率是256x256像素,每个像素有RGBA四个通道。比较每个通道的数据,就会发现,每个断层的RGBA四个通道是完全相同的,这是胶片扫描的特点决定的。

三维重建的基本原理是滤除完全透明的像素,用具有相同透明度且位置相邻的像素构建surface,因此数组data中只有透明通道(A通道)是我们需要的。

data = data[...,3] # 提取透明通道
>>> data.shape
(109, 256, 256)

现在data变成一个三维数组了。数组的0轴,即第1张到第109张CT片的方向,对应着头像的左右;数组的1轴,即每张CT片自上而下的方向,对应着头像的前后;数组的2轴,即每张CT片从左至右的方向,对应着头像的上下。3D工具库WxGL习惯将数据数组的0轴视为高度方向,不做调整的话,绘制出的头像将是水平侧卧的,就像CT片展示的那样。为了让头像立起来,需要将头像的上下方对应的数组2轴翻转到0轴之后,再上下翻转。

>>> data = np.rollaxis(data, 2, 0) # 2轴翻转至0轴,让头像立起来(倒立)
>>> data = np.flipud(data) # 上下翻转,头像正立
>>> data.shape
(256, 109, 256)

至此,数据处理算是完成了,不过,这些数据还没有空间定位,只是保持了相对的位置关系,我们需要给数据限定一个空间位置。由于CT片没有给出头部尺寸和分层厚度,只能按照通常的头像比例,给出头像在xyz轴上的空间范围。

x = np.linspace(-1, 1, data.shape[2]) # 头像前后范围:[-1, 1]
y = np.linspace(-0.65, 0.65, data.shape[1]) # 头像左右范围:[-0.65, 0.65]
z = np.linspace(-1, 1, data.shape[0]) # 头像高度范围:[-1, 1]

另外,还要滤除几乎完全透明的那些像素。我们暂且以最大值的1/8作为阈值,调整该阈值将会得到不同的重建效果。

level = data.max()/8 # 忽略低于此阈值的数据

万事俱备,只欠东风。是时候让wxgl一显身手了。

plt.capsule(data, x=x, y=y, z=z, level=level, color='#EEE9D4')
plt.show()

不要惊讶,只需要两行代码,一个逼真的三维头像呈现在眼前。这一切,仅仅依赖一套CT断层扫描片和WxGL这个3D工具库。


刚刚发布的0.7.3版3D工具库WxGL,新增了几个有趣的功能,其中之一就是刚刚用到的capsule函数。capsule意为胶囊,顾名思义,capsule函数可以从三维数据中找出等值面,并尝试构建出囊性结构(如果存在的话)。WxGL的安装非常简单,直接使用pip命令即可。如果在安装和使用WxGL的过程中遇到问题,请在文后留言,也可以直接到我的GitHub反馈问题。

pip install wxgl

最后,附上用头部CT断层扫描片复原三维头像的完整代码。

import numpy as np
from PIL import Image
from wxgl import wxplot as pltbase = r'D:\XufiveGithub\wxgl\res\headCT'
data = np.stack([np.array(Image.open(r'%s\head%d.png'%(base, i))) for i in range(109)], axis=0)data = data[...,3] # 提取透明通道
data = np.rollaxis(data, 2, 0) # 2轴翻转至0轴,让头像立起来(倒立)
data = np.flipud(data) # 上下翻转,头像正立x = np.linspace(-1, 1, data.shape[2]) # 头像前后范围:[-1, 1]
y = np.linspace(-0.65, 0.65, data.shape[1]) # 头像左右范围:[-0.65, 0.65]
z = np.linspace(-1, 1, data.shape[0]) # 头像高度范围:[-1, 1]
level = data.max()/8 # 忽略低于此阈值的数据plt.capsule(data, x=x, y=y, z=z, level=level, color='#EEE9D4')
plt.show(rotate=-1)

下图直观显示了不同的阈值对于三维重建结果的影响。

END

新闻

英伟达推出全球首个元宇宙平台

技术

想提高代码水平,做到这点

技术

Unet网络实现叶子病虫害图像分割

新闻

17岁少年因“泄愤”攻击航司系统

分享

点收藏

点点赞

点在看

相关文章:

Nginx学习笔记(一) Nginx架构

Nginx全程是什么? Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 daemon守护线程 nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个master…

PXE实现批量部署linux系统

pxe批量部署linux服务器1、pxe介绍PXE是有intel设计的协议,它可以使计算机通过网络启动,协议分为client和server两端,PXEclient在网卡的ROM中,当计算机引导时,BIOS把PXE client调入内存中执行,并显示出命令…

首场见习挑战赛倒计时3天!20000元奖学金瓜分就等你了!

CSDN软件开发精英赛是基于“C认证—软件工程师能力认证考试”而设立的编程比赛,大赛联合广大科技企业设置丰厚礼品及30万元奖学金。从7月22日官宣到今日,短短一个月内,大赛已经吸引了来自全国的2000+开发者参与其中。第一轮“见习…

一致性哈希算法以及其PHP实现

在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括: 轮循算法(Round Robin)、哈希算法(HASH)、最少连接算法(Least Connection)、响应速度算法(Response Time…

Linux入门(四)

目录: 1234567891011121314一、根文件系统层级标准FHS二、bash的基础特性(一)1.命令历史 2.命令行补全 3.路径补全 4.命令行展开 5.命令执行的状态结果 6.引用 7.快捷键 三、目录管理相关命令mkdir、rmdir、tree四、引用命令的执行结果五、文…

OSI[七层]与TCP/IP[四层]模型简述简图

OSI参考模型(OSI/RM)的全称是开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM),它是由国际标准化组织(International Standard Organization,ISO&#xf…

中国国际消费电子博览会拥抱转型,全新面貌拭目以待!

2021年9月24—26日,第十九届中国国际消费电子博览会(简称电博会)将在青岛国际会展中心隆重举行,如今距离电博会开幕已不到3个月的时间,全国各地的参展企业跃跃欲试、积极筹备。 长久以来,电博会为全球消费…

Fragment提交transaction导致state loss异常

下面自从Honeycomb发布后,下面栈跟踪信息和异常信息已经困扰了StackOverFlow很久了。 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.j…

ASP网络编程从入门到精通 下载

《ASP网络编程从入门到精通》 清华大学出版社 特点: 面向ASP零基础读者,循序渐进 全面分析ASP技术细节 用代码描述个个知识点,操作性强 通过典型模块设计,体会ASP的奥妙 通过网上商城购物系统,增加项目开发经验 适合的…

项目Makefile文件模板

整理出来的一个Makefile模板,新增了一个内容,调用gcc生成依赖文件,这样如果某个c文件包含的头文件被更新了,该c文件以及依赖于该c文件的obj文件都会被重新编译.这个模板是按照我习惯的项目文件组织形式进行定义的,我的习惯是头文件放在include文件夹,代码放在src文件夹,目标文件…

小撒、金晨都想拥有!百度全球首款汽车机器人亮相,车内躺着看星星

整理 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 金晨坐了都想带回家的车、无人车出行服务、撒贝宁与祝融号对话等等。 这届百度世界大会真的很惊艳。 8月18日,百度与央视新闻联合举办“AI这时代,星辰大海——百度世界大会2021…

解决oracle11g安装导致数据库无法自动搜集统计信息-转

近期发现个别11G数据库无法自动收集统计信息,部分视图查询结果如下: SQL> select client_name,status from dba_autotask_client where client_name auto optimizer stats collection;CLIENT_NAME STATUS -----------------------------------------…

服务器监控--cacti中英文版安装全解

近段时间一直在整服务器监控方面的东西,以下就是cacti中英文版安装的全过程,各安装包基本都是最新的,基于Centos 5.2平台下安装的!!#!/bin/bash# BY kerryhu# QQ:263205768# MAIL:king_819163.com# BLOG:[url]http://kerry.blog.51cto.com[/url]# Please manual operation yum …

lighttpd1.4.18代码分析

lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态posted 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1) 编辑 lighttpd1.4.18代码分析(七)--状态机(1)CON_STATE_REQUEST_START状态posted 2008-09-22 15:10 那谁 阅读(2259) | 评论 (0) 编辑 lighttpd1.4.18代码分析…

惊艳亮相!马斯克发布自研超算 Dojo 芯片、特斯拉人形机器人

编译 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 北京时间 8 月 20 日,特斯拉 AI 日终于开始了!在活动上不仅推出自研计算机系统Dojo 及 D1 芯片,同时还推出了特斯拉的下一个大型项目:人形机器人&#x…

git revert和git reset的区别

git revert 是撤销某次操作,此次操作之前的commit都会被保留git reset 是撤销某次提交,但是此次之后的修改都会被退回到暂存区具体一个例子,假设有三个commit, git st:commit3: add test3.ccommit2: add test2.ccommit1: add test…

python之深浅拷贝

对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。 import copy # ######### 数字、字符串 #########n1 123 # n1 "age 10"print(id(n1)) # ## 赋值 ##n2 n1 print(id(n2)) # ## 浅拷贝 ##n2 copy.cop…

linux:关于Linux系统中 CPU Memory IO Network的性能监测

我们知道:系统优化是一项复杂、繁琐、长期的工作.通常监测的子系统有以下这些:CPUMemoryIONetwork下面是常用的监测工具Linux 系统包括很多子系统(包括刚刚介绍的CPU,Memory,IO,Network,等&…

火爆 GitHub!这个 AI 神器究竟有什么魅力?

图像分割(image segmentation)技术是计算机视觉领域的一个重要的研究方向,图像分割是计算机视觉中的一个关键过程。它包括将视觉输入分割成片段以简化图像分析。片段表示目标或目标的一部分,并由像素集或“超像素”组成。图像分割…

HTTP 状态代码

HTTP 状态代码 如果向您的服务器发出了某项请求要求显示您网站21kaiyun.com上的某个网页(例如,当用户通过浏览器访问您的网页时),那么,您的服务器会返回 HTTP 状态代码以响应该请求。 此状态代码提供了有关请求状态的信…

[Web 开发] 定制IE下载对话框的按钮(打开/保存)

下图常见的IE 下载对话框, 上面有3个主要按钮: Run (打开), Save(保存), Cancel (取消) 在某些情况下, 你不希望用户点击“Run” 按钮 或者 “Sav…

25 年汽车技术老兵亲述,自动驾驶新驶向

受访者 | 俞斌 记者 | 伍杏玲 出品 | AI科技大本营(ID:rgznai100) 在 IT 发展长河中,我们面对过不同的技术风口,历史终究大浪淘沙沉者为金。其中“自动驾驶”似乎是经久不衰的“风口”,成为人类的终极追求之一&#xf…

当你学了现在的忘了前面的

我怀疑我的智商应该不是很高,要不然我也不会学的如此狼狈。虽然我总是能很好的理解现在所学的知识点,但是我就是记不住,当下次再次需要上次的知识点来解决问题的时候,我总是忘的差不多了,要不就是没把握和对不对的问题…

HTTP referer

HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。比如从我主页上链接到一个朋友那里,他的服务器就能够…

设置grep高亮显示匹配项

grep是个非常高频的命令,我们通过给它设置别名,来把匹配项区分出来,这样可以更直观。 设置前: 12[rootzabbix ~]# /sbin/ifconfig eth0 | grep inet addr inet addr:192.168.88.66 Bcast:192.168.88.255 Mask:255.255.255.0 设置…

PHP之源码目录结构

PHP之所以能在web开发语言中排名靠前,不仅仅是因为语法简单,上手容易。我个人认为更多是因为其语言本身的:模块的易扩展性,可维护性以及内存安全管理等特点。写过PHP的程序员不一定都知道:PHP是如何执行的?…

SSAS系列——【07】多维数据(查询Cube)

原文:SSAS系列——【07】多维数据(查询Cube)1、什么是MDX? MDX叫做“多维表达式”,是一种查询语言,是一种和SQL类似的查询语言,它基于 XML for Analysis (XMLA) 规范,并带有特定于 SQL Server A…

什么是图数据库?图数据库实践与创新浅析

近日,中国工程院院士,清华大学计算机科学与技术系教授郑纬民先生,在人民日报发表文章《把握图数据库自主创新机遇》,建议国内科研学者和工程人员,要在图数据库的理论研究与工程研发上坚持自主创新道路,确保…

C# 对应 Oracle 存储过程 的 SYS_REFCURSOR 应该 传入什么类型的参数?

Oracle中scott用户下创建存储过程:(注:从9i开始有了sys_refcursor这种类型,在以前的Oracle版本中需要使用REF CURSOR,并且还需放在一个程序包中)create or replace procedure sp_getdept(result out sys_refcursor)asbeginopen result for se…

Fedora 15 安装与配置一览

Fedora 15 将于2011.5.24日发布,今日离正式版发布还有4天。笨兔兔这里提前给大家支招用好Fedora 15。下面是笨兔兔在安装、配置Fedora 15 过程中的小结,希望给大家配置自己的Fedora 15 带来方便。仅供参考,如有错误,敬请指出。 『…