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; }
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()); }
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; }