1 /*****************************************************************************
5 ** Purpose: Interface to CTN Dicom classes
6 ** Programmer: Kevin Rosenberg
7 ** Date Started: March 2001
9 ** This is part of the CTSim program
10 ** Copyright (c) 1983-2001 Kevin Rosenberg
12 ** $Id: ctndicom.cpp,v 1.5 2001/03/05 15:10:58 kevin Exp $
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.
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.
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 ******************************************************************************/
35 #include "imagefile.h"
36 #include "projections.h"
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)
43 unsigned long lOptions = DCM_ORDERLITTLEENDIAN;
45 if (DCM_OpenFile (pszFile, lOptions, &m_pFile) != DCM_NORMAL) {
47 m_strFailMessage = "Can't open file ";
48 m_strFailMessage += m_strFilename;
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)},
61 int nElemRequired = sizeof (aElemRequired) / sizeof(DCM_ELEMENT);
63 if (DCM_ParseObject (&m_pFile, aElemRequired, nElemRequired, NULL, 0, NULL) == DCM_NORMAL) {
64 loadImage (iNRows, iNCols, iBitsAllocated, iBitsStored, iHighBit, iPixRep);
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)
74 DicomImporter::loadImage(unsigned short iNRows, unsigned short iNCols, unsigned short iBitsAllocated,
75 unsigned short iBitsStored, unsigned short iHighBit, unsigned short iPixRep)
77 unsigned long lRtnLength;
78 unsigned short iSamplesPerPixel, iPlanarConfig;
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)};
85 if (DCM_ParseObject (&m_pFile, &elemSamplesPerPixel, 1, NULL, 0, NULL) != DCM_NORMAL)
86 iSamplesPerPixel = 1; // default value
88 if (iSamplesPerPixel > 1) {
90 if (DCM_GetElementValue (&m_pFile, &elemPlanarConfig, &lRtnLength, &ctx) != DCM_NORMAL) {
92 m_strFailMessage = "Planar Configuration not specified when iSamplesPerPixel > 1";
96 DCM_ELEMENT elemPixelData = {DCM_PXLPIXELDATA, DCM_OT, "", 1, 0, NULL};
98 // Get the actual pixel data (the only other required element)
99 if (DCM_GetElementSize (&m_pFile, elemPixelData.tag, &lRtnLength) != DCM_NORMAL) {
101 m_strFailMessage = "Can't get pixel data size";
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) {
112 m_strFailMessage = "Too little pixel data supplied";
115 // Now allocate the memory to hold the pixel data and get it from the DICOM file...
117 unsigned char* pRawPixels = new unsigned char [lCheckLengthInBytes];
118 elemPixelData.length = lCheckLengthInBytes;
119 elemPixelData.d.ot = pRawPixels;
122 CONDITION cond = DCM_GetElementValue (&m_pFile, &elemPixelData, &lRtnLength, &ctx);
123 if ((cond != DCM_NORMAL) && (cond != DCM_GETINCOMPLETE)) {
125 m_strFailMessage = "Can't read pixel data";
129 if ((lCheckLengthInBytes < lRealLength) && (cond != DCM_GETINCOMPLETE)) {
131 m_strFailMessage = "Should have gooten incomplete message reading pixel data";
136 m_pImageFile = new ImageFile (iNCols, iNRows);
137 ImageFileArray v = m_pImageFile->getArray();
138 double dScale = 1 << iBitsStored;
139 unsigned int iMaskLength = iBitsStored;
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;
157 m_iContents = DICOM_CONTENTS_IMAGE;
161 DicomImporter::loadProjections()
163 unsigned long lRtnLength;
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)},
171 int nElemRequired = sizeof (aElemRequired) / sizeof(DCM_ELEMENT);
173 if (DCM_ParseObject (&m_pFile, aElemRequired, nElemRequired, NULL, 0, NULL) != DCM_NORMAL) {
175 m_strFailMessage = "Unable to read header for projections";
179 DCM_TAG somatomTag = DCM_MAKETAG(TAG_GROUP_SOMATOM, TAG_MEMBER_SOMATOM_DATA);
180 DCM_ELEMENT elemProjections = {somatomTag, DCM_UNKNOWN, "", 1, 0, NULL};
181 if (DCM_GetElementSize (&m_pFile, elemProjections.tag, &lRtnLength) != DCM_NORMAL) {
183 m_strFailMessage = "Can't find projection data";
187 unsigned char* pRawProjections = new unsigned char [lRtnLength];
188 elemProjections.length = lRtnLength;
189 elemProjections.d.ot = pRawProjections;
192 CONDITION cond = DCM_GetElementValue (&m_pFile, &elemProjections, &lRtnLength, &ctx);
193 if ((cond != DCM_NORMAL) && (cond != DCM_GETINCOMPLETE)) {
195 m_strFailMessage = "Can't read projections data";
196 delete pRawProjections;
199 m_iContents = DICOM_CONTENTS_PROJECTIONS;
200 m_pProjections = new Projections;
201 if (! m_pProjections->initFromSomatomAR_STAR (iNViews, iNDets, pRawProjections, lRtnLength)) {
203 m_strFailMessage = "Error converting raw projection data";
204 delete m_pProjections;
205 m_pProjections = NULL;
208 delete pRawProjections;
212 DicomImporter::~DicomImporter()
214 DCM_CloseObject (&m_pFile);
217 #endif // HAVE_CTN_DICOM