DCMTK open-source library study NOTE 4: uses the ini configuration file to archive dcm images, dcmtkdcm
Turn: http://blog.csdn.net/zssureqh/article/details/8846337
Background:
The server of the medical imaging PACS workstation needs to archive a large number of dcm files and write them into the database for processing. Due to the particularity of medical images, each Patient (I .e. the so-called Patient) performs at least one set of image sequences (I .e. Series) for each exam (I .e. Study ), each set of Image Sequences contains a large number of dcm files (for example, a heart CTA diagnosis, and a complete heart tomography sequence contains about 200 images ). In the DICOM3.0 Protocol, each image is marked by three unique UIDs (unique identifiers): StudyInstanceUID, SeriesInstanceUID, and SOPInstanceUID. Among them, StudyInstanceUID represents the only check (Study), SeriesInstanceUID represents the unique sequence under the corresponding check (Series), SOPInstanceUID represents the unique image under the unique sequence under the unique check. Generally, PACS workstations use these three UIDs to archive dcm files.
Archive design:
1. The basic archive structure is:
Level 1: StudyInstanceUID |
Store Image Data of the same patient |
Level 2: SeriesInstanceUID |
Store Image Data under the same check |
Level 3: SOPInstanceUID |
Store Image Data in the same sequence |
After learning about the archive structure, how should we write the dcm record into the database? The most intuitive idea is to record every dcm file in the database, so that when you need to read the specified dcm file, you can directly query it in the database using the given three UIDs. But as a result, the database capacity will increase dramatically, and a large number of redundant records exist in the same patient's database. Because the patient's image data is archived according to the above three levels of directories, a large amount of related image data is stored in the same directory on the server, for images of the same sequence, SOPInstanceUID can be used directly in the second-level directory for retrieval without the need for database queries. However, when the number of files in the second-level directory is large, it takes a lot of time to retrieve files in the file. How can we improve the retrieval efficiency? The answer is: configuration file. Since we have read three UIDs of each dcm file during archiving, the UID Information read during archiving can be written to the corresponding INI configuration file, and stored in the corresponding image sequence directory. When retrieving images, you can use the first two UID levels to quickly query the archive directory of image data in the database. after entering the specified archive directory, you can use the INI file generated during archiving, you can quickly retrieve the specified dcm file, in addition, if some common dcm file information is written into the INI configuration file (such as the width, height, patient name, birth date and month, window width/window location) during archiving ), in subsequent image processing, it can also save time and improve efficiency.
2. INI configuration file generation
The format of the INI configuration file is not described in detail. There are many blog posts in detail in CSDN. Please refer to them on your own. This section describes how to use the dcmtk open-source library to extract information about the corresponding dcm file and write it into the ini configuration file.
The DCMTK open source library is a good basic library for medical imaging development. It implements the DICOM3.0 standard and the class inheritance system is simple and clear, one-to-one correspondence with the DICOM3.0 standard (then I will write a blog on the correspondence between the inheritance system of the dcmtk open source Library and the DICOM3.0 standard ). Here we only use the DcmItem class in dcmtk, which is derived from the DcmObject base class. It contains ElementList member variables and stores the basic structure of a series of Data elements specified in the DICOM3.0 standard, as shown in:
Note: The DcmItem class is a subclass of Dataset (Dataset. It contains the data element sequence (ElementList data member ).
By reading the source code of the DcmItem class, the following dcmtk open-source Library provides the function for operating the corresponding data elements of the dcm file: findAndGet function, findOrCreate function, findAndXXX function, putAndInsert function, and insertXXX functions, such:
At this point, we can use the findAndGet function class to extract the relevant information in the dcm file, and use the WindowsAPI function to archive the INI configuration file. Because the INI configuration file is a text file, we use the findAndGetString function in DcmItem to extract the data elements in the dcm file. Using the findAndGetString function, we can directly obtain the data elements in the string format (const char, in addition, the INI configuration file is generated by using the WritePrivateProfileString function. (Note: The findAndGetString function exactly matches the format of the WritePrivateProfileString function. If other findAndGet functions, such as findAndGetSin32, you need to use functions such as itoa to convert the integer type to the const char * type, added programming complexity)
The following code is provided:
[Cpp]View plaincopyprint?
- DcmTagKey THU_DCM_ELEMENTS [] =
- {DCM_InstanceNubmber, DCM_Rows, DCM_Columns, DCM_PatientName}; // defines the dcm Data Element tag array to be written to the INI file.
- Int num = sizeof (thu_dcm_elemnt)/sizeof (DcmTagKey );
- OFString mImageValue;
- OFString mGap ("|"); // interval between data elements in the INI configuration file
- OFString mImageModule ("ImageModule \"); // The section name of the configuration file
- OFString mSOPInstanceUID;
- OFString mSeriesInstanceUID;
- DcmDataset * pDataset = mDcmFile-> getDataset ();
- DcmMetaInfo * pMetaInfo = mDcmFile-> getMetaInfo ();
- PDataset-> findAndGetOFString (DCM_SeriesInstanceUID, mSeriesInstanceUID );
- PDataset-> findAndGetOFString (DCM_SOPInstanceUID, mSOPInstanceUID );
- MImageModule + = mSeriesInstanceUID;
- For (int I = 0; I <num; ++ I)
- {
- OFString mValueRecord;
- DcmElement * element;
- If (thu_dcm_elemets [I]. getGroup ()> 0x0002) // to determine if the THU_DCM_ELEMENTS [I] is MetaInfo
- {
- // The element belongs to Dataset
- PDataset-> findAndGetOFStringArray (thu_dcm_elemets [I], mValueRecord );
- MValueRecord + = mGap;
- }
- Else
- {
- // The element belongs to MetaInfo
- If (thu_dcm_elemets [I]. getGroup () = 0x0000 & thu_dcm_elemets [I]. getElement () = 0x0000)
- {
- MValueRecord = mGap;
- }
- Else
- {
- PMetaInfo-> findAndGetOFStringArray (thu_dcm_elemets [I], mValueRecord );
- MValueRecord + = mGap;
- }
- }
- MImageValue + = mValueRecord;
- }
- : WritePrivateProfileString (mImageModule. c_str (), mSOPInstanceUID. c_str (), mImageValue. c_str (), iniFileName );
3. Database write:
The Writing Method of the database is similar to that of the INI configuration file. You only need to know a little about the C ++ database programming personnel, it is easy to write the database following the above INI configuration file generation process. I will not elaborate on it here, but just give a simple part of the Code:
[Cpp]View plaincopyprint?
- DcmFileFormat fileformat;
- TCHAR FilePath [MAX_PATH];
- OFCondition oc = fileformat. loadFile (FilePath );
- DcmDataset * pDataset = fileformat. getDataset ();
- Char query [1000];
- Memset (query, 0, sizeof (char) * 1000 );
- Lstrcat (query, _ T ("insert into patient values ("));
- Const char * tString;
- PDataset-> findAndGetString (DCM_InstanceNumber, tString );
- Lstrcat (query, tString );
- Lstrcat (query, _ T (","));
- PDataset-> findAndGetString (DCM_PatientName, tString );
- Lstrcat (query, _ T ("\""));
- Lstrcat (query, tString );
- Lstrcat (query, _ T ("\""));
- Lstrcat (query, _ T (","));
- PDataset-> findAndGetString (DCM_PatientID, tString );
- Lstrcat (query, tString );
- Lstrcat (query, _ T (","));
- PDataset-> findAndGetString (DCM_PatientBirthDate, tString );
- Lstrcat (query, tString );
- Lstrcat (query, _ T (","));
- PDataset-> findAndGetString (DCM_PatientSex, tString );
- Lstrcat (query ,"\"");
- Lstrcat (query, tString );
- Lstrcat (query ,"\"");
- Lstrcat (query ,",");
- PDataset-> findAndGetString (DCM_PatientAge, tString );
- Char temp [100];
- Memcpy (temp, tString, lstrlen (tString ));
- Temp [lstrlen (tString)] = _ T ('\ 0 ');
- For (int I = 0; I <strlen (temp); ++ I)
- If (temp [I] = _ T ('y '))
- Temp [I] = _ T ('\ 0 ');
- Lstrcat (query, temp );
- Lstrcat (query ,",");
- Lstrcat (query, _ T ("2013 )"));
- N style = "white-space: pre"> </span> // write data to the mysql database
- MYSQL * con;
- Con = mysql_init (MYSQL *) 0 );
- If (con! = NULL & mysql_real_connect (con, host, user, passwd, db, port, unix_socket, client_flag ))
- {
- If (! Mysql_select_db (con, db ))
- {
- : Printf ("Selcet successfully the database! \ N ");
- Con-> reconnect = 1;
- Int rt = mysql_real_query (mysql, query, strlen (query ));
- If (rt)
- {
- : Printf ("Error making insert !!! \ N ");
- }
- }
- }
For mysql c ++ operations, see blog: http://www.cnblogs.com/justinzhang/archive/2011/09/23/2185963.html