精华内容
下载资源
问答
  • DICOM 图像

    热门讨论 2012-11-09 11:28:35
    dcm格式的医学图像,网上dcm格式的图像比较少,在这里分享一下,希望对从事dicom的朋友有帮助!图片CT、MR、US、VL、XA,传输语法为1.2.840.10008.1.2.4.70和扫描等
  • DICOM图像

    千次阅读 2019-10-31 12:34:21
    DICOM文件可以大致分为两部分: 一部分:与图像相关的元信息,包括患者信息,检查信息,序列信息,图像信息等等。 另一部分:图像的像素数据。 在解析DICOM文件中的像素数据的时候,我们先需要读取以下图像相关信息...

    医学影像(Medical Imaging),是指利用某种介质(例如X射线、电磁、超声波等等)与人体相互作用,从而以影像方式将人体内部组织器官的结构和密度表现出来,然后提供给医生进行判断并对人体健康状况得出结论的一门科学。


    医学影像仪器主要包含:

    1. X光影像仪器
    2. CT(Computerized Tomography Computed Tomography)
    3. 超声(分B超、彩色多普勒超声、心脏彩超、三维彩超)
    4. 核磁共振成像(MRI)

    DICOM(医学数字成像和通讯),英文全称Digital Imaging and Communications in Medicine,是ACR(美国放射协会)和NAMA(美国国家电子制造商协会)联合开发医学数字成像和通讯的一个通用标准。


    Dicom官方文档:https://www.dicomstandard.org/current/


    患者的医学图像以DICOM文件格式进行存储,其中包含了图像信息以及患者的PHI(protected health information,即姓名、性别、年龄等),以及产生图像的设备的相关信息。如下图所示,以dcm后缀结尾的文件即DICOM文件,其存储的信息为二进制格式


    DICOM文件的内容一般由一个DICOM文件头和一个DICOM数据集组成

    每个DICOM文件都必须包含文件头,主要信息:

    1. 文件导言
    2. DICOM前缀
    3. 文件元信息元素

    DICOM数据集是DICOM文件的主要组成部分

    1. TAG号
    2. 值表示
    3. 值长度
    4. 值域

    基于DICOM3.0标准,每一张图都携带大量的信息,可以细分为以下四类:

    • Patient
    • Study
    • Series
    • Image

    每一项信息都可以用DICOM TAG来标识,DICOM TAG由两个十六进制数组成,即(Group,Element)

    每一项信息被包装成最基本的单元:Data Element(数据元素)。每个Data Element 由四部分组成:

    • DICOM TAG :存储该项信息的标识
    • VR(Value Representation):存储描述该项信息的数据类型
    • value length :存储描述该项信息的数据长度
    • value:存储描述该项信息的数据值

    处理DICOM文件的现成库

    • C++:DCMTK
    • Java:dcm4che
    • Python:pydicom

    安装pydicom

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pydicom
    

    pydicom数据的读取


    pydicom数据的处理


    pydicom数据的保存


    DICOM文件可以大致分为两部分:
    一部分:与图像相关的元信息,包括患者信息,检查信息,序列信息,图像信息等等。
    另一部分:图像的像素数据。 在解析DICOM文件中的像素数据的时候,我们先需要读取以下图像相关信息:
    以下是某个CT影像中的图像信息示例: (0028,0002) Samples per Pixel VR: US Length: 2 Value: 1 (0028,0004) Photometric Interpretation VR: CS Length: 12 Value: MONOCHROME2 (0028,0010) Rows VR: US Length: 2 Value: 512 (0028,0011) Columns VR: US Length: 2 Value: 512 (0028,0030) Pixel Spacing VR: DS Length: 22 Value:
    0.48828125\0.48828125 (0028,0100) Bits Allocated VR: US Length: 2 Value: 16 (0028,0101) Bits Stored VR: US Length: 2 Value: 12 (0028,0102) High Bit VR: US Length: 2 Value: 11 (0028,0103) Pixel Representation VR: US Length: 2 Value: 0 (0028,1050) Window Center VR: DS Length: 12 Value: 00100\00100 (0028,1051) Window Width VR: DS Length: 12 Value: 00500\00500 (0028,1052) Rescale Intercept VR: DS Length: 6 Value: -1000 (0028,1053) Rescale Slope VR: DS Length: 2 Value: 1 (0028,2110) Lossy Image Compression VR: CS Length: 2 Value: 01 (0028,2112) Lossy Image Compression Ratio VR: DS Length: 8 Value: 6.228918

    1.(0028,0002) Samples per Pixel
    每一个像素的取样数,一般来说,CT,MR,DR等灰度图像都是1,而彩超等彩图像都是3,分别表示R, G, B三个颜色通道。

    2.(0028,0004) Photometric Interpretation
    我们经常碰到的Photometric Interpretation有以下几种类型:
    Monochrome2 一般的灰度图像都采用这种,Pixel值越大,图像就越白。
    Monochrome1 只有部分CR, DR图像使用,Pixel值越大,图像就越黑。
    Palette Colour 一般用于彩超图像,每个像素占用8位或者16位,调色板保存在[0028,1201]RedPaletteColorLookupTableData, [0028,1202]GreenPaletteColorLookupTableData, [0028,1203]BluePaletteColorLookupTableData的属性中。
    RGB 这是最常用的彩图像格式。
    YBR_FULL 另外一种彩
    图像格式, 存储格式为Y(Luminance 亮度), B(Blueness 蓝色), R(Redness, 红色)
    YBR_FULL_422 一般用于JPG有损压缩格式的彩图像,每两个像素共同使用32位,每一个像素都有自己的Y(Luminance 亮度),但是共享相同的B(Blueness 蓝色), R(Redness, 红色)。所以,它的像素值存储方式是:YYBR,YYBT,YYBR
    YBR_RCT 用于JPEG 2000无损压缩彩
    图*像,Reversible Color Transformation, 可逆色彩变换。
    Y = (R+2G+B)/4, CB = B-G , CR = R - G
    G = Y - (CR+CB)/4 , R = CR + G, B = CB + G
    YBR_ICT 用于JPEG 2000有损压缩彩**图像 Irreversible Color Transformation, 不可逆色彩变换。
    Y = + .29900R + .58700G + .11400B
    CB = - .16875R - .33126G + .50000B
    CR = + .50000R - .41869G - .08131B
    3. (0028,0010)Rows
    图像的高度

    1. (0028,0011)Columns
      图像的宽度

    2. (0028,0030)Pixel Spacing
      图像像素间距,读取Pixel Data的时候不需要,主要用于长度测量。

    3. (0028,0100)Bits Allocated
      一个像素取样点存储时分配到的位数,一般RGB的图像,每一个颜色通道都使用8位,所以一般取值为8。对于灰度图像,如果是256级灰阶,一般就是8位。如果高于256级灰阶,一般就采用16位。

    4. (0028,0101)Bits Stored
      一个像素取样点存储时使用到的位数。比方说示例中CT影像,采用的是4K灰阶,像素值取值范围为0~4095,所以使用到的位数为12位。

    5. (0028,0102)High Bit
      最高位序号,它定义了存储点在分配的内存中的排列方式,它的值是最后一个bit的序号。如果第一个bit放在0位,那么最后一个bit为Bits Stored -1。

    6. (0028,0103)Pixel Representation
      如果这个值为0, 这表明是无符号类型,其VR类型应该为US,Unsigned Short. 如果这个值为1, 这表明为有符号类型,其VR类型应该为SS,Signed Short.

    7. (0028,1050)Window Center 和 (0028,1051) Window Width
      窗宽窗位,不解释

    8. (0028,1052)Rescale Intercept 和 (0028,1053)Rescale Slope
      用于根据像素值计算原始值,比方说,CT可以用于计算HU值。
      比方说:HU = Rescale Slope * X + Rescale Intercept.

    9. (0028,2110)Lossy Image Compression
      当该值为1时,表明该图像曾经经过有损压缩处理。即使后来解压缩后,再用非压缩格式存储和传输,该值也需要保持为1.

    10. (0028,2112)Lossy Image Compression Ratio
      有损压缩压缩率。 对于多帧图像,我们还需要读取Number of Frames (0028,0008)来获取帧数,然后,逐帧读取Pixel Data。 对于彩*图像,我们还需要读取Planar configuration (0028,0006),它定义了各个彩色通道值在Pixel Data中排列的排列方式。 当此值为0的时候,它这样排列的RGBRGBRGBRGBRGB。 当此值为1的时候,它是这样排列的:RRRRR…GGGGG…BBBBB。 对于多帧图像,它是这样排列的:第一帧的RRR…,第一帧的GGG…,第一帧的BBB…,第二帧的RRR…,第二帧的GGG…,第二帧的BBB…

    展开全文
  • Dicom图像发送

    2017-11-08 09:26:57
    Dicom图像发送工具Dicom图像发送工具Dicom图像发送工具
  • DicomTool 是一个免费的 C++ 工具,基于 DCMTK 库,给定一个 dicom 图像(它也适用于压缩的 dicom 图像)或包含许多 dicom 图像的目录,允许: 将他们匿名; 将它们转换为位图格式; 将它们的像素数据值保存在 ...
  • 医学图像标准格式DICOM文件的发送和接收
  • DICOM图像源码dicom.rar

    2020-06-04 15:26:41
    这用DELPHI6编写的程序,可以将BMP图像转变生成DICOM图像,也可以打开DICOM图像,下载解压之后里面有源程序,可以看到源码,比较清楚。
  • 非常简单好用的 DICOM图像发送测试工具,非常简单好用的 DICOM图像发送测试工具;非常简单好用的 DICOM图像发送测试工具,非常简单好用的 DICOM图像发送测试工具;
  • importcv2importnumpyimportdicomfrom matplotlib importpyplot as plt#读取单张Dicom图像dcm = dicom.read_file("../Data/vhm.420.dcm")dcm.image= dcm.pixel_array * dcm.RescaleSlope +dcm.RescaleIntercept#获取...

    importcv2importnumpyimportdicomfrom matplotlib importpyplot as plt#读取单张Dicom图像

    dcm = dicom.read_file("../Data/vhm.420.dcm")

    dcm.image= dcm.pixel_array * dcm.RescaleSlope +dcm.RescaleIntercept#获取图像中的像素数据

    slices =[]

    slices.append(dcm)#复制Dicom图像中的像素数据

    img = slices[ int(len(slices)/2) ].image.copy()#对图像进行阈值分割

    ret,img = cv2.threshold(img, 90,3071, cv2.THRESH_BINARY)

    img=numpy.uint8(img)#提取分割结果中的轮廓,并填充孔洞

    im2, contours, _ =cv2.findContours(img,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

    mask=numpy.zeros(img.shape, numpy.uint8)for contour incontours:

    cv2.fillPoly(mask, [contour],255)

    img[(mask> 0)] = 255

    #对分割结果进行形态学的开操作

    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(2,2))

    img=cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)#根据分割mask获取分割结果的像素数据

    img2 = slices[ int(len(slices)/2) ].image.copy()

    img2[(img== 0)] = -2000

    #显式原始数据,mask和分割结果

    plt.figure(figsize=(12, 12))

    plt.subplot(131)

    plt.imshow(slices[int(len(slices)/ 2)].image, 'gray')

    plt.title('Original')

    plt.subplot(132)

    plt.imshow(img,'gray')

    plt.title('Mask')

    plt.subplot(133)

    plt.imshow(img2,'gray')

    plt.title('Result')

    plt.show()

    展开全文
  • 西门子查看DICOM图像

    2019-03-14 11:44:04
    西门子专用看DICOM图像软件,可以直接查看DICOM图像,界面是西门子的样式。
  • MR膝盖DICOM图像

    2018-12-19 17:19:29
    dicom图像资源 膝盖图像 dicom MR格式图像 压缩文件 16张
  • 影像测试DICOM图像

    2019-02-22 23:59:12
    影像测试DICOM图像
  • DICOM 图像浏览器

    2015-10-17 22:51:25
    DICOM 图像浏览器,能打开医学图像
  • Dicom图像发送工具

    2016-09-02 18:38:53
    Dicom图像发送工具
  • 目录: 开始《DCMTK(MD版)编译和安装+VS2015》 第一章 《DCMTK(MD版)、QT、VS2015编写Dicom序列...第三章 《基于QT和DCMTK的Dicom 图像浏览器---单个Dicom图像读取类》 第四章 《基于QT和DCMTK的Dicom 图像浏...

    目录:

    开始  《DCMTK(MD版)编译和安装+VS2015》

    第一章 《DCMTK(MD版)、QT、VS2015编写Dicom序列浏览应用程序-新建项目,配置环境》

    第二章 《第二章 基于QT和DCMTK的Dicom 图像浏览器---界面设计》

    第三章 《 基于QT和DCMTK的Dicom 图像浏览器---单个Dicom图像读取类》

    第四章 《基于QT和DCMTK的Dicom 图像浏览器---检查文件夹下Dicom序列个数》

    第五章 《基于QT和DCMTK的Dicom 图像浏览器---Dicom图像序列类

    第六章  《基于QT和DCMTK的Dicom 图像浏览器---Dicom视图类

    第七章  《基于QT和DCMTK的Dicom 图像浏览器---收尾》

    一、 描述

    series UID 是区别每个序列的标识:同Dicom序列的series UID 一样,不同序列的series UID不一样。

    instanceNumber是序列内Dicom单文件的标识: instanceNumber决定了Dicom单文件在序列内的位置。

    二、准备工作

    编写mygobal.h

    #pragma once
    
    class QMainWindow;
    struct Rad_G {
    	static QMainWindow *m_mainWin;
    };

    编写mygobal.cpp

    #include "myGobal.h"
    #include <QMainWindow>
    
    QMainWindow *Rad_G::m_mainWin = 0;

    修改 DicomBrowse.cpp

    #include "myGobal.h"
    ...
    DicomBrowse::DicomBrowse(QWidget *parent)
    	: QMainWindow(parent)
    {
    	ui.setupUi(this);
    	isOpeing = false;	
    	Rad_G::m_mainWin = this; // 添加
    }
    ...

    修改Image.h

    ...
    class DiPixel;
    class Image{
    public:
    ...
        const DiPixel *getInternalPtr(); // 添加
    ...
    }

    修改Image.cpp

    ...
    const DiPixel * Image::getInternalPtr()
    {
    	return isNormal() ? dcmImage->getInterData() : nullptr;
    }
    ...

    修改ReadWorker.h

    ...
    class ReadWorker : public QObject
    {
    public:
    ...
    	QString curUid;
    public slots:
    	...
    	void readSeries();
    ...
    
    }

    修改ReadWorker.cpp

    #include "SeriesBase.h"
    ...
    void ReadWorker::readSeries()
    {
        // 读取指定的序列
    	if (!UID_Files.keys().contains(curUid))
    	{
                emit finish();
                return;
            }
    	QStringList files = UID_Files[curUid];
    
    	Image *dicom = 0; // 单Dicom文件
    	int progressValue = 0;
    	foreach(QString fileName, files)
    	{
    		++progressValue;
    		emit progress(100 * progressValue / files.size()/* 转到0-100之间*/);
    		dicom = new Image(fileName);
    		if (!dicom->isNormal())
    		{
    			delete dicom; dicom = 0;
    			continue; // 读取不成功(不是Dicom文件),跳出直接读取下一个文件
    		}
    
    		SeriesBase::append(dicom);
    	}
            emit finish();
    }
    ...

    三、序列基类

    添加基类

    修改类

    #pragma once
    #include <QMap>
    #include <QRectF>
    #include <QPixmap>
    
    class Image;
    class QSlider;
    class SeriesBase
    {
    public:
    	enum ViewType
    	{
    		XY = 0,
    		XZ,
    		YZ
    	};
    
    	SeriesBase();
    	virtual ~SeriesBase();
    	QSlider *slider; // 控制切片位置的控件
    
    	static void readSeriesUid(QString &s); // 读取序列
    	static void append(Image*);
    	static bool isNormal(); // 读取完,检查是否是可用的dicoms
    	
    	// 设置伪彩色和窗宽窗位
    	static void setColor(int color);
    	
    	static void setWindow(const double &center, const double &width)
    	{
    		winCenter = center; winWidth = width;
    	}
    	static void setWindowDelta(const double &dCenter, const double &dWidth)
    	{
    		winCenter += dCenter; winWidth += dWidth;
    	}
    	static void setRoiWindow(const QRectF &rect); // 只对XY视图有效
    	static void setDefaultWindow()
    	{
    		winCenter = defCenter; winWidth = defWidth;
    	}
    	static void getWindow(double &center, double &width)
    	{
    		center = winCenter; width = winWidth;
    	}
    	static void getSeriesSize(int &w, int&h, int&s)
    	{
    		w = imageWidth; h = imageHeight; s = dicomsSize;
    	}
    	const ViewType getViewType()
    	{
    		return vt;
    	}
    
    	/*--虚函数--*/
    	virtual void nextFrame() = 0;
    	virtual void prevFrame() = 0;
    	virtual void gotoFrame(int index) = 0;
    	virtual bool getPixmap(QPixmap &pixmap) = 0;
    	
    	virtual int getCurFrame() = 0;
    	virtual int getFrameCount() = 0;
    	virtual bool getRectSize(int &x_width, int &y_height) = 0;
    
    	virtual bool getPixSpacing(double &xs, double &ys) = 0; // 和视图比例有关
    	virtual QString getPixelValue(int x, int y) = 0;
    	virtual void update();
    	
    protected:
    	static QString UID; //序列唯一标识
    	static QMap<int, Image*> dicoms;// 序列
    	static const qint32** volume; // 三维体数据,对YZ、XZ视图有用
    	static int volumeSlices; // 三维体数据qint32*[]的个数,对YZ、XZ视图有用
    	static void createVolume();
    	static void deleteVolume();
    
    	static int curXYFrame;// 当前图像
    	static int curXZFrame;
    	static int curYZFrame;
    	ViewType vt; // 视图方式
    	static bool hasTreeView; // 彩色序列没有三视图
    
    	static double winCenter; // 窗位
    	static double winWidth; // 窗宽
    	static double defCenter;// 默认窗位窗宽
    	static double defWidth;
    
    	static int imageWidth;
    	static int imageHeight;
    	static int dicomsSize;
    };
    

     

    #include "SeriesBase.h"
    #include "ReadWorker.h"
    #include "Image.h"
    #include "myGobal.h"
    
    #include "dcmtk/dcmimgle/dcmimage.h"
    
    #include <qmainwindow.h>
    #include <QEventLoop>
    #include <QThread>
    #include <QObject>
    #include <QSlider>
    
    SeriesBase::SeriesBase()
    {
    	SeriesBase::volume = 0;
    	volumeSlices = 0;
    	slider = new QSlider;
    	slider->setMinimum(0);
    	slider->setOrientation(Qt::Vertical);
    	slider->setAttribute(Qt::WA_StyledBackground, true);
    	slider->setStyleSheet("background-color: rgba(200,200, 200,0)");
    }
    
    SeriesBase::~SeriesBase()
    {
    	qDeleteAll(dicoms.values());
    	dicoms.clear();	
    	deleteVolume();
    }
    
    void SeriesBase::readSeriesUid(QString &uid)
    {
    	if (UID == uid)
    		return;
    	UID = uid;
    	qDeleteAll(dicoms.values());
    	dicoms.clear();
    	deleteVolume();
    
    	SeriesBase::curXYFrame = 0;
    	SeriesBase::curXZFrame = 0;
    	SeriesBase::curYZFrame = 0;
    
    	ReadWorker *worker = new ReadWorker("");
    	worker->curUid = uid;
    	QThread *thread = new QThread();
    	QEventLoop loop;// 循环
    
    	QObject::connect(thread, SIGNAL(started()), worker, SLOT(readSeries())); // 线程开始后执行worker->readSeries()
    	QObject::connect(worker, SIGNAL(progress(int)), Rad_G::m_mainWin, SLOT(setProgressBarValue(int)));
    
    	QObject::connect(worker, SIGNAL(finish()), worker, SLOT(deleteLater()));// 执行完成,析构worker
    	QObject::connect(worker, SIGNAL(destroyed(QObject*)), thread, SLOT(quit()));// 析构worker 完成, 推出线程
    	QObject::connect(thread, SIGNAL(finished()), &loop, SLOT(quit())); // 退出线程, 退出循环
    	QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); // 退出线程, 析构线程
    
    	worker->moveToThread(thread); // 把worker 移动到线程
    	thread->start(); // 开始线程
    	loop.exec(); // 等待worker->readSeries()执行完成,退出循环
    
    	if (!isNormal())
    		return;
    	dicomsSize = dicoms.size();// 初始化dicomsSize ,即有多少序列
    
    	createVolume();//
    }
    
    void SeriesBase::append(Image *dicom)
    {
    	if (dicom && dicom->isNormal()) {
    		if (UID != dicom->getSeriesUID())
    		{
    			delete dicom;dicom = 0;
    			return;
    		}
    
    		if (dicoms.isEmpty()) {
    			dicom->getWindow(winCenter, winWidth);//  初始化窗宽窗位
    			dicom->getWindow(defCenter, defWidth);// 初始化默认窗宽位
    			dicom->getImageSize(imageWidth, imageHeight);// 初始化图像宽高
    		}
    		dicoms.insert(dicom->getInstanceNumber(), dicom);// 把图像插入到对应的位置
    	}
    }
    
    bool SeriesBase::isNormal()
    {
    	return !dicoms.isEmpty();
    }
    
    void SeriesBase::setColor(int color)
    {
    	Image::setColor(color);
    }
    
    // 实现鼠标划框调整窗宽位
    void SeriesBase::setRoiWindow(const QRectF & rect)
    {
    	if (dicoms.isEmpty()) return;
    
    	Image *image = dicoms.values().at(curXYFrame);
    	image->setRoiWindow(rect);
    	image->getWindow(winCenter, winWidth);
    }
    
    void SeriesBase::createVolume()
    {
    	dicoms.values().first()->isMonochrome() ? hasTreeView = true : hasTreeView = false;
    	if (!hasTreeView)
    		return;
    
    	 volumeSlices = dicomsSize;
    	size_t length = imageWidth*imageHeight;
    
    	volume = new const qint32*[dicomsSize];
    
    	quint8 *utemp8 = 0;
    	qint8 *temp8 = 0;
    	quint16 *utemp16 = 0;
    	qint16 *temp16 = 0;
    	quint32 *utemp32 = 0;
    	qint32 *temp32 = 0;
    
    	qint32 *temp = 0;
    
    	for (int i = 0; i < dicomsSize; ++i)
    	{
    		const DiPixel *pixel = dicoms.values().at(i)->getInternalPtr();
    		EP_Representation rest = pixel->getRepresentation();
    		if (pixel->getCount() != length)
    		{
    			hasTreeView = false; volumeSlices = i;
    			return;
    		}
    
    		temp = new qint32[length];
    		volume[i] = temp;
    
    		switch (rest)
    		{
    		case EPR_Uint8:
    			utemp8 = (quint8*)pixel->getData();
    			for (int j = 0; j < length; ++j)
    				temp[i] = utemp8[i];
    			break;
    		case EPR_Sint8:
    			temp8 = (qint8*)pixel->getData();
    			for (int j = 0; j < length; ++j)
    			{
    				temp[j] = temp8[j];
    			}
    			break;
    		case EPR_Uint16:
    			utemp16 = (quint16*)pixel->getData();
    			for (int j = 0; j < length; ++j)
    				temp[j] = utemp16[j];	
    			break;
    		case EPR_Sint16:
    			temp16 = (qint16*)pixel->getData();
    			for (int j = 0; j < length; ++j)
    			{
    				temp[j] = temp16[j];
    			}
    			break;
    		case EPR_Uint32:
    			utemp32 = (quint32*)pixel->getData();
    			for (int j = 0; j < length; ++j)
    			{
    				temp[j] = utemp32[j];
    			}
    			break;
    		case EPR_Sint32:
    			temp32 = (qint32*)pixel->getData();
    			for (int j = 0; j < length; ++j)
    			{
    				temp[j] = temp32[j];
    			}
    			break;
    		}
    	}
    }
    
    void SeriesBase::deleteVolume()
    {
    	if (volume == 0)
    		return;
    
    	for (int i = 0; i < volumeSlices; ++i)
    	{
    		if (volume[i] != 0)
    		{
    			delete[] volume[i];
    			volume[i] = 0;
    		}
    	}
    	
    	delete[] volume;
    	volume = 0;
    	volumeSlices = 0;
    }
    
    void SeriesBase::update()
    {
    	if(slider)
    		slider->setMaximum(getFrameCount() - 1);
    }
    
    
    QString SeriesBase::UID; //序列唯一标识
    QMap<int, Image*> SeriesBase::dicoms;// 序列
    const qint32** SeriesBase::volume=0; // 三维体数据,对YZ、XZ视图有用
    int SeriesBase::volumeSlices=0; // 三维体数据qint32*[]的个数,对YZ、XZ视图有用
    
    int SeriesBase::curXYFrame=0;// 当前图像
    int SeriesBase::curXZFrame=0;
    int SeriesBase::curYZFrame=0;
    
    bool SeriesBase::hasTreeView=false; // 彩色序列没有三视图
    
    double SeriesBase::winCenter; // 窗位
    double SeriesBase::winWidth; // 窗宽
    double SeriesBase::defCenter;// 默认窗位窗宽
    double SeriesBase::defWidth;
    int SeriesBase::imageWidth = 0;
    int SeriesBase::imageHeight = 0;
    int SeriesBase::dicomsSize = 0;

    四、XY面序列

    XYSeries.h

    #pragma once
    #include "SeriesBase.h"
    class XYSeries :
    	public SeriesBase
    {
    public:
    	XYSeries();
    	virtual ~XYSeries();
    
    	virtual void nextFrame();
    	virtual void prevFrame();
    	virtual void gotoFrame(int index);
    	virtual bool getPixmap(QPixmap &pixmap);
    
    	virtual int getCurFrame();
    	virtual int getFrameCount();
    	virtual bool getRectSize(int &x_width, int &y_height);
    
    	virtual bool getPixSpacing(double &xs, double &ys); // 和视图比例有关
    	virtual QString getPixelValue(int x, int y);
    };

    XYSeries.cpp

    #include "XYSeries.h"
    #include "Image.h"
    #include <QSlider>
    
    XYSeries::XYSeries():SeriesBase()
    {
    	vt = SeriesBase::XY;
    }
    
    XYSeries::~XYSeries()
    {
    
    }
    
    void XYSeries::nextFrame()
    {
    	++curXYFrame;
    	if (curXYFrame >= dicomsSize)
    		curXYFrame = 0;
    	slider->setValue(curXYFrame);
    }
    
    void XYSeries::prevFrame()
    {
    	--curXYFrame;
    	if (curXYFrame < 0)
    		curXYFrame = dicomsSize - 1;
    	slider->setValue(curXYFrame);
    }
    
    void XYSeries::gotoFrame(int index)
    {
    	if (index < 0)
    		curXYFrame = 0;
    	else if (curXYFrame >= dicomsSize)
    		curXYFrame = dicomsSize - 1;
    	else curXYFrame = index;
    	slider->setValue(curXYFrame);
    }
    
    bool XYSeries::getPixmap(QPixmap & pixmap)
    {
    	if (dicoms.isEmpty())
    		return false;
    	Image *image = dicoms.values().at(curXYFrame);
    	if (winWidth < 1) winWidth = 1;
    	image->setWindow(winCenter, winWidth);
    
    	return image->getPixmap(pixmap);
    }
    
    int XYSeries::getCurFrame()
    {
    	return curXYFrame;
    }
    
    int XYSeries::getFrameCount()
    {
    	return dicoms.size();
    }
    
    bool XYSeries::getRectSize(int & x_width, int & y_height)
    {
    	if (isNormal())
    	{
    		x_width = imageWidth;
    		y_height = imageHeight;
    		return true;
    	}
    	return false;
    }
    
    bool XYSeries::getPixSpacing(double & xs, double & ys)
    {
    	if (isNormal())
    	{
    		double zs;
    		return dicoms.values().first()->getPixSpacing(xs, ys, zs);
    	}
    	return false;
    }
    
    QString XYSeries::getPixelValue(int x, int y)
    {
    	if (isNormal())
    	{
    		return dicoms.values().at(curXYFrame)->getPixInfo(x,y);
    	}
    	return "";
    }
    

    五、 XZ面序列

    #pragma once
    #include "SeriesBase.h"
    class XZSeries :
    	public SeriesBase
    {
    public:
    	XZSeries();
    	virtual ~XZSeries();
    
    	virtual void nextFrame();
    	virtual void prevFrame();
    	virtual void gotoFrame(int index);
    	virtual bool getPixmap(QPixmap &pixmap);
    
    	virtual int getCurFrame();
    	virtual int getFrameCount();
    	virtual bool getRectSize(int &x_width, int &y_height);
    
    	virtual bool getPixSpacing(double &xs, double &ys); // 和视图比例有关
    	virtual QString getPixelValue(int x, int y);
    };
    #include "XZSeries.h"
    #include "Image.h"
    #include <QSlider>
    
    
    XZSeries::XZSeries():SeriesBase()
    {
    	vt = SeriesBase::XZ;
    }
    
    XZSeries::~XZSeries()
    {
    }
    
    void XZSeries::nextFrame()
    {
    	++curXZFrame;
    	curXZFrame >= imageHeight ? curXZFrame = 0 : curXZFrame = curXZFrame;
    	slider->setValue(curXZFrame);
    }
    
    void XZSeries::prevFrame()
    {
    	--curXZFrame;
    	curXZFrame < 0 ? curXZFrame = imageHeight - 1 : curXZFrame = curXZFrame;
    	slider->setValue(curXZFrame);
    }
    
    void XZSeries::gotoFrame(int index)
    {
    	index < 0 ? index = 0 : index = index;
    	index >= imageHeight ? index = imageHeight - 1 : index = index;
    	curXZFrame = index;
    	slider->setValue(curXZFrame);
    }
    
    bool XZSeries::getPixmap(QPixmap & pixmap)
    {
    	if(!hasTreeView)
    		return false;
    
    	size_t length = imageWidth * dicomsSize;
    	uchar *pDIB = new uchar[length];
    	memset(pDIB, 0, sizeof(uchar)*length);
    	double center = winCenter;
    	double width = winWidth;
    	double factor = 255 / width;
    	double lower = center - width / 2;
    
    	/*>>>>>>>>>>>>>赋值《《《《《《《《*/
    	for (uint y = 0; y < dicomsSize; ++y) {
    		const qint32 *ptr = volume[y];
    		int idx = curXZFrame * imageWidth;
    		int bmpIdx = (dicomsSize - 1 - y) * imageWidth;
    		if (ptr) {
    			for (uint x = 0; x < imageWidth; ++x) {
    				qint32 val = ptr[idx + x];
    				if (val > lower + width) pDIB[bmpIdx + x] = 255;
    				else if (val > lower) pDIB[bmpIdx + x] = (val - lower)*factor;
    			}
    		}
    	}
    
    	bool res = Image::UcharArrayToPixmap(pDIB, imageWidth, dicomsSize, length, pixmap, 8);
    	delete pDIB;
    	return res;
    }
    
    int XZSeries::getCurFrame()
    {
    	return curXZFrame;
    }
    
    int XZSeries::getFrameCount()
    {
    	if (!hasTreeView)
    		return 0;
    	return imageHeight;
    }
    
    bool XZSeries::getRectSize(int & x_width, int & y_height)
    {
    	if (isNormal() && hasTreeView)
    	{
    		x_width = imageWidth;
    		y_height = dicoms.size(); 
    		return true;
    	}
    	return false;
    }
    
    bool XZSeries::getPixSpacing(double & xs, double & ys)
    {
    	if (isNormal() && hasTreeView)
    	{
    		double d;
    		return dicoms.values().first()->getPixSpacing(xs, d, ys);
    	}
    	return false;
    }
    
    QString XZSeries::getPixelValue(int x, int y)
    {
    	if (isNormal()&&hasTreeView)
    	{
    		if (y < 0) y = 0;
    		if (y >= dicomsSize) y = dicomsSize - 1;
    		return dicoms.values().at(y)->getPixInfo(x, curXZFrame);
    	}
    	return "";
    }

     

    六、 YZ面序列

     

    #pragma once
    #include "SeriesBase.h"
    class YZSeries :
    	public SeriesBase
    {
    public:
    	YZSeries();
    	virtual ~YZSeries();
    
    	virtual void nextFrame();
    	virtual void prevFrame();
    	virtual void gotoFrame(int index);
    	virtual bool getPixmap(QPixmap &pixmap);
    
    	virtual int getCurFrame();
    	virtual int getFrameCount();
    	virtual bool getRectSize(int &x_width, int &y_height);
    
    	virtual bool getPixSpacing(double &xs, double &ys); // 和视图比例有关
    	virtual QString getPixelValue(int x, int y);
    };
    #include "YZSeries.h"
    #include <qslider.h>
    #include "Image.h"
    
    
    YZSeries::YZSeries():SeriesBase()
    {
    	vt = SeriesBase::YZ;
    }
    
    
    YZSeries::~YZSeries()
    {
    }
    
    void YZSeries::nextFrame()
    {
    	++curYZFrame;
    	if (curYZFrame >= imageWidth)
    		curYZFrame = 0;
    	slider->setValue(curYZFrame);
    }
    
    void YZSeries::prevFrame()
    {
    	--curYZFrame;
    	if (curYZFrame < 0)
    		curYZFrame = imageWidth - 1;
    	slider->setValue(curYZFrame);
    }
    
    void YZSeries::gotoFrame(int index)
    {
    	index < 0 ? index = 0 : index = index;
    	index >= imageWidth ? index = imageWidth - 1 : index = index;
    
    	curYZFrame = index;
    	slider->setValue(curYZFrame);
    }
    
    bool YZSeries::getPixmap(QPixmap & pixmap)
    {
    	if (!hasTreeView)
    		return false;
    
    	size_t size = imageHeight * dicomsSize;
    	uchar *pDIB = new uchar[size];
    	memset(pDIB, 0, sizeof(uchar)*size);
    	double center = winCenter;
    	double width = winWidth;
    	double factor = 255 / width;
    	double lower = center - width / 2;
    
    	/*>>>>>>>>>>>>>赋值《《《《《《《《*/
    	for (uint y = 0; y < dicomsSize; ++y) {
    		const qint32 *ptr = volume[y];
    		int bmpIdx = (dicomsSize - 1 - y) * imageHeight;
    		if (ptr) {
    			for (uint x = 0; x < imageHeight; ++x) {
    				qint32 val = ptr[x*imageWidth + curYZFrame];
    				if (val > lower + width) pDIB[bmpIdx + x] = 255;
    				else if (val > lower) pDIB[bmpIdx + x] = (val - lower)*factor;
    			}
    		}
    	}
    
    	bool res = Image::UcharArrayToPixmap(pDIB, imageHeight, dicomsSize, size, pixmap, 8);
    	delete pDIB;
    	return res;
    }
    
    int YZSeries::getCurFrame()
    {
    	return curYZFrame;
    }
    
    int YZSeries::getFrameCount()
    {
    	if (!hasTreeView)
    		return 0;
    	return imageWidth;
    }
    
    bool YZSeries::getRectSize(int & x_width, int & y_height)
    {
    	if (isNormal() && hasTreeView)
    	{
    		x_width = imageHeight;
    		y_height = dicoms.size();
    		return true;
    	}
    	return false;
    }
    
    bool YZSeries::getPixSpacing(double & xs, double & ys)
    {
    	if (isNormal() && hasTreeView)
    	{
    		double d;
    		return dicoms.values().first()->getPixSpacing(d, xs, ys);
    	}
    	return false;
    }
    
    QString YZSeries::getPixelValue(int x, int y)
    {
    	if (isNormal() && hasTreeView)
    	{
    		if (y < 0) y = 0;
    		if (y >= dicomsSize) y = dicomsSize - 1;
    		return dicoms.values().at(y)->getPixInfo(curYZFrame, x);
    	}
    	return "";
    }
    

     

    展开全文
  • DICOM图像中关于怎么显示图像方位的介绍
  • 我发现使用3D Slicer打开DICOM图像序列,分辨率非常清晰,但我用自己的demo,ITK读取DICOM序列,然后用VTK显示DICOM图像,分辨率非常模糊,没有3DSlicer清晰。为什么?看了3d slicer代码,我发现3dslicer使用自己...
  • 彩色花朵dicom图像

    2017-09-28 07:13:21
    内含彩色花朵dicom图像10张,经过试验可以使用VTK读取
  • Dicom图像资源

    2012-08-15 17:09:43
    Dicom图像,能够更好应用于实验或测试
  • DICOM图像浏览器

    2015-01-10 18:25:01
    dicom浏览器是一款查看影像资料的辅助工具。他可以读取和显示DICOM图像文件,支持窗宽窗位调节,直线、角度等测量,多帧影像播放,JPEG格式导出。
  • VTK.js 实现网页版dicom图像三维重建
  • Dicom图像浏览器

    热门讨论 2010-12-08 13:23:58
    一款相当经典的Dicom图像浏览器 非常值得下载 还带Dicom格式转换JPG
  • DcomRepository DICOM 图像
  • DICOM图像相关文档

    2011-04-11 15:58:53
    DICOM图像与BMP图像的转换研究 DICOM图像在PC机上的显示编辑和演示方法研究 DICOM信息读取接口设计 DICOM医学数字图像格式与BMP通用图像格式转换软件的设计与实现 DICOM医学图像文件格式 DICOM医学图像文件格式解析...
  • DICOM图像查看转换软件,可以查看,转换jpg,视频等,自己测试可以win7一下使用正常,win10 有兼容性的问题,放射科医生必备。
  • dicom 图像传输

    2012-05-26 12:07:04
    dicom图像传输的课程作业,利用C++编写
  • 今天小编就为大家分享一篇python读取dicom图像示例(SimpleITK和dicom包实现),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • DCMTK:缩放DICOM图像

    2021-05-14 22:51:44
    DCMTK:缩放DICOM图像缩放DICOM图像 缩放DICOM图像 #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk/dcmdata/cmdlnarg.h" #include "dcmtk/dcmdata/dcuid.h" #include ...

    DCMTK:缩放DICOM图像

    缩放DICOM图像

    #include "dcmtk/config/osconfig.h"   
    #include "dcmtk/dcmdata/dctk.h"         
    #include "dcmtk/dcmdata/cmdlnarg.h"     
    #include "dcmtk/dcmdata/dcuid.h"       
    #include 
    展开全文
  • 这允许选择包含DICOM图像集的文件夹的外观。 选择好路径后, 一个或多个系列应出现在“选择路径”按钮下方。 突出显示一个系列,然后单击“加载”。 DICOM 图像集现在应该被加载。 图像切片和阈值可以变化。 屏幕...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,689
精华内容 2,275
关键字:

DICOM图像