ismrmrd / ge_to_ismrmrd

GE to ISMRMRD converter
Other
7 stars 9 forks source link

Where are "passes" looped? #10

Open brunoriemenschneider opened 4 years ago

brunoriemenschneider commented 4 years ago

Hi,

I have converted some GE Scanarchives with several "passes", as GE calls them. In Orchestra, all passes can be recovered from the Scanarchive. However, after conversion to ismrmrd, I do not find the passes except for the first - the corresponding slices of further passes contain 0's. Tried in Matlab and Python. While there are the variables contrasts and repetitions with values > 1 in encoding.encodingLimits, there is no data for contrast and repetition > 1 (i.e., only 0's). There are no other encodingLimits that could be looped through.

System version is DV26.0_R05_2008.a Orchestra used with ge_to_ismrmrd: 1.7

roopchansinghv commented 4 years ago

The current GE converter implementation has no explicit handling of pass loops.

The current ScanArchive handling routine reads how many acquisition packets are in the ScanArchive, and iterates over all packets reported back.

What you could possibly try is to figure out the number of passes in your acquisition. From what I could tell, it would be similar to how the converter currently determines the slice that acquisition belongs to. That code is:

sliceID = GERecon::Acquisition::GetPacketValue(packetContents.sliceNumH, packetContents.sliceNumL);

You would probably need to do something similar for identifying your pass, i.e. something like:

passID = GERecon::Acquisition::GetPacketValue(packetContents.passSourceL, packetContents.passDestL);

You can the assign the passID to segment acquisition encoding counter for ISMRMRD, something along the lines of:

idx.segment = passID;

and see if that allows all data in all passes to be encoded.

In the documentation I could see, anything else referring to passes refer to the older raw data format (P-Files), or to specific applications that uses passes. The above was the only generic, non-application specific reference to "passes" I could find.

Let me know if this works. If it does, I can patch in the above code.

brunoriemenschneider commented 4 years ago

According to our techs who acquired the data these were acquired with FLAIR product sequences (underlying sequence "FSE-XL").

Suggested changes lead to

[...]/ismrmrd/ge_to_ismrmrd/src/GenericConverter.cpp: In member function ‘virtual std::vector PfileToIsmrmrd::GenericConverter::getAcquisitions(GERecon::ScanArchivePointer&, unsigned int)’: [...]/ismrmrd/ge_to_ismrmrd/src/GenericConverter.cpp:218:3: error: ‘passID’ was not declared in this scope passID = GERecon::Acquisition::GetPacketValue(packetContents.passSourceL, packetContents.passDestL); ^ [...]/ismrmrd/ge_to_ismrmrd/src/GenericConverter.cpp:218:64: error: ‘const struct GERecon::Acquisition::ProgrammableControlPacket’ has no member named ‘passSourceL’ passID = GERecon::Acquisition::GetPacketValue(packetContents.passSourceL, packetContents.passDestL); ^ [...]/ismrmrd/ge_to_ismrmrd/src/GenericConverter.cpp:218:92: error: ‘const struct GERecon::Acquisition::ProgrammableControlPacket’ has no member named ‘passDestL’ passID = GERecon::Acquisition::GetPacketValue(packetContents.passSourceL, packetContents.passDestL);

roopchansinghv commented 4 years ago

The first error is trivial - it just requires the 'passID' variable to be defined.

However, the subsequent errors are a bit more troubling, as it seems to indicate, that for the application (you mentioned FSE-XL), that passSourceL and passDestL were not defined.

Could you try this to see if this code (put at approximately the same place as the above) reports the correct number of passes that should be in your ScanArchive:

std::cout << "Number of passes is: " << processingControl->Value("NumPasses") << std::endl ;

If it does, then what you can try is to create an instance of the sliceTable describing your acquisition. So below the line:

GERecon::Control::ProcessingControlPointer processingControl = controlSource->CreateOrchestraProcessingControl();

add this line:

auto sliceTable = GERecon::Legacy::LxSliceTable(*lxData);

Then, look through Orchestra's documentation to see how you can access the elements with the LxSliceTable object to tell you which slice / pass / slice-in-pass you are dealing with.

I did a bit of digging at the end of last week and this morning, but this needs more time than I am able to spend on this right now. I am trying to get geometry information from GE raw data into the ISMRMRD header in a reasonable way, so people can make DICOMs as output ...

If you come up with a path to access the slice table data, I am happy to review a pull request to add to the existing functionality of the converter.