r593: no message
[ctsim.git] / libctsim / ctndicom.cpp
index a2a343b7abdb58da7230e1465feb0bdd2c5dcdf0..72d32181ad0209001db6f7c843a06b4e70501850 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: ctndicom.cpp,v 1.1 2001/03/01 07:30:49 kevin Exp $
+**  $Id: ctndicom.cpp,v 1.3 2001/03/02 02:08:14 kevin Exp $
 **
 **  This program is free software; you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License (version 2) as
 #endif
 
 #ifdef HAVE_CTN_DICOM
-#include "ctndicomp.h"
+#include "ctndicom.h" 
+
+#include "imagefile.h"
+#include "projections.h"
+
+
+DicomImporter::DicomImporter (const char* const pszFile)
+  : m_strFilename(pszFile), m_bFail(false), m_iContents(DICOM_CONTENTS_INVALID), 
+  m_pImageFile(NULL), m_pProjections(NULL)
+{
+  unsigned long lOptions = DCM_ORDERLITTLEENDIAN;
+  DCM_Debug (FALSE);
+  if (DCM_OpenFile (pszFile, lOptions, &m_pFile) != DCM_NORMAL) {
+    m_bFail = true;;
+    m_strFailMessage = "Can't open file ";
+    m_strFailMessage += m_strFilename;
+    return;
+  }
+
+  unsigned short iNRows, iNCols, iBitsAllocated, iBitsStored, iHighBit, iPixRep;
+  DCM_ELEMENT aElemRequired[] = {
+    {DCM_IMGROWS, DCM_US, "", 1, sizeof(iNRows), reinterpret_cast<char*>(&iNRows)},
+    {DCM_IMGCOLUMNS, DCM_US, "", 1, sizeof(iNCols), reinterpret_cast<char*>(&iNCols)},
+    {DCM_IMGBITSALLOCATED, DCM_US, "", 1, sizeof(iBitsAllocated), reinterpret_cast<char*>(&iBitsAllocated)},
+    {DCM_IMGBITSSTORED, DCM_US, "", 1, sizeof(iBitsStored), reinterpret_cast<char*>(&iBitsStored)},
+    {DCM_IMGHIGHBIT, DCM_US, "", 1, sizeof(iHighBit), reinterpret_cast<char*>(&iHighBit)},
+    {DCM_IMGPIXELREPRESENTATION, DCM_US, "", 1, sizeof(iPixRep), reinterpret_cast<char*>(&iPixRep)},
+  };
+  int nElemRequired = sizeof (aElemRequired) / sizeof(DCM_ELEMENT);
+
+  if (DCM_ParseObject (&m_pFile, aElemRequired, nElemRequired, NULL, 0, NULL) == DCM_NORMAL) {
+    loadImage (iNRows, iNCols, iBitsAllocated, iBitsStored, iHighBit, iPixRep);
+    return;
+  }
+  unsigned long lRtnLength;
+  DCM_TAG somatomTag = DCM_MAKETAG(TAG_GROUP_SOMATOM, TAG_MEMBER_SOMATOM_DATA);
+  if (DCM_GetElementSize (&m_pFile, somatomTag, &lRtnLength) == DCM_NORMAL)
+    loadProjections();
+}
+
+void
+DicomImporter::loadImage(unsigned short iNRows, unsigned short iNCols, unsigned short iBitsAllocated, 
+                         unsigned short iBitsStored, unsigned short iHighBit, unsigned short iPixRep)
+{
+  unsigned long lRtnLength;
+  unsigned short iSamplesPerPixel, iPlanarConfig;
+  
+  DCM_ELEMENT elemPlanarConfig = {DCM_IMGPLANARCONFIGURATION, DCM_US, "", 1, sizeof(iPlanarConfig), 
+                      reinterpret_cast<char*>(&iPlanarConfig)};
+  DCM_ELEMENT elemSamplesPerPixel = {DCM_IMGSAMPLESPERPIXEL, DCM_US, "", 1, 
+                      sizeof(iSamplesPerPixel), reinterpret_cast<char*>(&iSamplesPerPixel)};
+
+  if (DCM_ParseObject (&m_pFile, &elemSamplesPerPixel, 1, NULL, 0, NULL) != DCM_NORMAL)
+    iSamplesPerPixel = 1;  // default value
+
+  if (iSamplesPerPixel > 1) {
+    void* ctx = NULL;
+    if (DCM_GetElementValue (&m_pFile, &elemPlanarConfig, &lRtnLength, &ctx) != DCM_NORMAL) {
+      m_bFail = true;
+      m_strFailMessage = "Planar Configuration not specified when iSamplesPerPixel > 1";
+    }
+  }
+
+  DCM_ELEMENT elemPixelData = {DCM_PXLPIXELDATA, DCM_OT, "", 1, 0, NULL};
+
+  // Get the actual  pixel data (the only other required element)
+  if (DCM_GetElementSize (&m_pFile, elemPixelData.tag, &lRtnLength) != DCM_NORMAL) {
+    m_bFail = true;
+    m_strFailMessage = "Can't get pixel data size";
+    return;
+  }
+
+  // Check the size of the pixel data to make sure we have the correct amount...
+  unsigned long lRealLength = lRtnLength;
+  unsigned long lCheckLengthInBytes = iNRows * iNCols * iSamplesPerPixel;
+  if (iBitsAllocated == 16)
+    lCheckLengthInBytes *= 2;
+  if (lCheckLengthInBytes > lRealLength) {
+    m_bFail = true;
+    m_strFailMessage = "Too little pixel data supplied";
+    return;
+  }
+  // Now allocate the memory to hold the pixel data and get it from the DICOM file...
+
+  unsigned char* pRawPixels = new unsigned char [lCheckLengthInBytes];
+  elemPixelData.length = lCheckLengthInBytes;
+  elemPixelData.d.ot = pRawPixels;
+  
+  void* ctx = NULL;
+  CONDITION cond = DCM_GetElementValue (&m_pFile, &elemPixelData, &lRtnLength, &ctx);
+  if ((cond != DCM_NORMAL) && (cond != DCM_GETINCOMPLETE)) {
+    m_bFail = true;
+    m_strFailMessage = "Can't read pixel data";
+    delete pRawPixels;
+    return;
+  }
+  if ((lCheckLengthInBytes < lRealLength) && (cond != DCM_GETINCOMPLETE)) {
+    m_bFail;
+    m_strFailMessage = "Should have gooten incomplete message reading pixel data";
+    delete pRawPixels;
+    return;
+  }
+
+  m_pImageFile = new ImageFile (iNCols, iNRows);
+  ImageFileArray v = m_pImageFile->getArray();
+  double dScale = 1 << iBitsStored;
+  unsigned int iMaskLength = iBitsStored;
+  if (iMaskLength > 8)
+    iMaskLength -= 8;
+  unsigned int iMask = (1 << iMaskLength) - 1;
+  for (int iy = iNRows - 1; iy >= 0; iy--) {
+    for (int ix = 0; ix < iNCols; ix++) {
+      if (iBitsAllocated == 8)  {
+        unsigned char cV = pRawPixels[iy * iNRows + ix];
+        v[ix][iy] = (cV & iMask) / dScale;
+      } else if (iBitsAllocated == 16) {
+        unsigned long lBase = (iy * iNRows + ix) * 2;
+        unsigned char cV1 = pRawPixels[lBase];
+        unsigned char cV2 = pRawPixels[lBase+1] & iMask;
+        int iV = cV1 + (cV2 << 8);
+        v[ix][iy] = iV / dScale;
+      }
+    }
+  }
+  m_iContents = DICOM_CONTENTS_IMAGE;
+}
+
+void
+DicomImporter::loadProjections()
+{
+  unsigned long lRtnLength;
+  void* ctx = NULL;
+
+  unsigned short iNViews, iNDets;
+  DCM_ELEMENT aElemRequired[] = {
+    {DCM_IMGROWS, DCM_US, "", 1, sizeof(iNViews), reinterpret_cast<char*>(&iNViews)},
+    {DCM_IMGCOLUMNS, DCM_US, "", 1, sizeof(iNDets), reinterpret_cast<char*>(&iNDets)},
+  };
+  int nElemRequired = sizeof (aElemRequired) / sizeof(DCM_ELEMENT);
+
+  if (DCM_ParseObject (&m_pFile, aElemRequired, nElemRequired, NULL, 0, NULL) != DCM_NORMAL) {
+    m_bFail = true;
+    m_strFailMessage = "Unable to read header for projections";
+    return;
+  }
+
+  DCM_TAG somatomTag = DCM_MAKETAG(TAG_GROUP_SOMATOM, TAG_MEMBER_SOMATOM_DATA);
+  DCM_ELEMENT elemProjections = {somatomTag, DCM_OT, "", 1, 0, NULL};
+  if (DCM_GetElementSize (&m_pFile, elemProjections.tag, &lRtnLength) != DCM_NORMAL) {
+    m_bFail = true;
+    m_strFailMessage = "Can't find projection data";
+    return;
+  }
+
+  unsigned char* pRawProjections = new unsigned char [lRtnLength];
+  elemProjections.length = lRtnLength;
+  elemProjections.d.ot = pRawProjections;
+  
+  ctx = NULL;
+  CONDITION cond = DCM_GetElementValue (&m_pFile, &elemProjections, &lRtnLength, &ctx);
+  if ((cond != DCM_NORMAL) && (cond != DCM_GETINCOMPLETE)) {
+    m_bFail = true;
+    m_strFailMessage = "Can't read projections data";
+    delete pRawProjections;
+    return;
+  }
+  m_iContents = DICOM_CONTENTS_PROJECTIONS;
+  m_pProjections = new Projections;
+  m_pProjections->initFromSomatomAR_STAR (iNViews, iNDets, pRawProjections, lRtnLength);  
+  delete pRawProjections;
+}
+
+
+DicomImporter::~DicomImporter()
+{
+  DCM_CloseObject (&m_pFile);
+}
 
 #endif // HAVE_CTN_DICOM