📄 gdcmfile.cxx
字号:
std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
if ( PhotometricInterp == "YBR_FULL" )
{
return true;
}
if ( PhotometricInterp == GDCM_UNFOUND )
{
gdcmWarningMacro( "Not found : YBR Full (0028,0004)");
}
return false;
}
/**
* \brief tells us if LUT are used
* \warning Right now, 'Segmented xxx Palette Color Lookup Table Data'
* are NOT considered as LUT, since nobody knows
* how to deal with them
* Please warn me if you know sbdy that *does* know ... jprx
* @return true if LUT Descriptors and LUT Tables were found
*/
bool File::HasLUT()
{
// Check the presence of the LUT Descriptors, and LUT Tables
// LutDescriptorRed
if ( !GetDocEntry(0x0028,0x1101) )
{
return false;
}
// LutDescriptorGreen
if ( !GetDocEntry(0x0028,0x1102) )
{
return false;
}
// LutDescriptorBlue
if ( !GetDocEntry(0x0028,0x1103) )
{
return false;
}
// Red Palette Color Lookup Table Data
if ( !GetDocEntry(0x0028,0x1201) )
{
return false;
}
// Green Palette Color Lookup Table Data
if ( !GetDocEntry(0x0028,0x1202) )
{
return false;
}
// Blue Palette Color Lookup Table Data
if ( !GetDocEntry(0x0028,0x1203) )
{
return false;
}
// FIXME : (0x0028,0x3006) : LUT Data (CTX dependent)
// NOT taken into account, but we don't know how to use it ...
return true;
}
/**
* \brief gets the info from 0028,1101 : Lookup Table Desc-Red
* else 0
* @return Lookup Table number of Bits , 0 by default
* when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
* @ return bit number of each LUT item
*/
int File::GetLUTNbits()
{
std::vector<std::string> tokens;
int lutNbits;
//Just hope Lookup Table Desc-Red = Lookup Table Desc-Red
// = Lookup Table Desc-Blue
// Consistency already checked in GetLUTLength
std::string lutDescription = GetEntryValue(0x0028,0x1101);
if ( lutDescription == GDCM_UNFOUND )
{
return 0;
}
tokens.clear(); // clean any previous value
Util::Tokenize ( lutDescription, tokens, "\\" );
//LutLength=atoi(tokens[0].c_str());
//LutDepth=atoi(tokens[1].c_str());
lutNbits = atoi( tokens[2].c_str() );
tokens.clear();
return lutNbits;
}
// Special case:
// ts["1.2.840.10008.5.1.4.1.1.4.1"] = "Enhanced MR Image Storage";
bool File::GetRescaleSlopeIntercept(double &slope, double &intercept)
{
slope = 1.0;
intercept = 0.0;
TS *ts = Global::GetTS();
std::string sopclassuid_used;
// D 0002|0002 [UI] [Media Storage SOP Class UID]
const std::string &mediastoragesopclassuid_str = GetEntryValue(0x0002,0x0002);
const std::string &mediastoragesopclassuid = ts->GetValue(mediastoragesopclassuid_str);
//D 0008|0016 [UI] [SOP Class UID]
const std::string &sopclassuid_str = GetEntryValue(0x0008,0x0016);
const std::string &sopclassuid = ts->GetValue(sopclassuid_str);
if ( mediastoragesopclassuid == GDCM_UNFOUND && sopclassuid == GDCM_UNFOUND )
{
return false;
}
else
{
if( mediastoragesopclassuid == sopclassuid )
{
sopclassuid_used = mediastoragesopclassuid;
}
else
{
gdcmWarningMacro( "Inconsistant SOP Class UID: "
<< mediastoragesopclassuid << " and " << sopclassuid );
return false;
}
}
// ok we have now the correc SOP Class UID
if( sopclassuid_used == "Enhanced MR Image Storage" )
{
SeqEntry *PerframeFunctionalGroupsSequence = GetSeqEntry(0x5200,0x9230);
unsigned int n = PerframeFunctionalGroupsSequence->GetNumberOfSQItems();
if( !n ) return false;
SQItem *item1 = PerframeFunctionalGroupsSequence->GetFirstSQItem();
DocEntry *p = item1->GetDocEntry(0x0028,0x9145);
if( !p ) return false;
SeqEntry *seq = dynamic_cast<SeqEntry*>(p);
unsigned int n1 = seq->GetNumberOfSQItems();
if( !n1 ) return false;
SQItem *item2 = seq->GetFirstSQItem();
// D 0028|1052 [DS] [Rescale Intercept] [0 ]
DocEntry *p2 = item2->GetDocEntry(0x0028,0x1052);
if( !p2 ) return false;
ContentEntry *entry = dynamic_cast<ContentEntry *>(p2);
std::string intercept_str = entry->GetValue();
if ( sscanf( intercept_str.c_str(), "%lf", &intercept) != 1 )
{
intercept = 0.;
return false;
}
// D 0028|1053 [DS] [Rescale Slope] [5.65470085470085]
DocEntry *p3 = item2->GetDocEntry(0x0028,0x1053);
if( !p3 ) return false;
ContentEntry *entry2 = dynamic_cast<ContentEntry *>(p3);
std::string slope_str = entry2->GetValue();
if ( sscanf( slope_str.c_str(), "%lf", &slope) != 1 )
{
slope = 1.;
return false;
}
return true;
}
return false;
}
/**
*\brief gets the info from 0028,1052 : Rescale Intercept
* @return Rescale Intercept
*/
double File::GetRescaleIntercept()
{
double resInter = 0.;
double resSlope = 1.0;
if ( GetRescaleSlopeIntercept(resSlope, resInter) )
{
return resInter;
}
/// 0028 1052 DS IMG Rescale Intercept
const std::string &strRescInter = GetEntryValue(0x0028,0x1052);
if ( strRescInter != GDCM_UNFOUND )
{
if ( sscanf( strRescInter.c_str(), "%lf ", &resInter) != 1 )
{
// bug in the element 0x0028,0x1052
gdcmWarningMacro( "Rescale Intercept (0028,1052) is empty." );
}
}
return resInter;
}
/**
*\brief gets the info from 0028,1053 : Rescale Slope
* @return Rescale Slope. defaulted to 1.0 is not found, == 0.0 or empty
*/
double File::GetRescaleSlope()
{
double resInter = 0.;
double resSlope = 1.;
if ( GetRescaleSlopeIntercept(resSlope, resInter) )
{
return resSlope;
}
//0028 1053 DS IMG Rescale Slope
std::string strRescSlope = GetEntryValue(0x0028,0x1053);
if ( strRescSlope != GDCM_UNFOUND )
{
if ( sscanf( strRescSlope.c_str(), "%lf ", &resSlope) != 1 )
{
// bug in the element 0x0028,0x1053
gdcmWarningMacro( "Rescale Slope (0028,1053) is empty.");
}
}
if( resSlope == 0. )
{
gdcmWarningMacro( "No such thing as a slope of 0.0. Defaulting to 1.0 value" );
return 1.0;
}
return resSlope;
}
/**
* \brief This function is intended to user who doesn't want
* to have to manage a LUT and expects to get an RBG Pixel image
* (or a monochrome one ...)
* \warning to be used with GetImagePixels()
* @return 1 if Gray level, 3 if Color (RGB, YBR, *or PALETTE COLOR*)
*/
int File::GetNumberOfScalarComponents()
{
if ( GetSamplesPerPixel() == 3 )
{
return 3;
}
// 0028 0100 US IMG Bits Allocated
// (in order no to be messed up by old RGB images)
if ( GetEntryValue(0x0028,0x0100) == "24" )
{
return 3;
}
std::string strPhotometricInterpretation = GetEntryValue(0x0028,0x0004);
if ( Util::DicomStringEqual(strPhotometricInterpretation, "PALETTE COLOR") )
{
if ( HasLUT() )// PALETTE COLOR is NOT enough
{
return 3;
}
else
{
return 1;
}
}
// beware of trailing space at end of string
// DICOM tags are never of odd length
if ( strPhotometricInterpretation == GDCM_UNFOUND ||
Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") ||
Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") )
{
return 1;
}
else
{
// we assume that *all* kinds of YBR are dealt with
return 3;
}
}
/**
* \brief This function is intended to user that DOESN'T want
* to get RGB pixels image when it's stored as a PALETTE COLOR image
* - the (vtk) user is supposed to know how deal with LUTs -
* \warning to be used with GetImagePixelsRaw()
* @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -)
*/
int File::GetNumberOfScalarComponentsRaw()
{
// 0028 0100 US IMG Bits Allocated
// (in order no to be messed up by old RGB images)
if ( File::GetEntryValue(0x0028,0x0100) == "24" )
{
return 3;
}
// we assume that *all* kinds of YBR are dealt with
return GetSamplesPerPixel();
}
/**
* \brief Recover the offset (from the beginning of the file)
* of *image* pixels (not *icone image* pixels, if any !)
* @return Pixel Offset
*/
size_t File::GetPixelOffset()
{
DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
if ( pxlElement )
{
return pxlElement->GetOffset();
}
else
{
gdcmDebugMacro( "Big trouble : Pixel Element ("
<< std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
return 0;
}
}
/**
* \brief Recover the pixel area length (in Bytes)
* @return Pixel Element Length, as stored in the header
* (NOT the memory space necessary to hold the Pixels
* -in case of embeded compressed image-)
* 0 : NOT USABLE file. The caller has to check.
*/
size_t File::GetPixelAreaLength()
{
DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
if ( pxlElement )
{
return pxlElement->GetLength();
}
else
{
gdcmDebugMacro( "Big trouble : Pixel Element ("
<< std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
return 0;
}
}
/**
* \brief Adds the characteristics of a new element we want to anonymize
* @param group Group number of the target tag.
* @param elem Element number of the target tag.
* @param value new value (string) to substitute with
*/
void File::AddAnonymizeElement (uint16_t group, uint16_t elem,
std::string const &value)
{
Element el;
el.Group = group;
el.Elem = elem;
el.Value = value;
UserAnonymizeList.push_back(el);
}
/**
* \brief Overwrites in the file the values of the DicomElements
* held in the list
*/
void File::AnonymizeNoLoad()
{
std::fstream *fp = new std::fstream(Filename.c_str(),
std::ios::in | std::ios::out | std::ios::binary);
gdcm::DocEntry *d;
uint32_t offset;
uint32_t lgth;
uint32_t valLgth = 0;
std::string *spaces;
for (ListElements::iterator it = UserAnonymizeList.begin();
it != UserAnonymizeList.end();
++it)
{
d = GetDocEntry( (*it).Group, (*it).Elem);
if ( d == NULL)
continue;
if ( dynamic_cast<SeqEntry *>(d) )
{
gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
continue;
}
offset = (uint32_t)(d->GetOffset());
lgth = d->GetLength();
if (valLgth < lgth)
{
spaces = new std::string( lgth-valLgth, ' ');
(*it).Value = (*it).Value + *spaces;
delete spaces;
}
fp->seekp( offset, std::ios::beg );
fp->write( (*it).Value.c_str(), lgth );
}
fp->close();
delete fp;
}
/**
* \brief anonymize a File (remove Patient's personal info passed with
* AddAnonymizeElement()
* \note You cannot Anonymize a BinEntry (to be fixed)
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -