美文网首页
iOS DCMTK-Demo解析dicom文件 窗宽窗位多帧

iOS DCMTK-Demo解析dicom文件 窗宽窗位多帧

作者: 可乐冒气 | 来源:发表于2019-02-20 16:41 被阅读0次

    前言 DICOM -- DCTMK


    DICOM 介绍

    • 医疗数位影像传输协定(DICOM,Digital Imaging and Communications in Medicine)是一组通用的标准协定,在对于医学影像的处理、储存、打印、传输上。它包含了档案格式的定义及网络通信协定。DICOM是以TCP/IP为基础的应用协定,并以TCP/IP联系各个系统。两个能接受DICOM格式的医疗仪器间,可借由DICOM格式的档案,来接收与交换影像及病人资料。

    • DICOM可以整合不同厂商的医疗影像仪器、服务器工作站、打印机和网络设备,使它们都能整合在PACS系统中。许多不同厂商的仪器、服务器、工作站都根据DICOM的标准,来制造支援DICOM机器。DICOM已经广泛地被医院所采用,并且在牙医和一般的诊所中获得小规模的运用。

    DCTMK 介绍

    DCMTK

    此DICOM ToolKit(DCMTK)包由源代码和文档组成
    和一组软件库和安装说明
    实施部分DICOM / MEDICOM标准的应用程序。

    DCMTK包含以下子包,每个子包在其自己的子目录中:

    config  -  DCMTK的配置实用程序
    dcmdata  - 数据编码/解码库和实用程序应用程序
    dcmfg  - 用于处理功能组的库
    dcmimage  - 为dcmimgle添加对彩色图像的支持
    dcmimgle  - 图像处理库和实用程序应用程序
    dcmiod  - 用于处理信息对象和模块的库
    dcmjpeg  - 压缩/解压缩库和实用程序应用程序
    dcmjpls  - 压缩/解压缩库和实用程序应用程序
    dcmnet  - 网络库和实用程序应用程序
    dcmpmap  - 用于处理参数化地图对象的库
    dcmpstat  - 演示文稿状态库和实用程序应用程序
    dcmqrdb  - 图像数据库服务器
    dcmrt  - 放射治疗库和实用程序应用程序
    dcmseg  - 用于处理分段对象的库
    dcmsign  - 数字签名库和实用程序应用程序
    dcmsr  - 结构化报告库和实用程序应用程序
    dcmtls  - 网络库的安全扩展
    dcmtract  - 用于处理纤维束成像结果的库
    dcmwlm  - 模态工作列表数据库服务器
    oflog  - 基于log4cplus的日志库
    ofstd  - 一个通用类库
    

    —— 编译环境 过程
    在编译DCMTK过程中,看到了很多xcode4版本,唯一看到了一个 最新的编译过程 ,这个教程很详细,

    DCTMK 愉快的写了一个Demo

    .h

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    NS_ASSUME_NONNULL_BEGIN
    
    typedef void(^ImgBlock)(UIImage* image);
    @interface dicomHelper : NSObject
    // 加载文件
    -(void)loadFiled:(NSString *)filePath;
    //
    -(void)getDicImage:(SInt32)frame withCenter:(Float64)Wcenter withWidth:(Float64)Wwidth withImg:(ImgBlock)imgBlock;
    
    -(Float64)getWindowCenter;
    -(Float64)getWindowWidth;
    //
    @end
    NS_ASSUME_NONNULL_END
    

    .m

    @interface dicomHelper ()
    @property (nonatomic ,assign)DcmFileFormat *dcmFile;
    @property (nonatomic ,assign)DcmDataset *dataSet;
    @property (nonatomic ,assign)DicomImage *dicomImage;
    @end
    
    @implementation dicomHelper
    -(instancetype)init{
        self = [super init];
        if (self) {
        }
        return self;
    }
    -(void)dealloc{
        /// 删除内存区域 释放内存
        delete _dcmFile;
    //    delete _dataSet;
    //    delete _dcmFile;
    }
    /// 加载影像文件
    - (void)loadFiled:(NSString *)filePath{
        DcmDataDictionary &dict = dcmDataDict.wrlock();
        dict.loadDictionary([[[NSBundle mainBundle] pathForResource:@"private" ofType:@"dic"] cStringUsingEncoding:NSASCIIStringEncoding]);
        dcmDataDict.unlock();
        if (!dcmDataDict.isDictionaryLoaded()) {
            NSLog(@"Data dictionary not loaded");
        } else {
            NSLog(@"Data dictionary loaded!");
        }
    //    DcmRLEDecoderRegistration::registerCodecs(OFFalse /*pCreateSOPInstanceUID*/, OFFalse);
    //    DJDecoderRegistration::registerCodecs(EDC_never, EUC_default, EPC_default, OFFalse);
    //
        self.dcmFile = new DcmFileFormat();
        OFCondition cond = self.dcmFile->loadFile([filePath cStringUsingEncoding:NSASCIIStringEncoding], EXS_Unknown, EGL_withoutGL, DCM_MaxReadLength, ERM_autoDetect);
    
        if (cond.bad()) {
            NSLog(@"Something wrong loading DCM file");
        }
        self.dataSet = self.dcmFile->getDataset();
        
        
        // TODO: 测试 打印的是什么
        const char *transferSyntax;
        DcmMetaInfo *dcmMetaInfo = self.dcmFile->getMetaInfo();
        OFCondition transferSyntaxOfCondition = dcmMetaInfo->findAndGetString(
                                                                              DCM_TransferSyntaxUID, transferSyntax);
        NSLog(@"transferSyntaxOfCondition  %s", transferSyntaxOfCondition.text());
        NSLog(@"transferSyntax  %s", transferSyntax);
    }
    /// 解析影像
    -(void)getDicImage:(SInt32)frame withCenter:(Float64)Wcenter withWidth:(Float64)Wwidth withImg:(nonnull ImgBlock)imgBlock{
        DicomImage *img = [self getDicomImage:frame];
        if (img == NULL) {
            NSLog(@"Out of memory");
            return;
        }
        
        if (img->getStatus() != EIS_Normal)
        {
            const char *msg = DicomImage::getString(img->getStatus());
            NSLog(@"Some other error");
            //        OFLOG_FATAL(dcm2pnmLogger, DicomImage::getString(di->getStatus()));
            return;
        }
        /****/
        DcmStack stack;
        DcmObject *dobject = NULL;
        OFCondition status = self.dataSet->nextObject(stack, OFTrue);
        
        
        dobject = stack.top();
        
        /****/
        //const char *XferText = DcmXfer(xfer).getXferName();
        const char *SOPClassUID = NULL;
        const char *SOPInstanceUID = NULL;
        const char *SOPClassText = NULL;
        const char *colorModel;
        self.dataSet->findAndGetString(DCM_SOPClassUID, SOPClassUID);
        self.dataSet->findAndGetString(DCM_SOPInstanceUID, SOPInstanceUID);
        
        
        colorModel = img->getString(img->getPhotometricInterpretation());
        if (colorModel == NULL)
            colorModel = "unknown";
        if (SOPInstanceUID == NULL)
            SOPInstanceUID = "not present";
        if (SOPClassUID == NULL)
            SOPClassText = "not present";
        else
            SOPClassText = dcmFindNameOfUID(SOPClassUID);
        if (SOPClassText == NULL)
            SOPClassText = SOPClassUID;
        if (img->isMonochrome()) {
            NSLog(@"Is monochrome");
        }
        unsigned long count;
        
        //    di->hideAllOverlays();
        count = img->getWindowCount();
        //    di->setMinMaxWindow(1);
        if (Wwidth == 0 && Wcenter == 0) {
            img->setWindow([self getWindowCenter], [self getWindowWidth]);
        }else{
            img->setWindow(Wcenter, Wwidth);
        }
        NSLog(@"VOI windows in file %ld", count);
        int result = 0;
        
        NSString *cacheFolder = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        NSString *parentFolder = [cacheFolder stringByAppendingPathComponent:@"dicom"];
        
        NSString *filename = [NSString stringWithFormat:@"frame%d.jpg",frame];
    
        NSString *outputFile = [parentFolder stringByAppendingPathComponent:filename];
        FILE *ofile = fopen([outputFile cStringUsingEncoding:NSASCIIStringEncoding], "wb");
        DiJPEGPlugin plugin;
        plugin.setQuality(OFstatic_cast(unsigned int, 90));
        plugin.setSampling(ESS_422);
        result = img->writePluginFormat(&plugin, ofile, 0);
        fclose(ofile);
        UIImage *image = [[UIImage alloc] initWithContentsOfFile:outputFile];
        NSLog(@"-------%@",outputFile);
        imgBlock(image);
        /// 释放内存
        delete img;
    }
    ///获取指定帧的影像对象
    -(DicomImage*)getDicomImage:(Sint32)frameNumber{
        E_TransferSyntax xfer = self.dataSet->getOriginalXfer();
        DJDecoderRegistration::registerCodecs();
    //    DicomImage *dicomImage = new DicomImage(self.dcmFile, xfer, CIF_CheckLutBitDepth, frameNumber,[self getDicmFileFrameNumber]);
    //    _dicomImage = 0;
    //    delete _dicomImage;
        _dicomImage = new DicomImage(self.dcmFile, xfer);
        
        DJDecoderRegistration::cleanup();
    //    NSLog(@"-----%p",_dicomImage);
        if (_dicomImage == NULL) {
            NSLog(@"Out of memory");
            return nil;
        }
        return _dicomImage;
    }
    
    /// 获取文件影像帧数
    -(Sint32)getDicmFileFrameNumber{
       Sint32 frameCount;
        
        if (self.dataSet->findAndGetSint32(DCM_NumberOfFrames, frameCount).bad()) {
            frameCount = 1;
        }
        return frameCount;
    }
    /// 获取i影像患者名称
    -(NSString *)getpatientName{
        OFString patientName;
        OFCondition condition = self.dataSet->findAndGetOFString(DCM_PatientName, patientName);
        if (condition.good()) {
            return [NSString stringWithUTF8String:patientName.c_str()];
        }else{
            return @"NULL";
        }
    }
    /// 获取窗位
    -(Float64)getWindowCenter{
        Float64 windowCenter;
        self.dataSet->findAndGetFloat64(DCM_WindowCenter, windowCenter);
        return windowCenter;
    }
    /// 获取窗宽
    -(Float64)getWindowWidth{
        Float64 windowWidth;
        self.dataSet->findAndGetFloat64(DCM_WindowWidth, windowWidth);
        return windowWidth;
    }
    /// 获取文件影像类型 eg.CT SR...
    -(NSString *)getDicmFileModel{
        const char * model;
        self.dataSet->findAndGetString(DCM_Modality, model);
        return  [NSString stringWithUTF8String:model];
    }
    

    demo源码下载

    相关文章

      网友评论

          本文标题:iOS DCMTK-Demo解析dicom文件 窗宽窗位多帧

          本文链接:https://www.haomeiwen.com/subject/flvhyqtx.html