当前位置:   article > 正文

DICOM笔记-解析JPEG压缩格式DCM文件_.net 解压缩dcm

.net 解压缩dcm

  项目中使用了DICOM文件保存图像,之前经常遇到DICOM内放置的是short类型或者float类型的二维图像,按照之前的代码处理JEPG压缩的DICOM文件,当然会出现问题;从网上查到资料,是由于JEPG需要解码器;
  把我处理的过程记录下来,以供大家参考;

JPEG格式

  JPEG的全称是JointPhotographicExpertsGroup(联合图像专家小组),它是一种常用的图像存储格式, jpg/jpeg是24位的图像文件格式,也是一种高效率的压缩格式,文件格式是JPEG(联合图像专家组)标准的产物,该标准由ISO与CCI TT(国际电报电话咨询委员会)共同制定,是面向连续色调静止图像的一种压缩标准。
  JPEG格式可以分为标准JPEG、渐进式JPEG和JPEG2000三种格式。

标准JPEG

  该类型的图片文件,在网络上应用较多,只有图片完全被加载和读取完毕之后,才能看到图片的全貌;它是一种很灵活的图片压缩方式,用户可以在压缩比和图片品质之间进行权衡。不过,通常来讲,其压缩比在10:1到40:1之间,压缩比越大,品质就越差,压缩比越小,品质就越好。JPEG格式压缩的主要是高频信息,对色彩的信息保留较好,适合应用于互联网,可减少图像的传输时间,可以支持24bit真彩色,也普遍应用于需要连续色调的图像。JPEG由于可以提供有损压缩,因此压缩比可以达到其他传统压缩算法无法比拟的程度。其压缩模式有以下几种:顺序式编码(SequentialEncoding),递增式编码(ProgressiveEncoding),无失真编码(LosslessEncoding)和阶梯式编码(HierarchicalEncoding)
  JPEG的压缩,分为四个步骤:
    (1)颜色转换:由于JPEG只支持YUV颜色模式,而不支持RGB颜色模式,所以在将彩色图像进行压缩之前,必须先对颜色模式进据转换。转换完成之后还需要进行数据采样。一般采用的采样比例是2:1:1或4:2:2。由于在执行了此项工作之后,每两行数据只保留一行,因此,采样后图像数据量将压缩为原来的一半。
    (2)DCT变换:DCT(DiscreteConsineTransform)是将图像信号在频率域上进行变换,分离出高频和低频信息的处理过程。然后再对图像的高频部分(即图像细节)进行压缩,以达到压缩图像数据的目的。首先将图像划分为多个8*8的矩阵。然后对每一个矩阵作DCT变换(变换公式此略)。变换后得到一个频率系数矩阵,其中的频率系数都是浮点数。
    (3)量化:由于在后面编码过程中使用的码本都是整数,因此需要对变换后的频率系数进行量化,将之转换为整数。由于进行数据量化后,矩阵中的数据都是近似值,和原始图像数据之间有了差异,这一差异是造成图像压缩后失真的主要原因。
    (4)编码:编码采用两种机制:一是0值的行程长度编码;二是熵编码(EntropyCoding)。在JPEG中,采用曲徊序列,即以矩阵对角线的法线方向作“之”字排列矩阵中的元素。这样做的优点是使得靠近矩阵左上角、值比较大的元素排列在行程的前面,而行程的后面所排列的矩阵元素基本上为0值。行程长度编码是非常简单和常用的编码方式,在此不再赘述。编码实际上是一种基于统计特性的编码方法。在JPEG中允许采用HUFFMAN编码或者算术编码。

渐进式JPEG

  该类型的图片是对标准JPEG格式的改进,当在网页上下载渐进式JPEG图片时,首先呈现图片的大概外貌,然后再逐渐呈现具体的细节部分,因而被称之为渐进式JPEG。

JPEG2002

  一种全新的图片压缩发,压缩品质更好,并且改善了无线传输时,因信号不稳定而造成的马赛克及位置错乱等问题。另外,作为JPEG的升级版,JPEG2000的压缩率比标准JPEG高约30%,同时支持有损压缩和无损压缩。它还支持渐进式传输,即,先传输图片的粗略轮廓,然后,逐步传输细节数据,使得图片由模糊到清晰逐步显示。此外,JPEG2000还支持感兴趣区域,也就是说,可以指定图片上感兴趣区域的压缩质量,还可以选择指定的部分先进行解压。

DCMTK解析JPEG格式DCM文件

  从DICOM文件的0x0002,0x0010的tag可以看到“JPEG lossless”;
在这里插入图片描述
  dcmjpeg提供了一个压缩/解压缩库以及可用工具。该模块包含一些类,可将DICOM图像对象在非压缩和JPEG压缩表示(传输协议)之间转换。无失真和有失真JPEG处理都被支持。这个模块实现了一族codec(编码解码器,由DcmCodec类派生而来),可以将这些codec在codec list中注册,codec list是由dcmdata模块保存的。
  主要接口类:
    DJEncoderRegistration: 一个singleton单例类,为所有支持的JPEG处理注册编码器。在djencode.h中定义。
    DJDecoderRegistration: 一个singleton单例类,为所有支持的JPEG处理注册解码器。在djdecode.h中定义。
    DJCodecEncoder: JPEG编码器的一个抽象codec类,在djcodece.h中定义
    DJCodecDecoder: JPEG解码器的一个抽象codec类。
在程序的开始位置,首先注册JPEG的解码器;

	DJEncoderRegistration::registerCodecs(
		ECC_lossyYCbCr,
		EUC_default, // UID generation (never create new UID's)
		OFFalse, // verbose
		0, 0, 0, true, ESS_444, true); // optimize huffman table
	DJDecoderRegistration::registerCodecs();
	DJLSEncoderRegistration::registerCodecs();		//JPEG-LS encoder registerCodecs
	DJLSDecoderRegistration::registerCodecs();		//JPEG-LS decoder registerCodecs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

  在程序的结束位置,释放JPEG的解码器;

DJEncoderRegistration::cleanup();
DJDecoderRegistration::cleanup();
DJLSEncoderRegistration::cleanup();		//JPEG-LS encoder cleanup
DJLSDecoderRegistration::cleanup();		//JPEG-LS decoder cleanup
  • 1
  • 2
  • 3
  • 4

  使用到的头文件如下:

#include <dcmtk/dcmjpeg/djdecode.h>  /* for dcmjpeg decoders */
#include <dcmtk/dcmjpeg/djencode.h>
#include <dcmtk/dcmjpls/djdecode.h>		//for JPEG-LS decode
#include <dcmtk/dcmjpls/djencode.h>		//for JPEG-LS encode
  • 1
  • 2
  • 3
  • 4

代码

#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include "dcmtk\config\osconfig.h"
#include "dcmtk\dcmdata\dctk.h"
#include <dcmtk/dcmjpeg/djdecode.h>  /* for dcmjpeg decoders */
#include <dcmtk/dcmjpeg/djencode.h>
#include <dcmtk/dcmjpls/djdecode.h>		//for JPEG-LS decode
#include <dcmtk/dcmjpls/djencode.h>		//for JPEG-LS encode
using namespace std;
using namespace cv;

void ConvertDigitImageToGrayImageByWindowLevelAndWindowWidth(short* digitImage, short* grayImage, int size, int window_level, int window_width){
	double rate = 256.0 / window_width;
	for (size_t i = 0; i < size; i++){
		int tmp = 128.0 + (digitImage[i] - window_level)*rate;
		if (tmp < 0){
			tmp = 0;
		}
		else if (tmp > 255){
			tmp = 255;
		}
		grayImage[i] = tmp;
	}
}
int main()
{
	DJDecoderRegistration::registerCodecs();
	DJLSEncoderRegistration::registerCodecs();		//JPEG-LS encoder registerCodecs
	DJLSDecoderRegistration::registerCodecs();		//JPEG-LS decoder registerCodecs

	DcmFileFormat *myFileFormat = new DcmFileFormat;
	OFCondition cond = myFileFormat->loadFile("G:\\Data\\1.DCM");
	if (cond.good()){
		OFString patientName;
		if (myFileFormat->getDataset()->findAndGetOFString(DCM_PatientName, patientName).good())
			std::cout << "Patient Name: " << patientName << "\nTest successed.\n";
		else 
			std::cout << "No Patient Name Data!\n";
	}
	else 
		std::cout << "Error occurs when opening file, check path or filename.\n";
	
	short* pix_buf = new short[512 * 512];
	unsigned long size = 0;	

	DcmElement* pElement = nullptr;
	myFileFormat->getDataset()->chooseRepresentation(EXS_DeflatedLittleEndianExplicit, NULL);
	myFileFormat->getDataset()->findAndGetElement(DCM_PixelData, pElement);
	if (pElement != NULL) {
		size = pElement->getLength()/2;
		OFCondition cond = pElement->loadAllDataIntoMemory();
		if (cond.good()) {
			Uint16 * ptr;
			cond = pElement->getUint16Array(ptr);
			if (cond.good()) {
				ConvertDigitImageToGrayImageByWindowLevelAndWindowWidth((short*)ptr, pix_buf, size, 1000, 500);
			}
		}
	}

	Mat img = cv::Mat::zeros(512, 512, CV_8UC3);

	for (int i = 0; i < size; i++) {
		uchar* grayrowptr = img.ptr<uchar>(i / 512);//提取行指针
		grayrowptr[i % 512 * 3 + 0] = pix_buf[i];
		grayrowptr[i % 512 * 3 + 1] = pix_buf[i];
		grayrowptr[i % 512 * 3 + 2] = pix_buf[i];
	}
	cv::imwrite("G:\\Data\\gray_9zxr.bmp", img);
	
	imshow("Image", img);
	waitKey(0);
	
	system("pause");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

  使用的DICOM文件中图像数据放到了元素组内,需要使用findAndGetElement获取;
在这里插入图片描述
  DCM文件中数值应该会大于256的灰度值,所以会造成图像的失真,使用窗宽和窗位调整图像显示灰度值,归一化在0-255的范围内,就会显示正常;
在这里插入图片描述
  代码使用的DICOM文件所在位置为:DICOM文件.rar

引用文献

1.jpeg图片格式详解

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/165495?site
推荐阅读
相关标签
  

闽ICP备14008679号