Background:
Previous blog dicom:dicom Universal editing tools Sante Dicom Editor introduced the DICOM Universal Editing tool, found in the daily use process,"as long as the Sante DICOM Editor cannot open the data, It is basically possible to determine this dicom file format error (accuracy up to 99.9999% ^_^) ". At the same time exclamation Sante DICOM editor Artifact Ox break, want to know how its bottom is realized. It is possible to infer that the underlying dependent library is DCMTK through daily use and reading the software Help manual, as I have experienced compatibility issues with many dicom open source libraries such as DCMTK, fo-dicom, Dcm4che3, etc., with the strongest--DCMTK compatibility, Fo-dicom followed, dcm4che3 the worst .
Problem:
This article analyzes the compatibility of DCMTK, Dcm4che, and fo-dicom data loading by comparing dcmtk3.6 and dcm4che3.x parsing the same special Dicom file ( which contains non-standard VR elements ) Problem.
Special Dicom file content is as follows:
About the The " xx " F8, specifically described below:
There are no errors when loading data with DCMTK and fo-dicom, such as the following when DCMTK loads data:
It can be seen that DCMTK has successfully identified non-standard VR elements (0028,0120), and successfully loaded.
Although there is no error loading data using fo-dicom, the elements after the above non-standard VR element (0028,0120) are not loaded successfully, as shown in:
The error is ejected directly from the Dcm4che3 loading process as follows:
Problem Analysis:
This problem occurs because Dcm4che3 and fo-dicom are not recognized for 20 20 of non-standard VR when parsing the 0028,0120 element. The following will be analyzed by Dcm4che3 and DCMTK source to locate the specific location of the problem and give a solution (here temporarily only comparative analysis of dcm4che3.3.8 the latest version of the source and dmctk3.6, for the fo-dicom source analysis to be completed after the subsequent finishing and then supplemented).
1. dcmtk3.6 Source:
Using DCMTK to write this data load test project, the simple sample code is as follows:
int Main () {oflog::configure (oflogger::trace_ Log_level); char * ifname = "C:\\1.DCM" ; E_filereadmode ReadMode = /*erm_fileonly*/ erm_autodetect; E_transfersyntax Xfer = Exs_unknown; Uint32 maxreadlength = dcm_maxreadlength; bool loadintomemory = true ; Dcmfileformat Dfile; Dcmobject *dset = &dfile; if (ReadMode = = erm_dataset) Dset = Dfile.getdataset (); Ofcondition cond = Dfile.loadfile (ifname, Xfer, Egl_nochange, Maxreadlength, ReadMode); if (Cond.bad ()) {return 1 ; } return 0 ;}
Single-step debugging, you can know the process of DCMTK loading dicom file is as follows:
- Creating Dcmmetainfo, Dcmdataset elements
- Load dcmmetainfo, Dcmdataset elements separately
- Use readgrouplength, Readtagandlength, readsubelement in dcmitem to incrementally load Dcmmetainfo, Dcmdataset the individual child elements.
There are warning messages for non-standard VR elements in the Dcmitem class,
/*ifThe VR which was read isn't a standard VR, print aWarning*/if(!vr.isstandard ()) {Ofostringstream oss; OSS <<"Dcmitem:non-standard VR "<< (ofstatic_cast (unsigned char, vrstr[0]) < +) ?"': vrstr[0]) << (ofstatic_cast (unsigned char, vrstr[1]) < +) ?"': vrstr[1]) <<"' ("<< std_namespace hex << std_namespace setfill (' 0 ') << Std_namespace SETW (2) << ofstatic_cast (unsigned int, vrstr[0] &0xFF) <<"\\"<< Std_namespace SETW (2) << ofstatic_cast (unsigned int, vrstr[1] &0xFF) <<") encountered while parsing element"<< Newtag << ofstringstream_ends; Ofstringstream_getstr (OSS, tmpstring)/* Encoding of this data element might be wrong,TryTo correct it */if(Dcmacceptunexpectedimplicitencoding.get ()) {Dcmdata_warn (tmpstring <<", trying again with implicit VR Little Endian"); /* Put back read bytes to input stream...*/Instream.putback (); Bytesread =0; /*...And retry with implicit VR Little Endian transfer Syntax */returnReadtagandlength (instream, exs_littleendianimplicit, tag, length, bytesread); }Else{Dcmdata_warn (tmpstring <<", assuming"<< (vr.usesextendedlengthencoding)?"4":"2") <<"Byte length field"); } ofstringstream_freestr (Tmpstring)}/* Set the VR which was readinchThe above created tag object. */NEWTAG.SETVR (VR); /* Increase counter by2*/Bytesread + =2;
After the warning, the process for non-standard VR elements is as follows:
/ * Read the value in the Length field. In some cases, it's 4 bytes wide, in other * / /* Cases only 2 bytes (see DICOM Standard Part 5, section 7.1.1) */ if(XFERSYN.ISIMPLICITVR () | | nxtobj = = evr_na)//note that delimitation items don ' t has a VR{Instream.read (&valuelength,4);//length field is 4 bytes wideSwapifnecessary (Glocalbyteorder, Byteorder, &valuelength,4,4); Bytesread + =4; }Else{//the transfer syntax is explicit VRDCMVR VR (NEWTAG.GETEVR ());if(Vr.usesextendedlengthencoding ()) {Uint16 reserved; Instream.read (&reserved,2);//2 reserved bytesInstream.read (&valuelength,4);//Length field is 4 bytes wideSwapifnecessary (Glocalbyteorder, Byteorder, &valuelength,4,4); Bytesread + =6; }Else{Uint16 tmpvaluelength; Instream.read (&tmpvaluelength,2);//Length field is 2 bytes wideSwapifnecessary (Glocalbyteorder, Byteorder, &tmpvaluelength,2,2); Bytesread + =2; Valuelength = Tmpvaluelength; } }
The above code shows that0028,0120 's vr=20,20is parsed by DCMTK as a evr_unknown2b type, as described in the code comment:
Used internally for elements with unknown VR with 2-byte length field in explicit VR
Evr_unknown2b
the 7.1.2 of the dicom standard PS5 has a description of the non-standard VR, as follows:
2. dcm4che3.3.8 Source:
Then compare dcm4che3.3.8 source, single-step debugging found that for 0028,0120 vr=20,20, was DCMTK directly labeled as UN type,
public static VR valueof (int code) {try {VR VR = VALUE_OF[INDEXOF (code)]; if (VR! = null ) return VR; } catch (Indexoutofboundsexception e) {} log.warn ( "Unre cogniced VR code: {0}h-treat as UN ", Integer.tohexstring (code)); return UN; }
And in Dcm4che3, the UN type is defined as
Here the UN type is defined by referring to the DICOM3.0 standard above for the Vr=un (unknown) type of label constraint, that is , its VR field should be four bytes . However, the Value of vr=20,20 after 0028,0120 here is only two bytes in Length . This causes Dcm4che3 to incorrectly parse the length of the 0028,0120 element when it loads the 4163895298, which is the hexadecimal F8, as shown in:
Solution:
So far we have found the reason why Dcm4che3 error parsing 0028,0120 's vr=20,20 non-standard VR elements. for this non-standard VR cannot be treated uniformly as a vr.un type, but should be classified according to the length of its subsequent value length of 2 or 4来(for further details on the issue will continue to dig deeper, please note ), There are two places that need to be modified:
1. Correctly parse non-standard VR:
//vr.java,line Public StaticVrvalueOf(intCode) {Try{VR = Value_of[indexof (code)];if(VR! =NULL)returnVr }Catch(Indexoutofboundsexception e) {} Log.warn ("unrecogniced VR code: {0}h-treat as UN", integer.tohexstring (code));//return UN;Log.warn ("zssure:to solve non-standard vr,unrecogniced VR code: {0}h-treat as UN", integer.tohexstring (code));return NULL;//zssure:to solve non-standard VR}
2. Correctly read the VL of non-standard VR:
//dicominputstream.java Line 386 Public int Readheader()throwsIOException {byte[] buf = buffer; Tagpos = pos; Readfully (BUF,0,8);Switch(tag = Byteutils.bytestotag (buf,0, Bigendian)) { CaseTag.item: CaseTag.itemdelimitationitem: CaseTAG.SEQUENCEDELIMITATIONITEM:VR =NULL; Break;default:if(EXPLICITVR) {VR = vr.valueof (BYTEUTILS.BYTESTOVR (BUF,4));//zssure:to solve non-standard VR //referred:dcmtk/dcitem.cc/readtagandlength,line 970 if(VR = =NULL) {length = Byteutils.bytestoushort (buf,6, Bigendian);returnTag }//zssure:end if(vr.headerlength () = =8) {length = Byteutils.bytestoushort (buf,6, Bigendian);returnTag } readfully (BUF,4,4); }Else{VR = VR. UN; }} length = Byteutils.bytestoint (buf,4, Bigendian);returnTag }
Test File Download:
The test data used in this article has been uploaded to my github csdn repository and can be downloaded on my own, and has been anonymized to protect patient privacy.
Download Non-standard VR Test DCM file
Follow-Up Blog introduction:
1. "Stream copy" of Java stream operation from Dcm4che3.x Library
2. Eclipse automatically compiles dcm4che3.x source code
3. Dicom three open Source Library comparative analysis of "Data Loading" (cont.)
[Email protected]
Date: 2015-09-05
Copyright NOTICE: This article is zssure original article, reproduced please indicate the source, without permission shall not be reproduced.
Dicom:dicom three open source libraries comparative analysis of "data loading"