Import Option "Freehand Ultrasound Folder"

Dear ImFusion team,

I have a question regarding the Import option “Freehand Ultrasound Folder” and it’s usages:

Can this option be used for importing an .mha file with the corresponding .xml file (containing the configurations) to achieve a fully configured compounding of an Ultrasound sweep?

Or is this option used just for the import of several freehand ultrasound files at once?

Thanks in advance for your help.
Best regards,
Uladzislava

Hello Uladzislava,

Import “Freehand Ultrasound Folder” is for loading from an AVI or a series of PNG files together with metadata (timestamps, tracking and geometry) from CSV or TXT files.

To load an ultrasound sweep from MHA, you can use import “Freehand Ultrasound File”. This algorithm assumes the format of the PLUS Toolkit to load tracking data.

Best regards,
Steffen

Thanks Steffen,

In a follow up to the previous question, we have MHA files recorded using the PLUS toolkit, which also comes with a config file. When we load the MHA file only, using “Freehand ultrasound file” import option, we see that the spacing and the calibration matrix are not correct. This information is mentioned in the config file which looks similar to this:

<PlusConfiguration version="2.3" PlusRevision="Plus-2.0.0.2801">
  <DataCollection StartupDelaySec="1">
    <DeviceSet Name="SonixTouch Ascension3DG(GPS) C52 8cm+ Reference + Stylus + Phantom 2.0_stylus+phantom_complete+tempora +spatial" Description="Ascension3DG sensors should be plugged in to the Ascension3DG DriveBay mounted on SonixTouch in the following order from to leftmost slot (Transducer 1) to the right: 1 Probe, 2 Reference, 3 Stylus."/>
    <Device
      Id="TrackerDevice"
      Type="Ascension3DG"
      AcquisitionRate="50"
      LocalTimeOffsetSec="0"
      FilterAcWideNotch="1"
      FilterAcNarrowNotch="0"
      FilterDcAdaptive="0"
      FilterLargeChange="0"
      FilterAlpha="0">
      <DataSources>
        <DataSource Type="Tool" Id="Probe" BufferSize="500" PortName="0" AveragedItemsForFiltering="20"/>
        <DataSource Type="Tool" Id="Reference" BufferSize="500" PortName="1" AveragedItemsForFiltering="20"/>
        <DataSource Type="Tool" Id="Stylus" BufferSize="500" PortName="2" AveragedItemsForFiltering="20"/>
      </DataSources>
      <OutputChannels>
        <OutputChannel Id="TrackerStream">
          <DataSource Id="Probe"/>
          <DataSource Id="Reference"/>
          <DataSource Id="Stylus"/>
        </OutputChannel>
      </OutputChannels>
    </Device>
    <Device
      Id="VideoDevice"
      Type="SonixVideo"
      AcquisitionRate="30"
      LocalTimeOffsetSec="0.0012744"
      IP="127.0.0.1"
      Depth="-1"
      Sector="-1"
      Gain="-1"
      DynRange="-1"
      Zoom="-1"
      Frequency="-1"
      Timeout="-1"
      CompressionStatus="0"
      ImagingMode="BMode"
      RfAcquisitionMode="BOnly"
      AcquisitionDataType="BPost"
      ConnectionSetupDelayMs="3000">
      <DataSources>
        <DataSource
          Type="Video"
          Id="Video"
          PortName="B"
          PortUsImageOrientation="UF"
          BufferSize="500"
          AveragedItemsForFiltering="20"/>
      </DataSources>
      <OutputChannels>
        <OutputChannel Id="VideoStream" VideoDataSourceId="Video"/>
      </OutputChannels>
    </Device>
    <Device Id="TrackedVideoDevice" Type="VirtualMixer" LocalTimeOffsetSec="0.0012744">
      <InputChannels>
        <InputChannel Id="TrackerStream"/>
        <InputChannel Id="VideoStream"/>
      </InputChannels>
      <OutputChannels>
        <OutputChannel Id="TrackedVideoStream"/>
      </OutputChannels>
    </Device>
  </DataCollection>
  <CoordinateDefinitions>
    <Transform From="Image" To="Probe"
      Matrix="
        -0.00352034	0.141028	0.0032465	22.0759
        -0.14499	0.00166178	0.010435	59.3516
        0.0106726	-0.00332688	0.142833	-0.404978
        0	0	0	1"
       Error="1.07584" Date="061113_184308"/>
    <Transform From="Image" To="TransducerOriginPixel"
      Matrix="
        1	0	0	-410
        0	1	0	5
        0	0	1	0
        0	0	0	1"
       Date="2011.12.06 17:57:00"/>
    <Transform From="Phantom" To="Reference"
      Matrix="
        -0.0198568	0.0172267	-0.999654	15.1917
        -0.999777	-0.00751643	0.0197297	-25.635
        -0.00717396	0.999823	0.0173721	-39.4197
        0	0	0	1"
       Error="1.8609" Date="061113_183149"/>
    <Transform From="StylusTip" To="Stylus"
      Matrix="
        0.997801	-0.0639177	0.0175155	4.99625
        0.0639275	0.997955	0	0.320102
        -0.0174797	0.00111972	0.999847	-0.0875251
        0	0	0	1"
       Error="0.161172" Date="061113_183104"/>
    <Transform From="TransducerOriginPixel" To="TransducerOrigin"
      Matrix="
        0.146691	0	0	0
        0	0.13976	0	0
        0	0	0.143251	0
        0	0	0	1"
       Date="061113_184308"/>
  </CoordinateDefinitions>
  <Rendering WorldCoordinateFrame="Reference" DisplayedImageOrientation="MF">
    <DisplayableObject Type="Model" ObjectCoordinateFrame="TransducerOrigin" Id="ProbeModel" File="L14-5_38_ProbeModel.stl"
      ModelToObjectTransform="
        -1	0	0	29.7
        0	-1	0	1.5
        0	0	1	-14
        0	0	0	1"
      />
    <DisplayableObject Type="Model" ObjectCoordinateFrame="Reference" Id="Volume"/>
    <DisplayableObject Type="Model" ObjectCoordinateFrame="StylusTip" Id="StylusModel" File="Stylus_Example.stl"
      ModelToObjectTransform="
        1	0	0	-210
        0	1	0	0
        0	0	1	0
        0	0	0	1"
      />
    <DisplayableObject
      Id="PhantomModel"
      Type="Model"
      ObjectCoordinateFrame="Phantom"
      Opacity="0.6"
      File="FCal_2.0.stl"
      ModelToObjectTransform="
        1	0	0	-35
        0	1	0	-10
        0	0	1	-5
        0	0	0	1"/>
    <DisplayableObject Type="Image" ObjectCoordinateFrame="Image" Id="LiveImage"/>
  </Rendering>
  <Segmentation
    ApproximateSpacingMmPerPixel="0.149644"
    MorphologicalOpeningCircleRadiusMm="0.27"
    MorphologicalOpeningBarSizeMm="1"
    ClipRectangleOrigin="208 155"
    ClipRectangleSize="386 267"
    MaxLinePairDistanceErrorPercent="10"
    AngleToleranceDegrees="10"
    MaxAngleDifferenceDegrees="10"
    MinThetaDegrees="-70"
    MaxThetaDegrees="70"
    ThresholdImagePercent="10"
    CollinearPointsMaxDistanceFromLineMm="0.6"
    UseOriginalImageIntensityForDotIntensityScore="0"
    MaxLineShiftMm="10"/>
  <PhantomDefinition>
    <Description Name="fCAL" Type="Double-N" Version="2.0" WiringVersion="2.0" Institution="Queen&apos;s University PerkLab"/>
    <Geometry>
      <Pattern Type="NWire">
        <Wire Name="7:G1_g1" EndPointFront="30.0 0.0 20.0" EndPointBack="30.0 40.0 20.0"/>
        <Wire Name="8:L1_h1" EndPointFront="55.0 0.0 20.0" EndPointBack="35.0 40.0 20.0"/>
        <Wire Name="9:M1_m1" EndPointFront="60.0 0.0 20.0" EndPointBack="60.0 40.0 20.0"/>
      </Pattern>
      <Pattern Type="NWire">
        <Wire Name="4:G3_g3" EndPointFront="30.0 0.0 10.0" EndPointBack="30.0 40.0 10.0"/>
        <Wire Name="5:H3_l3" EndPointFront="35.0 0.0 10.0" EndPointBack="55.0 40.0 10.0"/>
        <Wire Name="6:M3_m3" EndPointFront="60.0 0.0 10.0" EndPointBack="60.0 40.0 10.0"/>
      </Pattern>
      <Pattern Type="NWire">
        <Wire Name="1:H5_h5" EndPointFront="35.0 0.0 0.0" EndPointBack="35.0 40.0 0.0"/>
        <Wire Name="2:L5_i5" EndPointFront="55.0 0.0 0.0" EndPointBack="40.0 40.0 0.0"/>
        <Wire Name="3:M5_m5" EndPointFront="60.0 0.0 0.0" EndPointBack="60.0 40.0 0.0"/>
      </Pattern>
      <Landmarks>
        <Landmark Name="#1" Position="104.3 5.0 20.0"/>
        <Landmark Name="#2" Position="104.3 45.0 20.0"/>
        <Landmark Name="#3" Position="104.3 45.0 0.0"/>
        <Landmark Name="#4" Position="104.3 -5.0 0.0"/>
        <Landmark Name="#5" Position="-34.3 45.0 15.0"/>
        <Landmark Name="#6" Position="-34.3 -5.0 20.0"/>
        <Landmark Name="#7" Position="-34.3 -5.0 0.0"/>
        <Landmark Name="#8" Position="-34.3 45.0 0.0"/>
      </Landmarks>
    </Geometry>
  </PhantomDefinition>
  <VolumeReconstruction
    OutputSpacing="0.5 0.5 0.5"
    ClipRectangleOrigin="0 0"
    ClipRectangleSize="820 616"
    Interpolation="NEAREST_NEIGHBOR"
	Calculation="MAXIMUM"
    Optimization="FULL"
    Compounding="On"
    FillHoles="On">
		<HoleFilling>
		<HoleFillingElement 
		Type="STICK" 
		StickLengthLimit="9" 
		NumberOfSticksToUse="1" />
		</HoleFilling>
	</VolumeReconstruction>

	
  <fCal
    PhantomModelId="PhantomModel"
    ReconstructedVolumeId="Volume"
    TransducerModelId="ProbeModel"
    StylusModelId="StylusModel"
    ImageDisplayableObjectId="LiveImage"
    NumberOfCalibrationImagesToAcquire="200"
    NumberOfValidationImagesToAcquire="100"
    NumberOfStylusCalibrationPointsToAcquire="200"
    RecordingIntervalMs="100"
    MaxTimeSpentWithProcessingMs="70"
    ImageCoordinateFrame="Image"
    ProbeCoordinateFrame="Probe"
    ReferenceCoordinateFrame="Reference"
    TransducerOriginCoordinateFrame="TransducerOrigin"
    TransducerOriginPixelCoordinateFrame="TransducerOriginPixel"
    TemporalCalibrationDurationSec="10"
    DefaultSelectedChannelId="TrackedVideoStream"/>
  <vtkPivotCalibrationAlgo ObjectMarkerCoordinateFrame="Stylus" ReferenceCoordinateFrame="Reference" ObjectPivotPointCoordinateFrame="StylusTip"/>
  <vtkPhantomRegistrationAlgo PhantomCoordinateFrame="Phantom" ReferenceCoordinateFrame="Reference" StylusTipCoordinateFrame="StylusTip"/>
  <vtkProbeCalibrationAlgo ImageCoordinateFrame="Image" ProbeCoordinateFrame="Probe" PhantomCoordinateFrame="Phantom" ReferenceCoordinateFrame="Reference"/>
</PlusConfiguration>

Can you please tell us how we can load the sweep with the information from the config file in ImFusionSuite?

Best regards,
Farid

Hi Farid,

We currently don’t have any algorithm for loading and parsing the PLUS config files.
I think the easiest option would be to write a simple python script to parse the PLUS config and copy the calibration and the spacing into the sweep.
Using the ImFusion python bindings you can set the calibration and spacing as follows:

sweep.tracking().calibration = calibration
for frame in sweep:
    frame.spacing = [spacing_x, spacing_y, 1.0]

Best,
Matteo Ronchetti