Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault #4604

Open
Mr-Blue-Sky-Candy opened this issue Apr 22, 2024 · 25 comments
Open

Segmentation fault #4604

Mr-Blue-Sky-Candy opened this issue Apr 22, 2024 · 25 comments

Comments

@Mr-Blue-Sky-Candy
Copy link

I only get segmentation fault. I can share the code I wrote but not the Dicom series. The code I wrote works for all others but not for some particular CT scans. How can I help you resolve this?

The code I wrote is the following:

names_generator = itk.GDCMSeriesFileNames.New()
names_generator.SetUseSeriesDetails(True)
names_generator.SetGlobalWarningDisplay(True)
names_generator.SetNumberOfWorkUnits(os.cpu_count())
names_generator.SetLoadPrivateTags(False)
names_generator.DebugOn()

dicomIO = itk.GDCMImageIO.New()
dicomIO.LoadPrivateTagsOff()
dicomIO.SetGlobalWarningDisplay(True)
reader = itk.ImageSeriesReader[itk.Image[itk.ctype("int"), 3]].New()
reader.SetGlobalWarningDisplay(True)
reader.SetMetaDataDictionaryArrayUpdate(True)
reader.SetNumberOfWorkUnits(os.cpu_count())
reader.SetImageIO(dicomIO)
reader.ForceOrthogonalDirectionOff()

It gives segmentation fault at the line
names_generator.SetDirectory(folder)

This code also gives segmentation fault:

reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(folder)
reader.SetFileNames(dicom_names)
image = reader.Execute()

Pydicom is able to read it but its metadata is very messy and hard to format besides it cannot read other particular Dicom series of CT scans.

ITK version is 5.3 on both ubuntu 22 and archlinux

@dzenanz dzenanz transferred this issue from InsightSoftwareConsortium/ITKPythonPackage Apr 22, 2024
Copy link

Thank you for contributing an issue! 🙏

Welcome to the ITK community! 🤗👋☀️

We are glad you are here and appreciate your contribution. Please keep in mind our community participation guidelines. 📜
Also, please check existing open issues and consider discussion on the ITK Discourse. 📖

This is an automatic message. Allow for time for the ITK community to be able to read the issue and comment on it.

@dzenanz
Copy link
Member

dzenanz commented Apr 22, 2024

I assume that this is not related to Python packaging, but to underlying GDCM code. Reproducing without data will probably be hard. Can you try anonymizing your DICOM file(s) and then sharing them? Use this or one of many other tools.

@Mr-Blue-Sky-Candy
Copy link
Author

I agree it is due to binded cpp or c code but I cannot share the dicom files. I know how to code cpp as well but I don't know how to debug a python binding. If there is a way I can help about this, I would be happy to do so

@dzenanz
Copy link
Member

dzenanz commented Apr 22, 2024

Can you try C++ code from this example on your DICOM data? Does it also crash?

@thewtex
Copy link
Member

thewtex commented Apr 22, 2024

Hi, could you please try with itk-5.4rc4? Do the same results occur?

@thewtex
Copy link
Member

thewtex commented Apr 22, 2024

Also,

image = itk.imread('path/to/dicom/dir/')

@Mr-Blue-Sky-Candy
Copy link
Author

Hi, could you please try with itk-5.4rc4? Do the same results occur?

this also failed

@Mr-Blue-Sky-Candy
Copy link
Author

Also,

image = itk.imread('path/to/dicom/dir/')

I already tried but forgot to mention. The outcome is the same

@thewtex
Copy link
Member

thewtex commented Apr 22, 2024

If you set up a debug build and get a backtrace, it will likely be evident where the issue exists. Please see Section 9.5.3 in The ITK Software Guide, Book 1 for guidance.

@Mr-Blue-Sky-Candy
Copy link
Author

Mr-Blue-Sky-Candy commented Apr 22, 2024

Hey, I had to refresh my cpp skills. I ran with debug mode but I always used qt creator run debug mode. So I can see this:

1  ??                                                                                                 0x7ffff4cab32c 
2  raise                                                                                              0x7ffff4c5a6c8 
3  abort                                                                                              0x7ffff4c424b8 
4  std::__glibcxx_assert_fail                                             debug.cc                 61 0x7ffff4edd3b2 
5  ??                                                                                                 0x7ffff654881e 
6  gdcm::PixmapReader::ReadImageInternal(gdcm::MediaStorage const&, bool)                             0x7ffff654ab16 
7  gdcm::ImageReader::ReadImage(gdcm::MediaStorage const&)                                            0x7ffff654c880 
8  gdcm::PixmapReader::Read()                                                                         0x7ffff65472da 
9  gdcm::SerieHelper::AddFileName(std::string const&)                                                 0x7ffff6522c7d 
10 gdcm::SerieHelper::SetDirectory(std::string const&, bool)                                          0x7ffff6522f3c 
11 itk::GDCMSeriesFileNames::SetInputDirectory(std::string const&)                                    0x7ffff698ebb4 
12 itk::GDCMSeriesFileNames::SetDirectory                                 itkGDCMSeriesFileNames.h 98 0x555555567b5d 
13 main                                                                   main.cpp                 32 0x555555566dc5 

Is this good?
It also show disassembler output. If you need me to share something else, let me know. I don't know how to proceed from this point on:
image

@thewtex
Copy link
Member

thewtex commented Apr 22, 2024

Nice!

It would be helpful to build as Debug CMAKE_BUILD_TYPE and find out the line number that identifies which assert is failing:

bool PixmapReader::ReadImageInternal(MediaStorage const &ms, bool handlepixeldata )
{
const DataSet &ds = F->GetDataSet();
std::string conversion;
bool isacrnema = false;
const Tag trecognitioncode(0x0008,0x0010);
if( ds.FindDataElement( trecognitioncode ) && !ds.GetDataElement( trecognitioncode ).IsEmpty() )
{
// PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm
// PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm
gdcmDebugMacro( "Mixture of ACR NEMA and DICOM file" );
isacrnema = true;
const char *str = ds.GetDataElement( trecognitioncode ).GetByteValue()->GetPointer();
assert( strncmp( str, "ACR-NEMA", strlen( "ACR-NEMA" ) ) == 0 ||
strncmp( str, "ACRNEMA", strlen( "ACRNEMA" ) ) == 0 ||
strncmp( str, "MIPS 2.0", strlen( "MIPS 2.0" ) ) == 0 );
(void)str;//warning removal
}
std::vector<unsigned int> vdims = ImageHelper::GetDimensionsValue(*F);
unsigned int numberofframes = vdims[2];
// What should I do when numberofframes == 0 ?
if( numberofframes > 1 )
{
PixelData->SetNumberOfDimensions(3);
PixelData->SetDimension(2, numberofframes );
}
else
{
gdcmDebugMacro( "NumberOfFrames was specified with a value of: "
<< numberofframes );
PixelData->SetNumberOfDimensions(2);
}
// 2. What are the col & rows:
PixelData->SetDimension(0, vdims[0] );
PixelData->SetDimension(1, vdims[1] );
// 3. Pixel Format ?
PixelFormat pf;
// D 0028|0002 [US] [Samples per Pixel] [1]
{
Attribute<0x0028,0x0002> at = { 1 }; // By default assume 1 Samples Per Pixel
at.SetFromDataSet( ds );
pf.SetSamplesPerPixel( at.GetValue() );
}
if( ms == MediaStorage::MRSpectroscopyStorage )
{
pf.SetScalarType( PixelFormat::FLOAT32 );
}
else
{
assert( MediaStorage::IsImage( ms ) );
// D 0028|0100 [US] [Bits Allocated] [16]
//pf.SetBitsAllocated(
// ReadUSFromTag( Tag(0x0028, 0x0100), ss, conversion ) );
{
//const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) );
Attribute<0x0028,0x0100> at = { 0 };
at.SetFromDataSet( ds );
pf.SetBitsAllocated( at.GetValue() );
//assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0100), ss, conversion ) );
}
// D 0028|0101 [US] [Bits Stored] [12]
//pf.SetBitsStored(
// ReadUSFromTag( Tag(0x0028, 0x0101), ss, conversion ) );
{
//const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) );
Attribute<0x0028,0x0101> at = { 0 };
at.SetFromDataSet( ds );
pf.SetBitsStored( at.GetValue() );
//assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0101), ss, conversion ) );
}
// D 0028|0102 [US] [High Bit] [11]
//pf.SetHighBit(
// ReadUSFromTag( Tag(0x0028, 0x0102), ss, conversion ) );
{
//const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) );
Attribute<0x0028,0x0102> at = { 0 };
at.SetFromDataSet( ds );
pf.SetHighBit( at.GetValue() );
//assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0102), ss, conversion ) );
}
// D 0028|0103 [US] [Pixel Representation] [0]
//Tag tpixelrep(0x0028, 0x0103);
//if( ds.FindDataElement( tpixelrep ) && !ds.GetDataElement( tpixelrep ).IsEmpty() )
{
//pf.SetPixelRepresentation(
// ReadUSFromTag( Tag(0x0028, 0x0103), ss, conversion ) );
//const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) );
Attribute<0x0028,0x0103> at = { 0 };
at.SetFromDataSet( ds );
pf.SetPixelRepresentation( at.GetValue() );
//assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0103), ss, conversion ) );
}
// else
// {
// gdcmWarningMacro( "Pixel Representation was not found. Default to Unsigned Pixel Representation" );
// pf.SetPixelRepresentation( 0 );
// }
}
// 5. Photometric Interpretation
// D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ]
const Tag tphotometricinterpretation(0x0028, 0x0004);
const ByteValue *photometricinterpretation
= ImageHelper::GetPointerFromElement( tphotometricinterpretation, *F );
PhotometricInterpretation pi = PhotometricInterpretation::UNKNOWN;
if( photometricinterpretation )
{
std::string photometricinterpretation_str(
photometricinterpretation->GetPointer(),
photometricinterpretation->GetLength() );
pi = PhotometricInterpretation::GetPIType( photometricinterpretation_str.c_str() );
// http://www.dominator.com/assets/003/5278.pdf
// JPEG 2000 lossless YUV_RCT
if( pi == PhotometricInterpretation::PI_END )
{
gdcmWarningMacro( "Discarding suspicious PhotometricInterpretation found: "
<< photometricinterpretation_str );
}
}
// try again harder:
if( !photometricinterpretation || pi == PhotometricInterpretation::PI_END )
{
if( pf.GetSamplesPerPixel() == 1 )
{
gdcmWarningMacro( "No PhotometricInterpretation found, default to MONOCHROME2" );
pi = PhotometricInterpretation::MONOCHROME2;
}
else if( pf.GetSamplesPerPixel() == 3 )
{
gdcmWarningMacro( "No PhotometricInterpretation found, default to RGB" );
pi = PhotometricInterpretation::RGB;
}
else if( pf.GetSamplesPerPixel() == 4 )
{
gdcmWarningMacro( "No PhotometricInterpretation found, default to ARGB" );
pi = PhotometricInterpretation::ARGB;
}
else
{
gdcmWarningMacro( "Impossible value for Samples Per Pixel: " << pf.GetSamplesPerPixel() );
return false;
}
}
assert( pi != PhotometricInterpretation::PI_END );
if( !pf.GetSamplesPerPixel() || (pi.GetSamplesPerPixel() != pf.GetSamplesPerPixel()) )
{
if( pi != PhotometricInterpretation::UNKNOWN )
{
pf.SetSamplesPerPixel( pi.GetSamplesPerPixel() );
}
else if ( isacrnema )
{
assert ( pf.GetSamplesPerPixel() == 0 );
assert ( pi == PhotometricInterpretation::UNKNOWN );
pf.SetSamplesPerPixel( 1 );
pi = PhotometricInterpretation::MONOCHROME2;
}
else
{
gdcmWarningMacro( "Cannot recognize image type. Does not looks like"
"ACR-NEMA and is missing both Sample Per Pixel AND PhotometricInterpretation."
"Please report" );
return false;
}
}
assert ( pf.GetSamplesPerPixel() != 0 );
// Very important to set the PixelFormat here before PlanarConfiguration
PixelData->SetPixelFormat( pf );
pf = PixelData->GetPixelFormat();
if( !pf.IsValid() )
{
return false;
}
if( pi == PhotometricInterpretation::UNKNOWN ) return false;
PixelData->SetPhotometricInterpretation( pi );
// 4. Planar Configuration
// D 0028|0006 [US] [Planar Configuration] [1]
const Tag planarconfiguration = Tag(0x0028, 0x0006);
// FIXME: Whatif planaconfiguration is send in a grayscale image... it would be empty...
// well hopefully :(
if( ds.FindDataElement( planarconfiguration ) && !ds.GetDataElement( planarconfiguration ).IsEmpty() )
{
const DataElement& de = ds.GetDataElement( planarconfiguration );
Attribute<0x0028,0x0006> at = { 0 };
at.SetFromDataElement( de );
//unsigned int pc = ReadUSFromTag( planarconfiguration, ss, conversion );
unsigned int pc = at.GetValue();
if( pc && PixelData->GetPixelFormat().GetSamplesPerPixel() != 3 )
{
gdcmDebugMacro( "Cannot have PlanarConfiguration=1, when Sample Per Pixel != 3" );
pc = 0;
}
PixelData->SetPlanarConfiguration( pc );
}
// Do the Palette Color:
// 1. Modality LUT Sequence
bool modlut = ds.FindDataElement(Tag(0x0028,0x3000) );
if( modlut )
{
gdcmWarningMacro( "Modality LUT (0028,3000) are not handled. Image will not be displayed properly" );
}
// 2. LUTData (0028,3006)
// technically I do not need to warn about LUTData since either modality lut XOR VOI LUT need to
// be sent to require a LUT Data...
bool lutdata = ds.FindDataElement(Tag(0x0028,0x3006) );
if( lutdata )
{
gdcmWarningMacro( "LUT Data (0028,3006) are not handled. Image will not be displayed properly" );
}
// 3. VOILUTSequence (0028,3010)
bool voilut = ds.FindDataElement(Tag(0x0028,0x3010) );
if( voilut )
{
gdcmWarningMacro( "VOI LUT (0028,3010) are not handled. Image will not be displayed properly" );
}
// (0028,0120) US 32767 # 2, 1 PixelPaddingValue
bool pixelpaddingvalue = ds.FindDataElement(Tag(0x0028,0x0120));
// PS 3.3 - 2008 / C.7.5.1.1.2 Pixel Padding Value and Pixel Padding Range Limit
if(pixelpaddingvalue)
{
// Technically if Pixel Padding Value is 0 on MONOCHROME2 image, then appearance should be fine...
bool vizissue = true;
if( pf.GetPixelRepresentation() == 0 )
{
Element<VR::US,VM::VM1> ppv;
if( !ds.GetDataElement(Tag(0x0028,0x0120) ).IsEmpty() )
{
ppv.SetFromDataElement( ds.GetDataElement(Tag(0x0028,0x0120)) ); //.GetValue() );
if( pi == PhotometricInterpretation::MONOCHROME2 && ppv.GetValue() == 0 )
{
vizissue = false;
}
}
}
else if( pf.GetPixelRepresentation() == 1 )
{
gdcmDebugMacro( "TODO" );
}
// test if there is any viz issue:
if( vizissue )
{
gdcmDebugMacro( "Pixel Padding Value (0028,0120) is not handled. Image will not be displayed properly" );
}
}
// 4. Palette Color Lookup Table Descriptor
if ( pi == PhotometricInterpretation::PALETTE_COLOR )
{
//const DataElement& modlutsq = ds.GetDataElement( Tag(0x0028,0x3000) );
//const SequenceOfItems* sq = modlutsq.GetSequenceOfItems();
//SequenceOfItems::ConstIterator it = sq->Begin();
//const DataSet &ds = it->GetNestedDataSet();
SmartPointer<LookupTable> lut = new LookupTable;
const Tag testseglut(0x0028, (0x1221 + 0));
if( ds.FindDataElement( testseglut ) )
{
lut = new SegmentedPaletteColorLookupTable;
}
//SmartPointer<SegmentedPaletteColorLookupTable> lut = new SegmentedPaletteColorLookupTable;
lut->Allocate( pf.GetBitsAllocated() );
// for each red, green, blue:
for(int i=0; i<3; ++i)
{
// (0028,1101) US 0\0\16
// (0028,1102) US 0\0\16
// (0028,1103) US 0\0\16
const Tag tdescriptor(0x0028, (uint16_t)(0x1101 + i));
//const Tag tdescriptor(0x0028, 0x3002);
Element<VR::US,VM::VM3> el_us3 = {{ 0, 0, 0}};
// Now pass the byte array to a DICOMizer:
el_us3.SetFromDataElement( ds[tdescriptor] ); //.GetValue() );
lut->InitializeLUT( LookupTable::LookupTableType(i),
el_us3[0], el_us3[1], el_us3[2] );
// (0028,1201) OW
// (0028,1202) OW
// (0028,1203) OW
const Tag tlut(0x0028, (uint16_t)(0x1201 + i));
//const Tag tlut(0x0028, 0x3006);
// Segmented LUT
// (0028,1221) OW
// (0028,1222) OW
// (0028,1223) OW
const Tag seglut(0x0028, (uint16_t)(0x1221 + i));
if( ds.FindDataElement( tlut ) )
{
const ByteValue *lut_raw = ds.GetDataElement( tlut ).GetByteValue();
if( lut_raw )
{
// LookupTableType::RED == 0
lut->SetLUT( LookupTable::LookupTableType(i),
(const unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() );
//assert( pf.GetBitsAllocated() == el_us3.GetValue(2) );
}
else
{
lut->Clear();
}
unsigned long check =
(el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536)
* el_us3.GetValue(2) / 8;
assert( !lut->Initialized() || check == lut_raw->GetLength() ); (void)check;
}
else if( ds.FindDataElement( seglut ) )
{
const ByteValue *lut_raw = ds.GetDataElement( seglut ).GetByteValue();
if( lut_raw )
{
lut->SetLUT( LookupTable::LookupTableType(i),
(const unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() );
//assert( pf.GetBitsAllocated() == el_us3.GetValue(2) );
}
else
{
lut->Clear();
}
//unsigned long check =
// (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536)
// * el_us3.GetValue(2) / 8;
//assert( check == lut_raw->GetLength() ); (void)check;
}
else
{
gdcmAssertAlwaysMacro(0);
}
}
if( ! lut->Initialized() ) return false;
PixelData->SetLUT(*lut);
}
// TODO
//assert( pi.GetSamplesPerPixel() == pf.GetSamplesPerPixel() );
// 5.5 Do IconImage if any
assert( PixelData->GetIconImage().IsEmpty() );
DoIconImage(ds, *PixelData);
// 6. Do the Curves if any
DoCurves(ds, *PixelData);
// 7. Do the Overlays if any
if( !DoOverlays(ds, *PixelData) )
{
return false;
}
// 8. Do the PixelData
if( handlepixeldata )
{
if( ms == MediaStorage::MRSpectroscopyStorage )
{
const Tag spectdata = Tag(0x5600, 0x0020);
if( !ds.FindDataElement( spectdata ) )
{
gdcmWarningMacro( "No Spectroscopy Data Found" );
return false;
}
const DataElement& xde = ds.GetDataElement( spectdata );
//bool need = PixelData->GetTransferSyntax() == TransferSyntax::ImplicitVRBigEndianPrivateGE;
//PixelData->SetNeedByteSwap( need );
PixelData->SetDataElement( xde );
}
else
{
const Tag pixeldata = Tag(0x7fe0, 0x0010);
if( !ds.FindDataElement( pixeldata ) )
{
gdcmWarningMacro( "No Pixel Data Found" );
return false;
}
const DataElement& xde = ds.GetDataElement( pixeldata );
bool need = PixelData->GetTransferSyntax() == TransferSyntax::ImplicitVRBigEndianPrivateGE;
PixelData->SetNeedByteSwap( need );
PixelData->SetDataElement( xde );
if( PixelData->GetTransferSyntax().IsEncapsulated() && PixelData->GetDataElement().GetByteValue() )
{
// Pixel Data attribute is not encapsulated, let's check for simple user error
const ByteValue *bv = PixelData->GetDataElement().GetByteValue();
if( bv->GetLength() == PixelData->GetBufferLength() ||
bv->GetLength() == PixelData->GetBufferLength() + 1 )
{
gdcmWarningMacro( "Pixel Data was found to be raw. Fixing invalid Transfer Syntax: " << PixelData->GetTransferSyntax() );
PixelData->SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian );
}
}
// FIXME:
// We should check that when PixelData is RAW that Col * Dim == PixelData->GetLength()
//PixelFormat guesspf = PixelFormat->GuessPixelFormat();
}
const unsigned int *dims = PixelData->GetDimensions();
if( dims[0] == 0 || dims[1] == 0 )
{
// Pseudo-declared JPEG SC image storage. Let's fix col/row/pf/pi
JPEGCodec jpeg;
if( jpeg.CanDecode( PixelData->GetTransferSyntax() ) )
{
std::stringstream ss;
const DataElement &de = PixelData->GetDataElement();
//const ByteValue *bv = de.GetByteValue();
const SequenceOfFragments *sqf = de.GetSequenceOfFragments();
if( !sqf )
{
// TODO: It would be nice to recognize file such as JPEGDefinedLengthSequenceOfFragments.dcm
gdcmDebugMacro( "File is declared as JPEG compressed but does not contains Fragments explicitly." );
return false;
}
sqf->WriteBuffer( ss );
//std::string s( bv->GetPointer(), bv->GetLength() );
//is.str( s );
PixelFormat jpegpf ( PixelFormat::UINT8 ); // usual guess...
jpeg.SetPixelFormat( jpegpf );
TransferSyntax ts;
bool b = jpeg.GetHeaderInfo( ss, ts );
if( b )
{
std::vector<unsigned int> v(3);
v[0] = PixelData->GetDimensions()[0];
v[1] = PixelData->GetDimensions()[1];
v[2] = PixelData->GetDimensions()[2];
assert( jpeg.GetDimensions()[0] );
assert( jpeg.GetDimensions()[1] );
v[0] = jpeg.GetDimensions()[0];
v[1] = jpeg.GetDimensions()[1];
PixelData->SetDimensions( v.data() );
//PixelData->SetPixelFormat( jpeg.GetPixelFormat() ); // need to handle carefully
if( PixelData->GetPixelFormat().GetSamplesPerPixel() != jpeg.GetPixelFormat().GetSamplesPerPixel() )
{
gdcmDebugMacro( "Fix samples per pixel." );
PixelData->GetPixelFormat().SetSamplesPerPixel( jpeg.GetPixelFormat().GetSamplesPerPixel() );
}
//PixelData->SetPhotometricInterpretation( jpeg.GetPhotometricInterpretation() );
if( PixelData->GetPhotometricInterpretation().GetSamplesPerPixel() != jpeg.GetPhotometricInterpretation().GetSamplesPerPixel() )
{
gdcmDebugMacro( "Fix photometric interpretation." );
PixelData->SetPhotometricInterpretation( jpeg.GetPhotometricInterpretation() );
}
assert( PixelData->IsTransferSyntaxCompatible( ts ) );
}
else
{
gdcmDebugMacro( "Columns or Row was found to be 0. Cannot compute dimension." );
return false;
}
}
else
{
gdcmDebugMacro( "Columns or Row was found to be 0. Cannot compute dimension." );
return false;
}
}
}
// Let's be smart when computing the lossyflag (0028,2110)
// LossyImageCompression
Attribute<0x0028,0x2110> licat;
bool lossyflag = false;
bool haslossyflag = false;
if( ds.FindDataElement( licat.GetTag() ) )
{
haslossyflag = true;
licat.SetFromDataSet( ds ); // could be empty
const CSComp & v = licat.GetValue();
lossyflag = atoi( v.c_str() ) == 1;
// Note: technically one can decompress into uncompressed form (eg.
// Implicit Little Endian) an input JPEG Lossy. So we need to check
// the attribute LossyImageCompression value:
PixelData->SetLossyFlag(lossyflag);
}
// Two cases:
// - DataSet did not specify the lossyflag
// - DataSet specify it to be 0, but there is still a chance it could be wrong:
// execute computation of lossy flag eny time the TS is encapsulated so as to
// update the correct PixelFormat as early as possible and not during
// decompression in case of mismatch:
if( (!haslossyflag || !lossyflag)
|| PixelData->GetTransferSyntax().IsEncapsulated() )
{
PixelData->ComputeLossyFlag();
if( PixelData->IsLossy() && (!lossyflag && haslossyflag ) )
{
// We always prefer the setting from the stream...
gdcmWarningMacro( "DataSet set LossyFlag to 0, while Codec made the stream lossy" );
}
// Make sure to combine DICOM info + pixel data bitstream:
PixelData->SetLossyFlag( PixelData->IsLossy() || lossyflag);
}
return true;
}

CC @malaterre

@Mr-Blue-Sky-Candy
Copy link
Author

I can see this in the command line output:

$ ./test_itk ../../../../work/AIRTQA/r-008-023-2-corrupt/
/usr/include/c++/13.2.1/bits/stl_vector.h:1125: std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[](size_type) [with _Tp = gdcm::Curve; _Alloc = std::allocator<gdcm::Curve>; reference = gdcm::Curve&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.
Aborted (core dumped)

@thewtex
Copy link
Member

thewtex commented Apr 22, 2024

@Mr-Blue-Sky-Candy I expect that there is a line number associated with gdcmPixmapReader.cxx that has an assert statement when a Debug build is created and it is debugged as described in the ITK Software Guide.

@Mr-Blue-Sky-Candy
Copy link
Author

I am already building Debug builds but as it is described in ITK software guide I switched to RelWithDebInfo build anyway. Unsurprisingly, the result is the same.

@thewtex
Copy link
Member

thewtex commented May 1, 2024

@Mr-Blue-Sky-Candy there are no line numbers for the screenshot shared in the GDCM calls -- is ITK_USE_SYSTEM_GDCM OFF?

@Mr-Blue-Sky-Candy
Copy link
Author

I added set(ITK_USE_SYSTEM_GDCM ON) to the CMakeLists.txt but the result is the same

@thewtex
Copy link
Member

thewtex commented May 2, 2024

The setting should be:

set(ITK_USE_SYSTEM_GDCM OFF)

So GDCM with a Debug build is used. Examining with gdb may be helpful as suggested in the ITK Software Guide.

@Mr-Blue-Sky-Candy
Copy link
Author

I am already running in qtcreator with gdb.

@Mr-Blue-Sky-Candy there are no line numbers for the screenshot shared in the GDCM calls -- is ITK_USE_SYSTEM_GDCM OFF?

Actually there is. I will share a different view with set(ITK_USE_SYSTEM_GDCM OFF):
image

@thewtex
Copy link
Member

thewtex commented May 2, 2024

We are looking for what is happening at Level 7:

image

@Mr-Blue-Sky-Candy
Copy link
Author

Mr-Blue-Sky-Candy commented May 2, 2024

Ahh OK. Thanks. I recompiled the system gdcm with debug symbols. Here you go:
image

@Mr-Blue-Sky-Candy
Copy link
Author

All functions look better here
image

@thewtex
Copy link
Member

thewtex commented May 2, 2024

Thanks, closer!

You will need to step through the code in gdcmPixmapReader (set a breakpoint in QtCreater) to understand what content that is expected is not present.

@Mr-Blue-Sky-Candy
Copy link
Author

Mr-Blue-Sky-Candy commented May 2, 2024

image
Here return Curves[i] in the file gdcmPixmap.h:47, i is 7 but it is larger than the size of Curves

@thewtex
Copy link
Member

thewtex commented May 3, 2024

@malaterre any suggestions?

@malaterre
Copy link
Member

@thewtex Curve module have been deprecated for years now. Without the actual DICOM DataSet there are plenty ways to create an illegal structure.

@Mr-Blue-Sky-Candy If you cannot share the DICOM file, I suggest building with 'Debug', you should at least get the proper behavior for 'assert' and hopefully track the root issue (not symptom).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants