DICOM医学图像处理:开源库mDCM与DCMTK的比较分析(一),JPEG无损压缩DCM图像(续)...
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
背景:
? ? ? ? 上周通過(guò)單步調(diào)試,找出了開(kāi)源庫(kù)mDCM與DCMTK在對(duì)DICOM圖像進(jìn)行JPEG無(wú)損壓縮時(shí)的細(xì)小區(qū)別,并順利實(shí)現(xiàn)了在C++和C#環(huán)境下對(duì)DICOM圖像的壓縮。但是問(wèn)題接踵而至啊,隨著項(xiàng)目的深入,發(fā)現(xiàn)在單獨(dú)的測(cè)試工程中可以實(shí)現(xiàn)的mDCM版本,在嵌入到項(xiàng)目整體中后,卻意外地出現(xiàn)了錯(cuò)誤,并未順利實(shí)現(xiàn)DICOM圖像的JPEG無(wú)損壓縮。因此需要繼續(xù)詳細(xì)對(duì)比分析mDCM與DCMTK兩者,期望尋找原因。
問(wèn)題分析:
? ? ? ? 開(kāi)啟項(xiàng)目的日志功能后,得到的信息反饋為:
No registered codec for transfer syntax! 在 Dicom.Data.DcmDataset.ChangeTransferSyntax(DicomTransferSyntax newTransferSyntax, DcmCodecParameters parameters),在…………………………處。
? ? ? ? 從日志得到的反饋來(lái)看,應(yīng)該是JPEG的編碼器注冊(cè)失敗。而編碼器部分包含在mDCM開(kāi)源庫(kù)的Dicom.Codec64.dll程序集中。因此單步調(diào)試進(jìn)入,查看工程是否順利加載了Dicom.Codec64.dll模塊。
? ? ? ? 首先單步進(jìn)入的是上周測(cè)試用的獨(dú)立工程JpegLossLess,通過(guò)在Program.cs中調(diào)用Dicom.Codec.DicomCodec.RegisterCodecs();使得程序進(jìn)入到DicomCodec.cs文件,程序運(yùn)行到靜態(tài)類DicomCodec的靜態(tài)方法RegisterCodecs內(nèi)。
? ? ? ? 如上圖所示,方法RegisterCodecs內(nèi)部通過(guò)C#的程序集的動(dòng)態(tài)加載和反射技術(shù),順利識(shí)別了工程引用中添加的Dicom.dl程序集和Dicom.Codec64.dll程序集。
接下來(lái)單步調(diào)試到整體工程中,程序從主框架轉(zhuǎn)移到我們手動(dòng)添加的調(diào)用Dicom.Codec.DicomCodec.RegisterCodecs();函數(shù)處,如下圖所示:
? ? ? ? ?經(jīng)過(guò)幾次的調(diào)試發(fā)現(xiàn),使用RegisterCodecs函數(shù)并未順利的注冊(cè)JPEG編碼器,識(shí)別出的17個(gè)程序集中只有Dicom.dll模塊。通過(guò)瀏覽DicomCodec.cs文件源碼發(fā)現(xiàn),RegisterCodecs函數(shù)是靜態(tài)類DicomCodec的靜態(tài)函數(shù),該函數(shù)實(shí)現(xiàn)的是自動(dòng)注冊(cè)JPEG所有編碼器。繼續(xù)瀏覽發(fā)現(xiàn),靜態(tài)類DicomCodec還有類似的其它函數(shù),如public static void RegisterCodec(DicomTransferSyntax ts, Type type);和public static void RegisterExternalCodecs(string path, string pattern);兩個(gè)函數(shù),分別是注冊(cè)指定傳輸語(yǔ)義的解碼器和注冊(cè)指定路徑下的程序集中的解碼器。由于我們利用RegisterCodecs函數(shù)并未實(shí)現(xiàn)自動(dòng)加載JPEG解碼器的功能,而且工程中已經(jīng)添加引用了DicomCodec64.dll程序集,并且在調(diào)試時(shí)刻VS2012的模塊窗口已經(jīng)顯示順利加載了DicomCodec64.dll程序集。所以此時(shí)決定嘗試手動(dòng)加載DicomCodec64.dll程序集,即用下面的代碼替換原本的Dicom.Codec.DicomCodec.RegisterCodecs();語(yǔ)句,
? ? ? ?string path = System.IO.Directory.GetCurrentDirectory();
?????? string pattern = "Dicom.Codec64.dll";
?????? DicomCodec.RegisterExternalCodecs(path, pattern);
? ? ? ? 此刻單步調(diào)試可以看到,已經(jīng)成功的實(shí)現(xiàn)了DicomCodec64.dll程序集中JPEG解碼器的注冊(cè),完成了將DICOM圖像JPEG壓縮的功能與整體工程的整合。
學(xué)習(xí)總結(jié):
1)GetReferencedAssemblies函數(shù)能否返回工程中的所有引用程序集?
? ? ? ? 通過(guò)對(duì)比上述的自動(dòng)和手動(dòng)的注冊(cè)代碼,發(fā)現(xiàn)兩者的最終都是利用的GetExportedTypes函數(shù)來(lái)完成注冊(cè),具體代碼都是Type[] types = asm.GetExportedTypes();來(lái)提取相應(yīng)的解碼器,唯一不同的是自動(dòng)注冊(cè)中是利用AssemblyName[] referenced = main.GetReferencedAssemblies();提取該模塊的引用程序集,而手動(dòng)注冊(cè)是利用的Assembly.LoadFile函數(shù)加載手動(dòng)指定的程序集文件,難道是GetReferencedAssemblies函數(shù)出現(xiàn)了問(wèn)題?GetReferencedAssemblies函數(shù)到底能不能返回我們工程中所有的引用程序集呢?
? ? ? ? 在MSDN搜索一下GetReferencedAssemblies函數(shù)的功能,描述為:Gets the AssemblyName objects for all the assemblies referenced by this assembly.
乍一看,好像該函數(shù)是可以返回我們工程中所有加載的程序集的名稱。但是仔細(xì)分析一下,描述中提到的是"this assembly”,此處this 應(yīng)該指的是調(diào)用RetReferencedAssemblies函數(shù)的程序集,因此該函數(shù)應(yīng)該獲得的是當(dāng)前模塊所引用的所有程序集,而并不是我們起初認(rèn)為的整個(gè)工程的引用程序集。經(jīng)過(guò)漫長(zhǎng)的搜索,終于在一篇stackoverflow的博文(http://stackoverflow.com/questions/3971793/what-when-assembly-getreferencedassemblies-returns-exe-dependency)中找到了對(duì)“提取工程所有依賴程序集”的相關(guān)說(shuō)明,文中作者不僅給出了實(shí)現(xiàn)的方法,而且給出了為什么GetReferencedAssemblies函數(shù)沒(méi)有返回工程所有引用程序集的原因(http://msdn.microsoft.com/en-us/magazine/cc163641.aspx)。此處簡(jiǎn)單的對(duì)其歸納一下,并借用一下原作者的圖:
? ? ? ? 如下圖所示,假設(shè)我們?cè)谀KA中調(diào)用了GetReferencedAssemblies函數(shù),那么按照MSDN中對(duì)應(yīng)的解釋,函數(shù)應(yīng)該返回this——即A所引用(更確切的說(shuō)是直接應(yīng)用)的程序集B、C、D。然而如下圖左所示,程序集C和D又分別引用了其他的程序集,所以此處我們并未直接獲取到整個(gè)工程中所有的程序集。因此自動(dòng)加載的時(shí)候并未順利的返回我們需要的Dicom.Codec64程序集。
? ? ? ? 說(shuō)到這里,我想提取工程所有引用程序集的方法已經(jīng)呼之欲出了,最簡(jiǎn)單的就是我們可以對(duì)GetReferencedAssemblies的首次返回值進(jìn)行遞歸調(diào)用,那么自然而然就可以得到所有的引用程序集A-J。但是博文中作者是按照上圖右中的方式來(lái)提取所有引用程序集的,因?yàn)檫f歸會(huì)影響程序的性能,尤其是程序模塊眾多的時(shí)候。簡(jiǎn)言之,就是利用算法導(dǎo)論中的“前序遍歷”來(lái)提取所有的引用程序集,具體代碼可以從給出的參考博文下載。
2)C#的靜態(tài)類與Singleton設(shè)計(jì)模式
? ? ? ? 在對(duì)比mDCM與DCMTK兩個(gè)開(kāi)源庫(kù)對(duì)于JPEG解碼器注冊(cè)的源代碼后,發(fā)現(xiàn)在用C++完成的DCMTK開(kāi)源庫(kù)中,使用的是Singleton設(shè)計(jì)模式的DcmCodecList類來(lái)完成JPEG各種解碼器注冊(cè)的,而用C#編寫(xiě)的mDCM開(kāi)源庫(kù)使用的是C#的靜態(tài)類public static DicomCodec。這兩種方式可以實(shí)現(xiàn)相同的功能,由于剛開(kāi)始從C++轉(zhuǎn)向C#,對(duì)于這兩者的區(qū)別不是很清楚,因此搜索了一下,僅摘取部分重要片段貼在博文中,便于以后查閱。
【摘要1】:http://bbs.csdn.net/topics/370008452
除了跨程序集的邊界問(wèn)題,static 類和模仿 GoF C++ 版的單件沒(méi)有本質(zhì)的區(qū)別。我感興趣的討論在于這兩者在滿足同樣的動(dòng)機(jī)的情況下,是否達(dá)成了同樣的效果,我個(gè)人的看法是,靜態(tài)類有簡(jiǎn)單和優(yōu)雅的一面。事實(shí)上,在Java和C#方面,GoF的設(shè)計(jì)模式本身有問(wèn)題,這就是經(jīng)典的Double Lock Check問(wèn)題(看 CLR via C#)。
粗略地說(shuō),在C# 4中,這些模式消失了:單件(靜態(tài)類)、策略(委托和Lambda)、觀察者(事件)、裝飾(擴(kuò)展方法)、工廠(部分靠反射實(shí)現(xiàn))、代理(表達(dá)式樹(shù)和動(dòng)態(tài)類)、迭代器(yield return語(yǔ)法),等等,如果你按照GoF的實(shí)現(xiàn)來(lái)做這些,你反而舍近求遠(yuǎn)了。
最后,不光是 singleton,我對(duì)設(shè)計(jì)模式一個(gè)普遍的看法是,隨著編程語(yǔ)言的進(jìn)步,所有設(shè)計(jì)模式的實(shí)現(xiàn)都將消亡,而思想保存了下來(lái)。設(shè)計(jì)模式的本質(zhì)也可以說(shuō)是為了修飾語(yǔ)言的缺陷,一種優(yōu)雅的語(yǔ)言,不需要設(shè)計(jì)模式(這個(gè)觀點(diǎn)是我一個(gè)大學(xué)同學(xué)提出的,他也是一位 Ruby 社區(qū)的專家)。
【摘要2】:http://www.cnblogs.com/utopia/archive/2010/03/02/1676390.html
靜態(tài)類的語(yǔ)義是全局唯一代碼段,而單件的語(yǔ)義是全局唯一對(duì)象實(shí)例;
語(yǔ)義上是完全不同地,不能說(shuō)起修飾都是“全局唯一”就放一塊比較;
如果是這樣那么所有public修飾的東西我們不是都得比較一翻了;
另外:如果要研究對(duì)象設(shè)計(jì),那么請(qǐng)先拋開(kāi)代碼。對(duì)象設(shè)計(jì)是本身哲學(xué)性和世界觀的表達(dá)。
如何把現(xiàn)實(shí)的東西用概念還原表達(dá)出來(lái),才是對(duì)象設(shè)計(jì)的實(shí)質(zhì)。而代碼則是體現(xiàn)你頭腦里那個(gè)概念模型的工具。
【摘要3】:http://blog.csdn.net/lyrebing/article/details/1902235
單例模式的目的是為了在程序中提供類的唯一實(shí)例,而且僅提供唯一的訪問(wèn)點(diǎn)。靜態(tài)不需要實(shí)例,僅提供一個(gè)全局功能。使用單例可以繼承,實(shí)現(xiàn)接口,而靜態(tài)類不能。靜態(tài)方法不能訪問(wèn)類中的實(shí)例字段,因?yàn)殪o態(tài)方法不是通過(guò)實(shí)例來(lái)訪問(wèn)的。而單例中的方法卻可以訪問(wèn)那個(gè)唯一實(shí)例中的實(shí)例字段。靜態(tài)方法在執(zhí)行后,會(huì)釋放掉它所創(chuàng)建的所有對(duì)象。而單例中的方法卻可以保留。靜態(tài)字段僅是提供全局的功能,大家共享同一內(nèi)存位置。訪問(wèn)單例中的字段是類的唯一實(shí)例中的字段,大家只能訪問(wèn)這個(gè)實(shí)例的字段。
?
作者:zssure@163.com
時(shí)間:2014-08-17
轉(zhuǎn)載于:https://my.oschina.net/zssure/blog/354805
總結(jié)
以上是生活随笔為你收集整理的DICOM医学图像处理:开源库mDCM与DCMTK的比较分析(一),JPEG无损压缩DCM图像(续)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Redis缓存 ava-Jedis操作R
- 下一篇: 快速批量导入庞大数据到SQL SERVE