vector<ImportDescriptor*> EnviLibraryImporter::getImportDescriptors(const string& filename)
{
   vector<ImportDescriptor*> descriptors;

   string headerFile = filename;
   string dataFile;
   // assume filename is a header file and try to parse
   bool bSuccess = mFields.populateFromHeader(filename);
   if (bSuccess == false)
   {
      dataFile = filename;           // was passed data file name instead of header file name
      headerFile = findHeaderFile(dataFile);
      if (headerFile.empty() == false)
      {
         bSuccess = mFields.populateFromHeader(headerFile);
      }
   }
   if (bSuccess == true)
   {
      if (dataFile.empty())  // was passed header file name and now need to find the data file name
      {
         dataFile = findDataFile(headerFile);
      }
      if (dataFile.empty())  // no data file found for the header
      {
         return descriptors;
      }

      EnviField* pField = mFields.find("file type");
      if (pField != NULL)
      {
         if (pField->mValue == "ENVI Spectral Library" || 
             pField->mValue == "Spectral Library")
         {
            // Get the name and dataset from the header values
            string name;
            string dataset;

            EnviField* pBandNamesField = mFields.find("band names");
            if (pBandNamesField != NULL)
            {
               if (pBandNamesField->mChildren.empty() == false)
               {
                  EnviField* pNameField = pBandNamesField->mChildren.front();
                  if (pNameField != NULL)
                  {
                     name = pNameField->mValue;
                  }
               }
            }

            EnviField* pDescriptionField = mFields.find("description");
            if (pDescriptionField != NULL)
            {
               // Library name
               if (name.empty() == true)
               {
                  EnviField* pNameField = pDescriptionField->find("library name");
                  if (pNameField != NULL)
                  {
                     name = pNameField->mValue;
                  }
               }

               // Dataset
               EnviField* pDatasetField = pDescriptionField->find("dataset");
               if (pDatasetField != NULL)
               {
                  dataset = pDatasetField->mValue;
               }
            }

            // Create the data descriptor
            Service<ModelServices> pModel;

            RasterElement* pRasterElement = NULL;
            if (dataset.empty() == false)
            {
               pRasterElement = dynamic_cast<RasterElement*>(pModel->getElement(dataset, "RasterElement", NULL));
            }

            if (name.empty() == true)
            {
               // Create a unique default name
               unsigned int libraryNumber = pModel->getElements(pRasterElement, "SignatureLibrary").size();

               DataElement* pSignatureLibrary = NULL;
               do
               {
                  char buffer[64];
                  sprintf(buffer, "%u", ++libraryNumber);

                  name = "Spectral Library " + string(buffer);
                  pSignatureLibrary = pModel->getElement(name, "SignatureLibrary", pRasterElement);
               }
               while (pSignatureLibrary != NULL);
            }

            ImportDescriptor* pImportDescriptor =
               pModel->createImportDescriptor(name, "SignatureLibrary", pRasterElement);
            if (pImportDescriptor != NULL)
            {
               SignatureDataDescriptor* pDescriptor =
                  dynamic_cast<SignatureDataDescriptor*>(pImportDescriptor->getDataDescriptor());
               if (pDescriptor != NULL)
               {
                  // Metadata
                  FactoryResource<DynamicObject> pMetadata;
                  if (pDescriptionField != NULL)
                  {
                     vector<EnviField*>& children = pDescriptionField->mChildren;
                     for (vector<EnviField*>::iterator iter = children.begin(); iter != children.end(); ++iter)
                     {
                        EnviField* pField = *iter;
                        if (pField != NULL)
                        {
                           if ((pField->mTag.empty() == false) && (pField->mValue.empty() == false))
                           {
                              pMetadata->setAttribute(pField->mTag, pField->mValue);
                           }
                        }
                     }
                  }

                  // Signature names
                  EnviField* pSigNamesField = mFields.find("spectra names");
                  if (pSigNamesField != NULL)
                  {
                     vector<string> sigNames;
                     for (unsigned int i = 0; i < pSigNamesField->mChildren.size(); i++)
                     {
                        EnviField* pField = pSigNamesField->mChildren[i];
                        if (pField != NULL)
                        {
                           vector<char> bufferVector(pField->mValue.size() + 1);
                           char* pBuffer = &bufferVector.front();
                           strcpy(pBuffer, pField->mValue.c_str());

                           char* pPtr = strtok(pBuffer, ",");
                           while (pPtr != NULL)
                           {
                              string sigName = StringUtilities::stripWhitespace(string(pPtr));
                              sigNames.push_back(sigName);

                              pPtr = strtok(NULL, ",");
                           }
                        }
                     }

                     if (sigNames.empty() == false)
                     {
                        pMetadata->setAttribute("Signature Names", sigNames);
                     }
                  }

                  // Signature units - Set custom units into the data descriptor so that the
                  // user can modify them even though units are not loaded from the file
                  FactoryResource<Units> pUnits;
                  pUnits->setUnitName("Custom");
                  pUnits->setUnitType(CUSTOM_UNIT);
                  pDescriptor->setUnits("Reflectance", pUnits.get());

                  // Wavelengths
                  EnviField* pSamplesField = mFields.find("samples");
                  if (pSamplesField != NULL)
                  {
                     unsigned int numWavelengths = StringUtilities::fromXmlString<unsigned int>(pSamplesField->mValue);

                     vector<double> wavelengths;
                     unsigned int uiNanometerValues = 0;

                     EnviField* pWavelengthField = mFields.find("wavelength");
                     if (pWavelengthField != NULL)
                     {
                        vector<unsigned int> goodBands;
                        EnviField* pBblField = mFields.find("bbl");
                        if (pBblField != NULL)
                        {
                           // Parse the bad bands list. This method puts the indices of good bands in ascending order.
                           EnviImporter::parseBbl(pBblField, goodBands);

                           // Sort in descending order so that the last one can be popped later
                           // A pop_back is much faster than an erase on the first element
                           reverse(goodBands.begin(), goodBands.end());
                        }

                        unsigned int numWavelengthsRead = 0;
                        for (std::vector<EnviField*>::const_iterator iter = pWavelengthField->mChildren.begin();
                           iter != pWavelengthField->mChildren.end();
                           ++iter)
                        {
                           EnviField* pField = *iter;
                           if (pField != NULL)
                           {
                              vector<char> bufferVector(pField->mValue.size() + 1);
                              char* pBuffer = &(bufferVector.front());
                              strcpy(pBuffer, pField->mValue.c_str());

                              char* pPtr = strtok(pBuffer, ",");
                              while (pPtr != NULL)
                              {
                                 double dWavelength = 0.0;
                                 if (sscanf(pPtr, "%lf", &dWavelength) == 1)
                                 {
                                    if (dWavelength > 50.0)    // Assumed to be in nanometers
                                    {
                                       uiNanometerValues++;
                                    }

                                    // Restrict the number of wavelengths to the number of samples in the header file
                                    if (numWavelengthsRead < numWavelengths)
                                    {
                                       // Only write the wavelength if the value is valid
                                       // Since the bands are in descending order,
                                       // goodBands.back() always holds the next good band.
                                       if (pBblField == NULL ||
                                          (goodBands.empty() == false && goodBands.back() == numWavelengthsRead))
                                       {
                                          if (goodBands.empty() == false)
                                          {
                                             goodBands.pop_back();
                                          }

                                          wavelengths.push_back(dWavelength);
                                       }
                                    }

                                    ++numWavelengthsRead;
                                 }

                                 pPtr = strtok(NULL, ",");
                              }
                           }
                        }

                        VERIFYNR(goodBands.empty() == true);
                     }

                     // Wavelength units
                     bool bConvertWavelengths = false;
                     bool bDetermineUnits = true;

                     EnviField* pUnitsField = mFields.find("wavelength units");
                     if (pUnitsField != NULL)
                     {
                        if (pUnitsField->mValue == "Micrometers")
                        {
                           bDetermineUnits = false;
                        }
                        else if (pUnitsField->mValue == "Nanometers")
                        {
                           bDetermineUnits = false;
                           bConvertWavelengths = true;
                        }
                     }

                     if (bDetermineUnits)
                     {
                        if ((uiNanometerValues * 100) / wavelengths.size() > 50)
                        {
                           bConvertWavelengths = true;
                        }
                     }

                     if (bConvertWavelengths == true)
                     {
                        for (vector<double>::size_type i = 0; i < wavelengths.size(); i++)
                        {
                           wavelengths[i] *= 0.001;
                        }
                     }

                     string pCenterPath[] = { SPECIAL_METADATA_NAME, BAND_METADATA_NAME, 
                        CENTER_WAVELENGTHS_METADATA_NAME, END_METADATA_NAME };
                     pMetadata->setAttributeByPath(pCenterPath, wavelengths);
                  }

                  if (pMetadata->getNumAttributes() > 0)
                  {
                     pDescriptor->setMetadata(pMetadata.get());
                  }

                  // Create the file descriptor
                  FactoryResource<SignatureFileDescriptor> pFileDescriptor;
                  if (pFileDescriptor.get() != NULL)
                  {
                     pFileDescriptor->setFilename(dataFile);
                     pDescriptor->setFileDescriptor(pFileDescriptor.get());
                  }
               }
               descriptors.push_back(pImportDescriptor);
            }
         }
      }
   }

   return descriptors;
}
Beispiel #2
0
std::vector<ImportDescriptor*> FitsImporter::getImportDescriptors(const std::string& fname)
{
   std::string filename = fname;
   std::vector<std::vector<std::string> >& errors = mErrors[fname];
   std::vector<std::vector<std::string> >& warnings = mWarnings[fname];
   errors.clear();
   warnings.clear();
   int status=0;
   std::vector<ImportDescriptor*> descriptors;

   FitsFileResource pFile(filename);
   if (!pFile.isValid())
   {
      errors.resize(1);
      errors[0].push_back(pFile.getStatus());
      RETURN_DESCRIPTORS;
   }

   int hduCnt = 0;
   int specificHdu = 0;
   int hdu = 1;
   if (!splitFilename(filename, hduCnt, specificHdu, hdu, pFile, errors, warnings))
   {
      RETURN_DESCRIPTORS;
   }
   errors.resize(hduCnt+1);
   warnings.resize(hduCnt+1);

   for(; hdu <= hduCnt; ++hdu)
   {
      std::string datasetName = filename + "[" + StringUtilities::toDisplayString(hdu) + "]";
      int hduType;
      CHECK_FITS(fits_movabs_hdu(pFile, hdu, &hduType, &status), hdu, false, continue);
      ImportDescriptorResource pImportDescriptor(static_cast<ImportDescriptor*>(NULL));
      FactoryResource<DynamicObject> pMetadata;
      VERIFYRV(pMetadata.get() != NULL, descriptors);
      { // scope
         std::vector<std::string> comments;
         char pCard[81];
         char pValue[81];
         char pComment[81];
         int nkeys = 0;
         CHECK_FITS(fits_get_hdrspace(pFile, &nkeys, NULL, &status), hdu, true, ;);
         for(int keyidx = 1; keyidx <= nkeys; ++keyidx)
         {
            CHECK_FITS(fits_read_keyn(pFile, keyidx, pCard, pValue, pComment, &status), hdu, true, continue);
            std::string name = StringUtilities::stripWhitespace(std::string(pCard));
            std::string val = StringUtilities::stripWhitespace(std::string(pValue));
            std::string comment = StringUtilities::stripWhitespace(std::string(pComment));
            if (!val.empty())
            {
               pMetadata->setAttributeByPath("FITS/" + name, val);
            }
            else if (!comment.empty())
            {
               comments.push_back(comment);
            }
         }
         if (!comments.empty())
         {
            // ideally, this would add a multi-line string but Opticks doesn't display this properly
            // pMetadata->setAttributeByPath("FITS/COMMENT", StringUtilities::join(comments, "\n"));
            for(unsigned int idx = 0; idx < comments.size(); ++idx)
            {
               pMetadata->setAttributeByPath("FITS/COMMENT/" + StringUtilities::toDisplayString(idx), comments[idx]);
            }
         }
      }
      switch(hduType)
      {
      case IMAGE_HDU:
      {
         pImportDescriptor = ImportDescriptorResource(datasetName, TypeConverter::toString<RasterElement>());
         VERIFYRV(pImportDescriptor.get() != NULL, descriptors);

         EncodingType fileEncoding;
         InterleaveFormatType interleave(BSQ);
         unsigned int rows=0;
         unsigned int cols=0;
         unsigned int bands=1;

         int bitpix;
         int naxis;
         long axes[3];
         CHECK_FITS(fits_get_img_param(pFile, 3, &bitpix, &naxis, axes, &status), hdu, false, continue);
         switch(bitpix)
         {
         case BYTE_IMG:
            fileEncoding = INT1UBYTE;
            break;
         case SHORT_IMG:
            fileEncoding = INT2SBYTES;
            break;
         case LONG_IMG:
            fileEncoding = INT4SBYTES;
            break;
         case FLOAT_IMG:
            fileEncoding = FLT4BYTES;
            break;
         case DOUBLE_IMG:
            fileEncoding = FLT8BYTES;
            break;
         default:
            warnings[hdu].push_back("Unsupported BITPIX value " + StringUtilities::toDisplayString(bitpix) + ".");
            continue;
         }
         EncodingType dataEncoding = checkForOverflow(fileEncoding, pMetadata.get(), hdu, errors, warnings);
         if (naxis == 1)
         {
            // 1-D data is a signature
            pImportDescriptor = ImportDescriptorResource(datasetName, TypeConverter::toString<Signature>());
            pMetadata->setAttributeByPath(METADATA_SIG_ENCODING, dataEncoding);
            pMetadata->setAttributeByPath(METADATA_SIG_LENGTH, axes[0]);

            RasterUtilities::generateAndSetFileDescriptor(pImportDescriptor->getDataDescriptor(), filename,
               StringUtilities::toDisplayString(hdu), BIG_ENDIAN_ORDER);

            // add units
            SignatureDataDescriptor* pSigDd =
               dynamic_cast<SignatureDataDescriptor*>(pImportDescriptor->getDataDescriptor());
            if (pSigDd != NULL)
            {
               FactoryResource<Units> pUnits;
               pUnits->setUnitName("Custom");
               pUnits->setUnitType(CUSTOM_UNIT);
               pSigDd->setUnits("Reflectance", pUnits.get());
            }

            break; // leave switch()
         }
         else if (naxis == 2)
         {
            cols = axes[0];
            rows = axes[1];
         }
         else if (naxis == 3)
         {
            cols = axes[0];
            rows = axes[1];
            bands = axes[2];
         }
         else
         {
            errors[hdu].push_back(StringUtilities::toDisplayString(naxis) + " axis data not supported.");
         }

         RasterDataDescriptor* pDataDesc = RasterUtilities::generateRasterDataDescriptor(
            datasetName, NULL, rows, cols, bands, interleave, dataEncoding, IN_MEMORY);
         pImportDescriptor->setDataDescriptor(pDataDesc);
         if (specificHdu == 0 && hdu == 1 && naxis == 2 && (axes[0] <= 5 || axes[1] <= 5))
         {
            // use 5 as this is a good top end for the number of astronomical band pass filters
            // in general usage. this is not in a spec anywhere and is derived from various sample
            // FITS files for different astronomical instruments.
            //
            // There's a good chance this is really a spectrum. (0th HDU)
            // We'll create an import descriptor for the spectrum version of this
            // And disable the raster descriptor by default
            pImportDescriptor->setImported(false);
            ImportDescriptorResource pSigDesc(datasetName, TypeConverter::toString<SignatureLibrary>());
            DynamicObject* pSigMetadata = pSigDesc->getDataDescriptor()->getMetadata();
            pSigMetadata->merge(pMetadata.get());
            std::vector<double> centerWavelengths;
            unsigned int cnt = (axes[0] <= 5) ? axes[1] : axes[0];
            double startVal = StringUtilities::fromDisplayString<double>(
               dv_cast<std::string>(pMetadata->getAttributeByPath("FITS/MINWAVE"), "0.0"));
            double endVal = StringUtilities::fromDisplayString<double>(
               dv_cast<std::string>(pMetadata->getAttributeByPath("FITS/MAXWAVE"), "0.0"));
            double incr = (endVal == 0.0) ? 1.0 : ((endVal - startVal) / static_cast<double>(cnt));
            centerWavelengths.reserve(cnt);
            for (unsigned int idx = 0; idx < cnt; idx++)
            {
               centerWavelengths.push_back(startVal + (idx * incr));
            }
            pSigMetadata->setAttributeByPath(CENTER_WAVELENGTHS_METADATA_PATH, centerWavelengths);

            // Units
            std::string unitsName = dv_cast<std::string>(pMetadata->getAttributeByPath("FITS/BUNIT"), std::string());
            if (!unitsName.empty())
            {
               FactoryResource<Units> units;
               units->setUnitName(unitsName);
               units->setUnitType(RADIANCE);
               SignatureDataDescriptor* pSigDd =
                  dynamic_cast<SignatureDataDescriptor*>(pSigDesc->getDataDescriptor());
               if (pSigDd != NULL)
               {
                  pSigDd->setUnits("Reflectance", units.get());
               }
            }

            RasterUtilities::generateAndSetFileDescriptor(pSigDesc->getDataDescriptor(),
               filename, StringUtilities::toDisplayString(hdu), BIG_ENDIAN_ORDER);

            // If units are not available, set custom units into the data descriptor so that the user can
            // modify them - this must occur after the call to RasterUtilities::generateAndSetFileDescriptor()
            // so that the file descriptor will still display no defined units
            if (unitsName.empty())
            {
               FactoryResource<Units> units;
               units->setUnitName("Custom");
               units->setUnitType(CUSTOM_UNIT);
               SignatureDataDescriptor* pSigDd = dynamic_cast<SignatureDataDescriptor*>(pSigDesc->getDataDescriptor());
               if (pSigDd != NULL)
               {
                  pSigDd->setUnits("Reflectance", units.get());
               }
            }

            descriptors.push_back(pSigDesc.release());
         }

         RasterFileDescriptor* pFileDescriptor = dynamic_cast<RasterFileDescriptor*>(
            RasterUtilities::generateAndSetFileDescriptor(pDataDesc, filename,
            StringUtilities::toDisplayString(hdu), BIG_ENDIAN_ORDER));
         if (pFileDescriptor != NULL)
         {
            unsigned int bitsPerElement = RasterUtilities::bytesInEncoding(fileEncoding) * 8;
            pFileDescriptor->setBitsPerElement(bitsPerElement);
         }

         break; // leave switch()
      }
      case ASCII_TBL:
      case BINARY_TBL:
         warnings[hdu].push_back("Tables not supported. [HDU " + StringUtilities::toDisplayString(hdu) + "]");
         continue;
      default:
         warnings[hdu].push_back("HDU " + StringUtilities::toDisplayString(hdu) + " is an unknown type.");
         continue;
      }

      pImportDescriptor->getDataDescriptor()->setMetadata(pMetadata.release());
      pImportDescriptor->setImported(errors[hdu].empty());
      descriptors.push_back(pImportDescriptor.release());
   }
Beispiel #3
0
std::vector<ImportDescriptor*> DicomImporter::getImportDescriptors(const std::string &filename)
{
   mErrors.clear();
   mWarnings.clear();
   std::vector<ImportDescriptor*> descriptors;

   DcmFileFormat fileformat;
   OFCondition status;
   if((status = fileformat.loadFile(filename.c_str())).bad())
   {
      return descriptors;
   }

   ImportDescriptorResource pImportDescriptor(filename, TypeConverter::toString<RasterElement>());
   VERIFYRV(pImportDescriptor.get() != NULL, descriptors);
   descriptors.push_back(pImportDescriptor.release());

   DicomImage img(fileformat.getDataset(), fileformat.getDataset()->getOriginalXfer());
   if(img.getStatus() != EIS_Normal)
   {
      mErrors.push_back(std::string("Unable to decode image: ") + DicomImage::getString(img.getStatus()));
      pImportDescriptor->setDataDescriptor(RasterUtilities::generateRasterDataDescriptor(filename, NULL, 0, 0, INT1UBYTE, IN_MEMORY));
      return descriptors;
   }
   InterleaveFormatType interleave(BSQ);
   EncodingType encoding(INT4UBYTES);
   bool rgb = false;
   unsigned long rows = img.getHeight(), columns = img.getWidth(), frames = img.getFrameCount();
   int imgDepth = img.getDepth();
   switch(img.getPhotometricInterpretation())
   {
   case EPI_Monochrome1:
   case EPI_Monochrome2:
      // do nothing special....this is single or multi-frame grayscale, 1 or 2 byte
      break;
   case EPI_RGB:
   case EPI_PaletteColor:
      // supported if there's only 1 frame
      if(frames == 1)
      {
         frames = 3;
         rgb = true;
      }
      else
      {
         mWarnings.push_back("RGB and palette color not supported when multiple frames are present. Converting to grayscale.");
      }
      break;
   default:
      mWarnings.push_back(std::string(DicomImage::getString(img.getPhotometricInterpretation())) +
         " not supported. Attempting to convert to grayscale.");
   }

   if(imgDepth <= 8)
   {
      encoding = INT1UBYTE;
   }
   else if(imgDepth <= 16)
   {
      encoding = INT2UBYTES;
   }
   else if(imgDepth <= 32)
   {
      encoding = INT4UBYTES;
   }
   else
   {
      mWarnings.push_back("Bit depth " + StringUtilities::toDisplayString(imgDepth) + " not supported. Downgrading to 32 bits.");
      encoding = INT4UBYTES;
   }

   RasterDataDescriptor *pDescriptor = RasterUtilities::generateRasterDataDescriptor(
      filename, NULL, rows, columns, frames, interleave, encoding, IN_MEMORY);
   if(pDescriptor != NULL)
   {
      if(rgb)
      {
         pDescriptor->setDisplayBand(RED, pDescriptor->getBands()[0]);
         pDescriptor->setDisplayBand(GREEN, pDescriptor->getBands()[1]);
         pDescriptor->setDisplayBand(BLUE, pDescriptor->getBands()[2]);
         pDescriptor->setDisplayMode(RGB_MODE);
      }
      pImportDescriptor->setDataDescriptor(pDescriptor);
      FactoryResource<DynamicObject> pMeta;
      int idx = 0;
      DcmElement *pElmnt;
      while((pElmnt = fileformat.getDataset()->getElement(idx++)) != NULL)
      {
         if(pElmnt->error().bad())
         {
            continue;
         }
         const DcmTag &tag = pElmnt->getTag();
         std::string name = const_cast<DcmTag&>(tag).getTagName();
         if(name.empty())
         {
            name = QString("(%1,%2)").arg(pElmnt->getGTag(), 4, 16, QChar('0')).arg(pElmnt->getETag(), 4, 16, QChar('0')).toStdString();
         }
         pMeta->setAttributeByPath(std::string("DICOM/") + name, dcmElementToDataVariant(*pElmnt));
      }
      pImportDescriptor->getDataDescriptor()->setMetadata(pMeta.release());
   }
   RasterUtilities::generateAndSetFileDescriptor(pImportDescriptor->getDataDescriptor(), filename, std::string(), LITTLE_ENDIAN_ORDER);

   return descriptors;
}