图像处理系统的分析工具
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像处理系统的分析工具相关的知识,希望对你有一定的参考价值。
参考技术A图像处理和分析工具主要功能是进行图像增强,便于后续的专业视觉工具进行识别和理解。常用的图像处理和分析工具包括:直方图工具、滤波操作、形态学操作、轮廓提前、几何变换、颜色空间变换。从输出关系角度,可将基本图像预处理算法分为:点变换算法、领域操作算法。
直方图分析
直方图分析是最基本的图像分析工具,直方图可对图像的整体灰度分布进行刻画,主要指标包括:均值、标准差等。
滤波操作
滤波是最常用使用的图像增强方法,主要包括:低通滤波、高通滤波、边缘检测、高斯滤波等。
形态学操作
形态学操作是常用的图像增强方法:主要包括:膨胀、腐蚀、开启、闭合、中值滤波等。
轮廓提取
轮廓是图像的重要边缘特征,轮廓提取的精度、速度和稳定性是轮廓提取工具的主要评价标准。
几何变换
常用的几何变换包括:旋转、平移、尺度、切变等,其统称为仿射变换。仿射采样也为集合变换范畴。
颜色空间转换
图像处理技术从图像格式上可以分为灰度图像处理和彩色图像处理。在图像处理技术发展的早期,由于受计算机处理能力的限制,图像处理技术领域的研究主要集中在灰度图像处理技术。随着计算机处理能力的飞速发展,彩色图像处理技术越来越受到关注。彩色图像处理相比灰度图像处理存在很多优势,其中最重要的有两点:(1)彩色图像所包含的信息量比灰度图像丰富很多(2)彩色图像更加符合人的视觉习惯。
一般情况下,相机输出的颜色数据为RGB颜色空间数据。然而,在工业用用中,经常需要再CIE色度学空间、人类视觉空间或者OD颜色密度空间进行彩色图像处理。颜色空间转换即指由RGB颜色空间到CIE LAB空间、CIE LCH空间、HSI空间、HSL空间以及OD颜色密度空间转换。
DICOM医学图像处理:基于DCMTK工具包学习和分析worklist
背景:
DICOM3.0协议中有介绍关于worklist的部分。简而言之,worklist可以看做是放射科设备从医院RIS系统中自动读取患者信息的一种“通信协议”,可以指存储在RIS系统中的患者数据库,主要包括患者的基本信息(如年龄、性别、身高、体重、出生年月等),这与DCM文件信息头MetaInfo中的多数字段重合。因此从RIS系统中自动获取worklist是医院信息化的必要组成部分。下面简单的给出几个图像,形象的描述一下worklist的作用。
worklist的实例学习:
在简单的了解了worklist的作用后,下面我们利用DCMTK提供的工具包(wlmscpfs.exe和findscu.exe)来真实模拟一下该场景,从而更深刻的学习worklist的功能。
worklist简单的看做一种“通讯”,那么自然就存在着通讯的两端,暂且称作“服务端”和“客户端”。这里我们用wlmscpfs.exe来作为worklist通讯的服务端,即等待外部访问的终端;用findscu.exe来作为服务端,用来发起worklist访问。
首先简单的介绍一下工具包的指令及使用方式。wlmscpfs.exe是类似于DOS时代的命令,通过设定参数可以实现不同的目的。利用Win+R键开启操作系统的运行窗口,输入cmd后进入到命令提示行窗口。然后进入到DCMTK编译后的bin文件夹(我本机地址是C:\\Program Files (x86)\\DCMTK\\bin)目录,此时直接输入wlmscpfs.exe就可以看到关于该命令工具的各种说明。
>cd C:\\Program Files (x86)\\DCMTK\\bin
>wlmscpfs.exe
(注,此处如果为了省事,可以将bin文件夹路径添加到windows的环境变量中,如是就可以在任何目录下使用bin下的各种工具了)
由上图看到,wlmscpfs.exe工具至少需要给出port一个参数,即开启worklist服务的本机端口号。另外还需要输入worklist数据库文件的地址,用来供客户端查询、访问使用。下面我们正式开启worklist的服务端程序,至于开启全过程,可以跟大家推荐CSDN一位博主的精品文章(http://blog.csdn.net/pachleng/article/details/5800513),博文中给出了具体的操作步骤,这个实例是对DCMTK论坛中的补充和更新。大家可以动手试一下。
第一步:建立各级目录
以我的电脑为例,我在D盘创建了DCMWorklist文件夹,然后建立了两个子文件夹wlistdb和wlistqry。
第二步:准备worklist数据库文件,开启worklist服务端服务。
然后将worklist的数据库文件拷贝到wlistdb目录下,此处参见冷哥博文,记得建立OFFIS子目录。至于worklist数据库文件通常在dcmtk库的源码中已经给出了,默认目录是dcmtk-3.6.0\\dcmtk-3.6.0\\dcmwlm\\datawlistdb(我用的是3.6.0版本)。但是源码中的文件通常是.dump扩展名的文件,也就是我们常见的文本文件(用记事本或者Notepad++等工具双击即可打开)。通过利用dcmtk工具包中的dump2dcm.exe可以将.dump文件转换成.wl文件,转换后的.wl文件就是worklist数据库文件。
>dcmp2dcm.exe .\\dcmtk-3.6.0\\dcmtk-3.6.0\\dcmwlm\\data\\wklistdb\\wlist1.dump d:\\DCMWorklist\\wlistdb\\OFFIS\\wlist.wl
>……
有了worklist数据库文件后,我们就可以开启worklist服务了,利用的工具就是前文提到的wlmscpfs.exe(从工具名称中的SCP就可以看出这应该是服务端开启服务的)。
>wlmscpfs.exe –d –dfr –dfp d:\\DCMWorklist\\wlistdb 104 (注:其中的-d是为了方便我们观察工具运行过程而开启的调试开关)
>……
第三步,准备查询文件,开启worklist查询。
服务端已经准备就绪,下面就是该发起worklist查询服务啦。利用的工具是findscu.exe(从工具名称中的SCU同样可以猜测出这是客户端)。dcmtk源码包中同样给我们提供了查询worklist的查询文件,默认目录是dcmtk-3.6.0\\dcmtk-3.6.0\\dcmwlm\\data\\wlistqry,打开后可以看到里面以.dump格式存在的文件,再次利用dump2dcm.exe将.dump转换为.wl文件。
>dcmp2dcm.exe .\\dcmtk-3.6.0\\dcmtk-3.6.0\\dcmwlm\\data\\wklistqrt\\wlistqry1.dump d:\\DCMWorklist\\wlistqry\\wlistqry.wl
然后我们利用findscu发起查询请求,
>findscu.exe –d 127.0.0.1 104 d:\\DCMWorklist\\wlistqry\\wlistqry.wl –aec OFFIS
其中aec代表的是被请求或者说被呼叫的应用端的名称,即我们wlistdb文件夹内的OFFIS子文件夹。
通过以上三步,我们就简单的利用dcmtk提供的wlmscpf.exe和findscu.exe工具包以及相应的wklistdb数据库文件和wklistqry数据库查询文件模拟了worklist服务开启及查询的整个流程。是不是很简单,很容易上手。
实际结果分析:
上一部分中提到了在使用wlmscpfs.exe和findscu.exe工具包的时候开启了-d调试模式,目的就是为了方便我们跟踪整个通讯的流程。另外为了方便查看,我们利用重定向技术,将wlmscpfs.exe和findscu.exe工具包的调试信息输出到txt文件,方便我们事后进行再次对比查看。下面将两个工具包的调试信息用Notopad++打开,对比分析一下,见下图:
从调试信息可以清晰的看到wlmscpfs.exe与findscu.exe之间的通信流程,该流程在DICOM3.0标准的第四部分(Service Class Specifications )和第八部分(Network Communication Support for Message Exchange)都有详细的介绍,上述的重定向生成的文本文档就是学习DICOM3.0第四、八部分最好的实例。因为dcmtk是开源的,所以这方便我们分析wlmscpfs.exe和findscu.exe两个工具包的源码。具体分析见下一节。
wlmscpfs.exe和findscu.exe工具包源码分析:
wlmscpfs.exe | findscu.exe | |
C/S | worklist服务端 | worklist客户端 |
源码文件 | wlmscpfs.cc wlcefs.cc wlmactmg.cc | findscu.cc |
内部函数 | 1)ConnectToDataSource();//开启连接 2)WlmActivityManager(); //函数内部利用WSAStartup()启动了Windows套接字服务 3)StartProvidingService(); //启动worklist管理服务,位于wlmactmg.cc文件。函数内部调用(a)(b)两个函数。 (a)ASC_initializeNetwork()函数 ASC_initializeNetwork函数调用了DICOM协议封装的TCP协议函数DUL_InitializeNetwork(该函数内部就会出现我们在套接字编程中常见的socket、setsockopt、bind和listen函数) (b)WaitForAssociation();函数 WaitForAssociation函数调用了DICOM协议封装的TCP/IP协议函数receiveTransportConnectionTCP(该函数内部利用的是select端口模式,会出现套接字编程中常见的select、accept函数) 4)disconnectfromDataSource(); //断开连接的函数。 | 1)WSAStartup();//初始化套接字服务 2)DcmFindSCU::initializeNetWork(); //函数内部调用的也是ASC_initializeNetwork函数。 3)DcmFindSCU::performQuery(); //同样该函数内部封装了很多以DUL开头的协议操作函数。DUL是DICOM Upper Layer 的缩写。 4)WSACleanup(); |
从上述分析中我们基本可以看出,worklist的通讯是建立在TCP/IP这一现有协议之上的,可以说是对协议的二次封装。与我们平时进行套接字编程的基本流程相似,搞清楚了这一点,对于分析工具包、学习工具包的使用都会有很大的帮助。
worklist数据库文件或查询文件(*.wl)的生成:
1)问题提出:
参照冷哥博文(http://blog.csdn.net/pachleng/article/details/5800513、http://blog.csdn.net/pachleng/article/details/5827232)中的说明,我们可以很容易的利用DCMTK的工具包学习worklist操作。但是在实际应用模仿过程中,有的人可能会好奇为什么要把wklist.wl和wklistqry.wl文件分别放在不同目录?为什么同为以.wl为扩展名的文件,一个就可以作为worklist的数据库文件放在服务端,而另一个就是客户单的查询文件?如果想发起自己的查询,即C-FIND请求,我们怎么手动生成wklistqry.wl文件?
针对上述问题,在dcmtk的论坛中也曾经有人提到过,参见(http://forum.dcmtk.org/viewtopic.php?f=1&t=1475&hilit=wlmscpfs.exe%23p5016)。利用UltraEdit工具将wklist.wl和wklistqry.wl文件同时打开,对比如下:
从上图中可以看出,作为worklist客户端数据库文件的wklist.wl中是将患者真实信息以符合DICOM3.0标准字段的形式存储,而客户端发起查询请求的wklistqry.wl文件内部只是简单的需要查询的空字段,即各个字段的值域都为空。参考博文中给出了利用dump2dcm.exe工具包将.dump文件转换成wklistqry.wl文件(dump可以认为是普通的文本文件,可以利用记事本等工具进行直接编辑)。如下图所示:
例如作为测试用的wlist-2.dump文件中的患者ID为123456,生成后的wlist-2.wl文件中的(0010,0020)字段也是123456。
2)实际测试:
从dump2dcm.exe工具包的说明我们就可以知道,.wl文件其实就是dcm文件,只是该类文件中并不存在真实的像素信息。通常只包含信息头部分,主要指的是患者的各项信息。因此想利用dcmtk的库函数直接获取.wl文件,其实就是手动构造dcm文件的过程。参见http://support.dcmtk.org/docs/mod_dcmdata.html#Examples中的第二个例子,我们可以手动生成以“.wl”为后缀的dcm文件。具体的代码如下:
#include <stdio.h>
#include <tchar.h>
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/dcmdata/dcpxitem.h"
#include "dcmtk/dcmjpeg/djdecode.h"
#include "dcmtk/dcmjpeg/djencode.h"
#include "dcmtk/dcmjpeg/djcodece.h"
#include "dcmtk/dcmjpeg/djrplol.h"
using namespace std;
int main()
char uid[100];
DcmFileFormat fileformat;
DcmDataset *dataset = fileformat.getDataset();
/**********************************************
*
*利用下列语句可以生成worklist的数据库文件,即
*不含有影像信息的dcm文件
*
************************************************/
dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
dataset->putAndInsertString(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT));
dataset->putAndInsertString(DCM_PatientName, "Doe^John");
OFCondition status = fileformat.saveFile("D:\\\\DcmWorklist\\\\worklist\\\\test.wl", EXS_LittleEndianExplicit);
if (status.bad())
cerr << "Error: cannot write DICOM file (" << status.text() << ")" << endl;
return 0;
既然服务端需要的worklist数据库文件和客户端需要的查询文件都是.wl文件,唯一的区别就是一个有值域,一个没有。因此利用上述代码我们既可以生成worklist数据库文件,也可以生成worklist查询文件。
3)测试结果:
查看findscu.exe工具包,我们可以找到-k选项,也就是在提供了查询文件wklistqry.wl的同时也可以指定限定的查询字段,例如
>findscu 127.0.0.1 104 -v -k 0010,0020="123456" -aec OFFIS wlistqry.wl
如果不添加-k 0010,0020=“123456”限定选项,查询结果如前文中重定向的结果相同,而添加了限定字段后,我们能够查询到的就只有数据库端中满足PatientID字段为123456的患者数据。具体结果如下:
从中我们可以看到服务端给我们的反馈是PatientID为123456的患者信息,所返回的信息都是wlistqry.wl文件中要求的字段,其中通过-k 0010,0020=“123456”限定项来限定了查询的结果,在服务端的反馈是两个患者中表明有一个匹配的worklist数据库文件,如上图中黄色区域所示。
猜想:既然我们可以利用dcmtk自由生成客户端的.wl查询文件,而-k 0010,0020=”123456”就是对该查询文件的补充,那么是不是如果我们直接把123456写入到wlistqry.wl中的(0010,0020)字段的值域,而直接利用修改后的查询文件也会得到相同的结果呢?此处利用自己的代码将0010,0020字段的值域填充为123456
#include <stdio.h>
#include <tchar.h>
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/dcmdata/dcpxitem.h"
#include "dcmtk/dcmjpeg/djdecode.h"
#include "dcmtk/dcmjpeg/djencode.h"
#include "dcmtk/dcmjpeg/djcodece.h"
#include "dcmtk/dcmjpeg/djrplol.h"
using namespace std;
int main()
char uid[100];
DcmFileFormat fileformat;
DcmDataset *dataset = fileformat.getDataset();
/**********************************************
*【猜测一】:
*利用下列语句可以生成worklist的查询文件
*即,
* 各个字段数据都为空的dcm文件
************************************************/
dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
dataset->putAndInsertString(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT));
dataset->putAndInsertString(DCM_ImplementationVersionName,"OFFIS_DCMTK_361");
dataset->putAndInsertString(DCM_SpecificCharacterSet,"");
dataset->putAndInsertString(DCM_PatientName, "");
dataset->putAndInsertString(DCM_PatientID,"123456");
dataset->putAndInsertString(DCM_PatientBirthDate,"");
dataset->putAndInsertString(DCM_PatientSex,"");
OFCondition status = fileformat.saveFile("D:\\\\DcmWorklist\\\\worklist\\\\testqry.wl", EXS_LittleEndianExplicit);
if (status.bad())
cerr << "Error: cannot write DICOM file (" << status.text() << ")" << endl;
return 0;
然后利用
>findscu 127.0.0.1 104 -v -aec OFFIS testqry.wl 指令直接发起查询。
查询结果反馈如下图所示:
上图证明了我们的猜想,通过写入wlistqry.wl的相关字段的值域,就等同于在findscu.exe指令中添加-k XXXX,XXXX限定选项。
至此我们详细的介绍了如何模拟worklist的双端服务,如何开启服务端服务、发起客户端查询,关键是对如何利用dcmtk的库函数来生成自定义的查询端.wl文件进行了补充设实例测试。
(完)
时间:2014-08-23
以上是关于图像处理系统的分析工具的主要内容,如果未能解决你的问题,请参考以下文章