r593: no message
[ctsim.git] / libctsim / ctndicom.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:           ctndicomp.cpp
5 **  Purpose:      Interface to CTN Dicom classes
6 **      Programmer:   Kevin Rosenberg
7 **      Date Started: March 2001
8 **
9 **  This is part of the CTSim program
10 **  Copyright (c) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id: ctndicom.cpp,v 1.3 2001/03/02 02:08:14 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #ifdef HAVE_CTN_DICOM
33 #include "ctndicom.h" 
34
35 #include "imagefile.h"
36 #include "projections.h"
37
38
39 DicomImporter::DicomImporter (const char* const pszFile)
40   : m_strFilename(pszFile), m_bFail(false), m_iContents(DICOM_CONTENTS_INVALID), 
41   m_pImageFile(NULL), m_pProjections(NULL)
42 {
43   unsigned long lOptions = DCM_ORDERLITTLEENDIAN;
44   DCM_Debug (FALSE);
45   if (DCM_OpenFile (pszFile, lOptions, &m_pFile) != DCM_NORMAL) {
46     m_bFail = true;;
47     m_strFailMessage = "Can't open file ";
48     m_strFailMessage += m_strFilename;
49     return;
50   }
51
52   unsigned short iNRows, iNCols, iBitsAllocated, iBitsStored, iHighBit, iPixRep;
53   DCM_ELEMENT aElemRequired[] = {
54     {DCM_IMGROWS, DCM_US, "", 1, sizeof(iNRows), reinterpret_cast<char*>(&iNRows)},
55     {DCM_IMGCOLUMNS, DCM_US, "", 1, sizeof(iNCols), reinterpret_cast<char*>(&iNCols)},
56     {DCM_IMGBITSALLOCATED, DCM_US, "", 1, sizeof(iBitsAllocated), reinterpret_cast<char*>(&iBitsAllocated)},
57     {DCM_IMGBITSSTORED, DCM_US, "", 1, sizeof(iBitsStored), reinterpret_cast<char*>(&iBitsStored)},
58     {DCM_IMGHIGHBIT, DCM_US, "", 1, sizeof(iHighBit), reinterpret_cast<char*>(&iHighBit)},
59     {DCM_IMGPIXELREPRESENTATION, DCM_US, "", 1, sizeof(iPixRep), reinterpret_cast<char*>(&iPixRep)},
60   };
61   int nElemRequired = sizeof (aElemRequired) / sizeof(DCM_ELEMENT);
62
63   if (DCM_ParseObject (&m_pFile, aElemRequired, nElemRequired, NULL, 0, NULL) == DCM_NORMAL) {
64     loadImage (iNRows, iNCols, iBitsAllocated, iBitsStored, iHighBit, iPixRep);
65     return;
66   }
67   unsigned long lRtnLength;
68   DCM_TAG somatomTag = DCM_MAKETAG(TAG_GROUP_SOMATOM, TAG_MEMBER_SOMATOM_DATA);
69   if (DCM_GetElementSize (&m_pFile, somatomTag, &lRtnLength) == DCM_NORMAL)
70     loadProjections();
71 }
72
73 void
74 DicomImporter::loadImage(unsigned short iNRows, unsigned short iNCols, unsigned short iBitsAllocated, 
75                          unsigned short iBitsStored, unsigned short iHighBit, unsigned short iPixRep)
76 {
77   unsigned long lRtnLength;
78   unsigned short iSamplesPerPixel, iPlanarConfig;
79   
80   DCM_ELEMENT elemPlanarConfig = {DCM_IMGPLANARCONFIGURATION, DCM_US, "", 1, sizeof(iPlanarConfig), 
81                       reinterpret_cast<char*>(&iPlanarConfig)};
82   DCM_ELEMENT elemSamplesPerPixel = {DCM_IMGSAMPLESPERPIXEL, DCM_US, "", 1, 
83                       sizeof(iSamplesPerPixel), reinterpret_cast<char*>(&iSamplesPerPixel)};
84
85   if (DCM_ParseObject (&m_pFile, &elemSamplesPerPixel, 1, NULL, 0, NULL) != DCM_NORMAL)
86     iSamplesPerPixel = 1;  // default value
87
88   if (iSamplesPerPixel > 1) {
89     void* ctx = NULL;
90     if (DCM_GetElementValue (&m_pFile, &elemPlanarConfig, &lRtnLength, &ctx) != DCM_NORMAL) {
91       m_bFail = true;
92       m_strFailMessage = "Planar Configuration not specified when iSamplesPerPixel > 1";
93     }
94   }
95
96   DCM_ELEMENT elemPixelData = {DCM_PXLPIXELDATA, DCM_OT, "", 1, 0, NULL};
97
98   // Get the actual  pixel data (the only other required element)
99   if (DCM_GetElementSize (&m_pFile, elemPixelData.tag, &lRtnLength) != DCM_NORMAL) {
100     m_bFail = true;
101     m_strFailMessage = "Can't get pixel data size";
102     return;
103   }
104
105   // Check the size of the pixel data to make sure we have the correct amount...
106   unsigned long lRealLength = lRtnLength;
107   unsigned long lCheckLengthInBytes = iNRows * iNCols * iSamplesPerPixel;
108   if (iBitsAllocated == 16)
109     lCheckLengthInBytes *= 2;
110   if (lCheckLengthInBytes > lRealLength) {
111     m_bFail = true;
112     m_strFailMessage = "Too little pixel data supplied";
113     return;
114   }
115   // Now allocate the memory to hold the pixel data and get it from the DICOM file...
116
117   unsigned char* pRawPixels = new unsigned char [lCheckLengthInBytes];
118   elemPixelData.length = lCheckLengthInBytes;
119   elemPixelData.d.ot = pRawPixels;
120   
121   void* ctx = NULL;
122   CONDITION cond = DCM_GetElementValue (&m_pFile, &elemPixelData, &lRtnLength, &ctx);
123   if ((cond != DCM_NORMAL) && (cond != DCM_GETINCOMPLETE)) {
124     m_bFail = true;
125     m_strFailMessage = "Can't read pixel data";
126     delete pRawPixels;
127     return;
128   }
129   if ((lCheckLengthInBytes < lRealLength) && (cond != DCM_GETINCOMPLETE)) {
130     m_bFail;
131     m_strFailMessage = "Should have gooten incomplete message reading pixel data";
132     delete pRawPixels;
133     return;
134   }
135
136   m_pImageFile = new ImageFile (iNCols, iNRows);
137   ImageFileArray v = m_pImageFile->getArray();
138   double dScale = 1 << iBitsStored;
139   unsigned int iMaskLength = iBitsStored;
140   if (iMaskLength > 8)
141     iMaskLength -= 8;
142   unsigned int iMask = (1 << iMaskLength) - 1;
143   for (int iy = iNRows - 1; iy >= 0; iy--) {
144     for (int ix = 0; ix < iNCols; ix++) {
145       if (iBitsAllocated == 8)  {
146         unsigned char cV = pRawPixels[iy * iNRows + ix];
147         v[ix][iy] = (cV & iMask) / dScale;
148       } else if (iBitsAllocated == 16) {
149         unsigned long lBase = (iy * iNRows + ix) * 2;
150         unsigned char cV1 = pRawPixels[lBase];
151         unsigned char cV2 = pRawPixels[lBase+1] & iMask;
152         int iV = cV1 + (cV2 << 8);
153         v[ix][iy] = iV / dScale;
154       }
155     }
156   }
157   m_iContents = DICOM_CONTENTS_IMAGE;
158 }
159
160 void
161 DicomImporter::loadProjections()
162 {
163   unsigned long lRtnLength;
164   void* ctx = NULL;
165
166   unsigned short iNViews, iNDets;
167   DCM_ELEMENT aElemRequired[] = {
168     {DCM_IMGROWS, DCM_US, "", 1, sizeof(iNViews), reinterpret_cast<char*>(&iNViews)},
169     {DCM_IMGCOLUMNS, DCM_US, "", 1, sizeof(iNDets), reinterpret_cast<char*>(&iNDets)},
170   };
171   int nElemRequired = sizeof (aElemRequired) / sizeof(DCM_ELEMENT);
172
173   if (DCM_ParseObject (&m_pFile, aElemRequired, nElemRequired, NULL, 0, NULL) != DCM_NORMAL) {
174     m_bFail = true;
175     m_strFailMessage = "Unable to read header for projections";
176     return;
177   }
178
179   DCM_TAG somatomTag = DCM_MAKETAG(TAG_GROUP_SOMATOM, TAG_MEMBER_SOMATOM_DATA);
180   DCM_ELEMENT elemProjections = {somatomTag, DCM_OT, "", 1, 0, NULL};
181   if (DCM_GetElementSize (&m_pFile, elemProjections.tag, &lRtnLength) != DCM_NORMAL) {
182     m_bFail = true;
183     m_strFailMessage = "Can't find projection data";
184     return;
185   }
186
187   unsigned char* pRawProjections = new unsigned char [lRtnLength];
188   elemProjections.length = lRtnLength;
189   elemProjections.d.ot = pRawProjections;
190   
191   ctx = NULL;
192   CONDITION cond = DCM_GetElementValue (&m_pFile, &elemProjections, &lRtnLength, &ctx);
193   if ((cond != DCM_NORMAL) && (cond != DCM_GETINCOMPLETE)) {
194     m_bFail = true;
195     m_strFailMessage = "Can't read projections data";
196     delete pRawProjections;
197     return;
198   }
199   m_iContents = DICOM_CONTENTS_PROJECTIONS;
200   m_pProjections = new Projections;
201   m_pProjections->initFromSomatomAR_STAR (iNViews, iNDets, pRawProjections, lRtnLength);  
202   delete pRawProjections;
203 }
204
205
206 DicomImporter::~DicomImporter()
207 {
208   DCM_CloseObject (&m_pFile);
209 }
210
211 #endif // HAVE_CTN_DICOM
212