Skip to content

Instantly share code, notes, and snippets.

@thewtex
Created May 7, 2014 03:55
Show Gist options
  • Save thewtex/6f50c44b071fcbca152b to your computer and use it in GitHub Desktop.
Save thewtex/6f50c44b071fcbca152b to your computer and use it in GitHub Desktop.
Plus IntersonSDKCxx
Index: src/DataCollection/CMakeLists.txt
===================================================================
--- src/DataCollection/CMakeLists.txt (revision 3305)
+++ src/DataCollection/CMakeLists.txt (working copy)
@@ -15,6 +15,7 @@
OPTION (PLUS_USE_VFW_VIDEO "Provide support for the Video-for-Windows video digitizer" OFF)
OPTION (PLUS_USE_EPIPHAN "Provide support for the Epiphan" OFF)
OPTION (PLUS_USE_INTERSON_VIDEO "Provide support Interson USB ultrasound probes" OFF)
+OPTION (PLUS_USE_INTERSONSDKCXX_VIDEO "Provide support Interson SDK 1.X with C++ Wrapper USB ultrasound probes" OFF)
OPTION(PLUS_USE_STEALTHLINK "Provide support for the Medtronick StealthLink Server" OFF)
OPTION (PLUS_TEST_BKPROFOCUS "Enable testing of acquisition from BK ProFocus ultrasound systems. Enable this only if a BK ProFocus device is connected to this computer." OFF)
@@ -748,6 +749,36 @@
ENDIF (PLUS_USE_INTERSON_VIDEO)
# --------------------------------------------------------------------------
+# Interson SDK C++ support
+
+IF (PLUS_USE_INTERSONSDKCXX_VIDEO)
+ FIND_PACKAGE( IntersonSDKCxx REQUIRED )
+ SET (DataCollection_SRCS ${DataCollection_SRCS}
+ IntersonSDKCxx/vtkIntersonSDKCxxVideoSource.cxx
+ )
+ if (WIN32)
+ SET (DataCollection_HDRS ${DataCollection_HDRS}
+ IntersonSDKCxx/vtkIntersonSDKCxxVideoSource.h
+ )
+ endif (WIN32)
+ SET (DataCollection_LIBS ${DataCollection_LIBS}
+ ${IntersonSDKCxx_LIBRARIES}
+ )
+ SET (DataCollection_INCLUDE_DIRS ${DataCollection_INCLUDE_DIRS}
+ ${IntersonSDKCxx_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/IntersonSDKCxx
+ )
+ SET ( External_Libraries_Install ${External_Libraries_Install}
+ ${IntersonSDK_DIR}/Libraries/Interson${CMAKE_SHARED_LIBRARY_SUFFIX}
+ ${IntersonSDK_DIR}/Libraries/IntersonTools${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
+ SET ( External_Libraries_Debug ${External_Libraries_Debug}
+ ${IntersonSDK_DIR}/Libraries/Interson${CMAKE_SHARED_LIBRARY_SUFFIX}
+ ${IntersonSDK_DIR}/Libraries/IntersonTools${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
+ENDIF (PLUS_USE_INTERSONSDKCXX_VIDEO)
+
+# --------------------------------------------------------------------------
# Build the library
SET (DataCollection_LIBS ${DataCollection_LIBS}
Index: src/DataCollection/Testing/CMakeLists.txt
===================================================================
--- src/DataCollection/Testing/CMakeLists.txt (revision 3305)
+++ src/DataCollection/Testing/CMakeLists.txt (working copy)
@@ -149,6 +149,17 @@
SET_TESTS_PROPERTIES( vtkSonixVideoSourceTest1 PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR;WARNING" )
ENDIF (PLUS_USE_ULTRASONIX_VIDEO AND PLUS_TEST_ULTRASONIX)
+#*************************** vtkIntersonSDKCxxVideoSourceTest.cxx ***************************
+IF (PLUS_USE_INTERSONSDKCXX_VIDEO)
+ ADD_EXECUTABLE(vtkIntersonSDKCxxVideoSourceTest vtkintersonSDKCxxVideoSourceTest.cxx)
+ TARGET_LINK_LIBRARIES(vtkIntersonSDKCxxVideoSourceTest vtkDataCollection vtkPlusCommon)
+ ADD_TEST(NAME vtkIntersonSDKCxxVideoSourceTest
+ COMMAND $<TARGET_FILE:vtkIntersonSDKCxxVideoSourceTest>
+ --rendering-off
+ --config-file=${ConfigFilesDir}/Testing/PlusDeviceSet_IntersonSDKCxxVideoSourceTest.xml
+ )
+ SET_TESTS_PROPERTIES( vtkIntersonSDKCxxVideoSourceTest PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR;WARNING" )
+ENDIF ()
IF (PLUS_USE_BKPROFOCUS_VIDEO)
Index: src/DataCollection/vtkUsImagingParameters.h
===================================================================
--- src/DataCollection/vtkUsImagingParameters.h (revision 3305)
+++ src/DataCollection/vtkUsImagingParameters.h (working copy)
@@ -161,4 +161,4 @@
};
-#endif
\ No newline at end of file
+#endif
Index: src/PlusConfigure.h.in
===================================================================
--- src/PlusConfigure.h.in (revision 3305)
+++ src/PlusConfigure.h.in (working copy)
@@ -84,6 +84,7 @@
#cmakedefine PLUS_USE_HEARTSIGNALBOX
#cmakedefine PLUS_USE_ICCAPTURING_VIDEO
#cmakedefine PLUS_USE_INTERSON_VIDEO
+#cmakedefine PLUS_USE_INTERSONSDKCXX_VIDEO
#cmakedefine PLUS_USE_MICRONTRACKER
#cmakedefine PLUS_USE_MMF_VIDEO
#cmakedefine PLUS_USE_PHIDGET_SPATIAL_TRACKER
@@ -135,4 +136,4 @@
#include "vtkPlusLogger.h"
#include "vtkPlusConfig.h"
-#endif // __PlusConfigure_h
\ No newline at end of file
+#endif // __PlusConfigure_h
Index: src/PlusLibConfig.cmake.in
===================================================================
--- src/PlusLibConfig.cmake.in (revision 3305)
+++ src/PlusLibConfig.cmake.in (working copy)
@@ -10,7 +10,12 @@
# Tell the user project where to find Plus use file
SET(PlusLib_USE_FILE "@CMAKE_CURRENT_BINARY_DIR@/UsePlusLib.cmake" )
+
+# Get the location for IntersonCxx
+SET(PLUS_USE_INTERSONSDKCXX_VIDEO "@PLUS_USE_INTERSONSDKCXX_VIDEO@")
+IF(PLUS_USE_INTERSONSDKCXX_VIDEO)
+ find_package(IntersonSDKCxx REQUIRED)
+ENDIF()
# Our library dependencies (contains definitions for IMPORTED targets)
include("@CMAKE_CURRENT_BINARY_DIR@/PlusLibLibraryDepends.cmake")
-
Index: src/UsePlusLib.cmake.in
===================================================================
--- src/UsePlusLib.cmake.in (revision 3305)
+++ src/UsePlusLib.cmake.in (working copy)
@@ -117,6 +117,7 @@
SET(PLUS_USE_HEARTSIGNALBOX @PLUS_USE_HEARTSIGNALBOX@)
SET(PLUS_USE_ICCAPTURING_VIDEO @PLUS_USE_ICCAPTURING_VIDEO@)
SET(PLUS_USE_INTERSON_VIDEO @PLUS_USE_INTERSON_VIDEO@)
+ SET(PLUS_USE_INTERSONSDKCXX_VIDEO @PLUS_USE_INTERSONSDKCXX_VIDEO@)
SET(PLUS_USE_MICRONTRACKER @PLUS_USE_MICRONTRACKER@)
SET(PLUS_USE_MMF_VIDEO @PLUS_USE_MMF_VIDEO@)
SET(PLUS_USE_PHIDGET_SPATIAL_TRACKER @PLUS_USE_PHIDGET_SPATIAL_TRACKER@)
/*=Plus=header=begin======================================================
Program: Plus
Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
See License.txt for details.
=========================================================Plus=header=end*/
#include "PlusConfigure.h"
#include "vtkIntersonSDKCxxVideoSource.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkPlusChannel.h"
#include "vtkPlusDataSource.h"
#include "vtkPlusBuffer.h"
#include "vtkUSImagingParameters.h"
#include "IntersonCxxImagingScan2DClass.h"
#include "IntersonCxxControlsHWControls.h"
#include "IntersonCxxIntersonClass.h"
#include "itkImage.h"
typedef IntersonCxx::Imaging::Scan2DClass Scan2DClassType;
typedef IntersonCxx::Controls::HWControls HWControlsType;
typedef IntersonCxx::IntersonClass IntersonClassType;
vtkCxxRevisionMacro(vtkIntersonSDKCxxVideoSource, "$Revision: 1.0$");
vtkStandardNewMacro(vtkIntersonSDKCxxVideoSource);
const unsigned int Dimension = 3;
typedef Scan2DClassType::BmodePixelType BmodePixelType;
typedef itk::Image< BmodePixelType, Dimension > BmodeImageType;
struct BmodeCallbackClientData
{
BmodeImageType * Image;
};
//----------------------------------------------------------------------------
void __stdcall pasteIntoBmodeImage( BmodePixelType * buffer, void * clientData )
{
BmodeCallbackClientData * callbackClientData = static_cast< BmodeCallbackClientData * >( clientData );
BmodeImageType * image = callbackClientData->Image;
const BmodeImageType::RegionType & largestRegion = image->GetLargestPossibleRegion();
const BmodeImageType::SizeType imageSize = largestRegion.GetSize();
const int maxVectors = Scan2DClassType::MAX_VECTORS;
const int maxSamples = Scan2DClassType::MAX_SAMPLES;
const int framePixels = maxVectors * maxSamples;
BmodePixelType * imageBuffer = image->GetPixelContainer()->GetBufferPointer();
std::memcpy( imageBuffer, buffer, framePixels * sizeof( BmodePixelType ) );
}
class vtkIntersonSDKCxxVideoSource::vtkInternal
{
public:
vtkIntersonSDKCxxVideoSource *External;
//----------------------------------------------------------------------------
vtkIntersonSDKCxxVideoSource::vtkInternal::vtkInternal(vtkIntersonSDKCxxVideoSource* external)
: External(external)
{
this->HWControls = new HWControlsType();
this->Scan2DClass = new Scan2DClassType();
this->IntersonClass = new IntersonClassType();
const int maxVectors = Scan2DClassType::MAX_VECTORS;
const int maxSamples = Scan2DClassType::MAX_SAMPLES;
this->BmodeImage = BmodeImageType::New();
typedef BmodeImageType::RegionType BmodeRegionType;
BmodeRegionType bmodeRegion;
BmodeRegionType::IndexType bmodeIndex;
bmodeIndex.Fill( 0 );
bmodeRegion.SetIndex( bmodeIndex );
BmodeRegionType::SizeType bmodeSize;
bmodeSize[0] = maxSamples;
bmodeSize[1] = maxVectors;
bmodeRegion.SetSize( bmodeSize );
this->BmodeImage->SetRegions( bmodeRegion );
this->BmodeImage->Allocate();
this->BmodeClientData.Image = this->BmodeImage.GetPointer();
this->Scan2DClass->SetNewBmodeImageCallback( &pasteIntoBmodeImage,
&(this->BmodeClientData) );
}
//----------------------------------------------------------------------------
vtkIntersonSDKCxxVideoSource::vtkInternal::~vtkInternal()
{
this->External = NULL;
delete HWControls;
delete Scan2DClass;
delete IntersonClass;
}
std::string GetSdkVersion()
{
return this->IntersonClass->Version();
}
HWControlsType * GetHWControls()
{
return this->HWControls;
}
Scan2DClassType * GetScan2DClass()
{
return this->Scan2DClass;
}
void * GetBmodeBuffer()
{
return this->BmodeImage->GetPixelContainer()->GetBufferPointer();
}
private:
HWControlsType * HWControls;
Scan2DClassType * Scan2DClass;
IntersonClassType * IntersonClass;
BmodeImageType::Pointer BmodeImage;
BmodeCallbackClientData BmodeClientData;
};
//----------------------------------------------------------------------------
vtkIntersonSDKCxxVideoSource::vtkIntersonSDKCxxVideoSource()
{
this->Internal = new vtkInternal(this);
this->RequireImageOrientationInConfiguration = true;
this->RequireFrameBufferSizeInDeviceSetConfiguration = true;
this->RequireAcquisitionRateInDeviceSetConfiguration = false;
this->RequireAveragedItemsForFilteringInDeviceSetConfiguration = false;
this->RequireLocalTimeOffsetSecInDeviceSetConfiguration = false;
this->RequireUsImageOrientationInDeviceSetConfiguration = true;
this->RequireRfElementInDeviceSetConfiguration = false;
this->ImagingParameters = new vtkUsImagingParameters(this);
this->PulseVoltage = 50;
}
//----------------------------------------------------------------------------
vtkIntersonSDKCxxVideoSource::~vtkIntersonSDKCxxVideoSource()
{
if( !this->Connected )
{
this->Disconnect();
}
delete this->Internal;
this->Internal=NULL;
}
//----------------------------------------------------------------------------
void vtkIntersonSDKCxxVideoSource::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::InternalConnect()
{
LOG_TRACE( "vtkIntersonSDKCxxVideoSource::InternalConnect" );
HWControlsType * hwControls = this->Internal->GetHWControls();
typedef HWControlsType::FoundProbesType FoundProbesType;
FoundProbesType foundProbes;
hwControls->FindAllProbes( foundProbes );
if( foundProbes.empty() )
{
LOG_ERROR( "Interson SDK Cxx could not find the probe." );
return PLUS_FAIL;
}
if( foundProbes.size() > 1 )
{
LOG_WARNING("Multiple Interson probes are attached, using the first one");
}
hwControls->FindMyProbe( 0 );
const unsigned int probeId = hwControls->GetProbeID();
LOG_DEBUG( "Found probe ID: " << probeId );
if( probeId == 0 )
{
LOG_ERROR( "Interson SDK Cxx could not find the probe." );
return PLUS_FAIL;
}
double depth = -1;
this->ImagingParameters->GetDepthMm( depth );
this->SetDepthMm( depth );
double frequency = -1;
if( this->SetProbeFrequency( frequency ) == PLUS_FAIL )
{
return PLUS_FAIL;
}
if( !hwControls->SendHighVoltage( this->PulseVoltage ) )
{
LOG_ERROR( "Could not set the high voltage." );
return PLUS_FAIL;
}
if( !hwControls->EnableHighVoltage() )
{
LOG_ERROR( "Could not enable high voltage." );
return PLUS_FAIL;
}
vtkPlusDataSource* source = NULL;
if( this->GetFirstActiveOutputVideoSource( source ) != PLUS_SUCCESS )
{
LOG_ERROR("Unable to retrieve the video source in the IntersonVideo device.");
return PLUS_FAIL;
}
// Clear buffer on connect because the new frames that we will acquire might have a different size
vtkPlusBuffer * plusBuffer = source->GetBuffer();
plusBuffer->Clear();
plusBuffer->SetPixelType( VTK_UNSIGNED_CHAR );
plusBuffer->SetFrameSize( Scan2DClassType::MAX_SAMPLES, Scan2DClassType::MAX_VECTORS );
double dynamicRangeDb = -1;
this->ImagingParameters->GetDynRangeDb( dynamicRangeDb );
if( this->SetDynRangeDb( dynamicRangeDb ) == PLUS_FAIL )
{
return PLUS_FAIL;
}
// TODO: use hardware button
hwControls->DisableHardButton();
Scan2DClassType * scan2D = this->Internal->GetScan2DClass();
scan2D->SetRFData( false );
LOG_DEBUG( "Interson SDK version " << this->Internal->GetSdkVersion() <<
", USB probe FPGA version " << hwControls->ReadFPGAVersion() );
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::InternalDisconnect()
{
LOG_DEBUG("Disconnect from Interson");
this->StopRecording();
Scan2DClassType * scan2D = this->Internal->GetScan2DClass();
scan2D->AbortScan();
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::InternalStartRecording()
{
Scan2DClassType * scan2D = this->Internal->GetScan2DClass();
scan2D->AbortScan();
HWControlsType * hwControls = this->Internal->GetHWControls();
if( !hwControls->StartMotor() )
{
LOG_ERROR( "Could not start motor." );
return PLUS_FAIL;
}
scan2D->StartReadScan();
Sleep( 100 ); // "time to start"
if( !hwControls->StartBmode() )
{
LOG_ERROR( "Could not start B-mode collection." );
return PLUS_FAIL;
};
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::InternalStopRecording()
{
HWControlsType * hwControls = this->Internal->GetHWControls();
if( !hwControls->StopAcquisition() )
{
LOG_ERROR( "Could not stop acquisition." );
return PLUS_FAIL;
}
Scan2DClassType * scan2D = this->Internal->GetScan2DClass();
scan2D->StopReadScan();
Sleep( 100 ); // "time to stop"
scan2D->DisposeScan();
if( !hwControls->StopMotor() )
{
LOG_ERROR( "Could not stop motor." );
return PLUS_FAIL;
}
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::InternalUpdate()
{
if( !this->Recording )
{
// drop the frame, we are not recording data now
return PLUS_SUCCESS;
}
HWControlsType * hwControls = this->Internal->GetHWControls();
if( hwControls->ReadHardButton() )
{
// TODO: add support for sending the button press info through OpenIGTLink
}
this->FrameNumber++;
vtkPlusDataSource* source = NULL;
if( this->GetFirstActiveOutputVideoSource( source ) != PLUS_SUCCESS )
{
LOG_ERROR("Unable to retrieve the video source in the ICCapturing device.");
return PLUS_FAIL;
}
int frameSizeInPx[2] = { Scan2DClassType::MAX_SAMPLES,
Scan2DClassType::MAX_VECTORS };
vtkPlusBuffer * plusBuffer = source->GetBuffer();
// If the buffer is empty, set the pixel type and frame size to the first received properties
if ( plusBuffer->GetNumberOfItems() == 0 )
{
LOG_DEBUG("Set up Plus image buffer");
plusBuffer->SetPixelType( VTK_UNSIGNED_CHAR );
plusBuffer->SetImageType( US_IMG_BRIGHTNESS );
plusBuffer->SetFrameSize( frameSizeInPx );
plusBuffer->SetImageOrientation( US_IMG_ORIENT_FU );
LOG_INFO("Frame size: " << frameSizeInPx[0] << "x" << frameSizeInPx[1]
<< ", pixel type: " << vtkImageScalarTypeNameMacro( plusBuffer->GetPixelType() )
<< ", device image orientation: "
<< PlusVideoFrame::GetStringFromUsImageOrientation( source->GetPortImageOrientation() )
<< ", buffer image orientation: "
<< PlusVideoFrame::GetStringFromUsImageOrientation( plusBuffer->GetImageOrientation() ));
}
if( plusBuffer->AddItem( this->Internal->GetBmodeBuffer(),
source->GetPortImageOrientation(),
frameSizeInPx,
VTK_UNSIGNED_CHAR,
1,
US_IMG_BRIGHTNESS,
0,
this->FrameNumber ) != PLUS_SUCCESS )
{
LOG_ERROR( "Error adding item to video source " << source->GetSourceId() );
return PLUS_FAIL;
}
this->Modified();
return PLUS_SUCCESS;
}
//-----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::ReadConfiguration(vtkXMLDataElement* config)
{
LOG_TRACE("vtkIntersonSDKCxxVideoSource::ReadConfiguration");
if ( config == NULL )
{
LOG_ERROR("Unable to configure Interson video source! (XML data element is NULL)");
return PLUS_FAIL;
}
Superclass::ReadConfiguration(config);
vtkXMLDataElement* deviceConfig = this->FindThisDeviceElement(config);
if (deviceConfig == NULL)
{
LOG_ERROR("Unable to find ImageAcquisition element in configuration XML structure!");
return PLUS_FAIL;
}
double dynRange = -1;
if ( deviceConfig->GetScalarAttribute("DynRangeDb", dynRange))
{
this->ImagingParameters->SetDynRangeDb(dynRange);
}
double frequency = -1;
if ( deviceConfig->GetScalarAttribute("FrequencyMhz", frequency))
{
this->ImagingParameters->SetFrequencyMhz(frequency);
}
double depthMm = -1;
if ( deviceConfig->GetScalarAttribute("DepthMm", depthMm))
{
this->ImagingParameters->SetDepthMm(depthMm);
}
return PLUS_SUCCESS;
}
//-----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::WriteConfiguration(vtkXMLDataElement* config)
{
// Write superclass configuration
Superclass::WriteConfiguration(config);
if ( config == NULL )
{
LOG_ERROR("Config is invalid");
return PLUS_FAIL;
}
vtkXMLDataElement* imageAcquisitionConfig = this->FindThisDeviceElement(config);
if (imageAcquisitionConfig == NULL)
{
LOG_ERROR("Cannot find ImageAcquisition element in XML tree!");
return PLUS_FAIL;
}
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::NotifyConfigured()
{
if( this->OutputChannels.size() > 1 )
{
LOG_WARNING("vtkIntersonSDKCxxVideoSource is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
}
if( this->OutputChannels.empty() )
{
LOG_ERROR("No output channels defined for vtkIntersonSDKCxxVideoSource. Cannot proceed." );
this->CorrectlyConfigured = false;
return PLUS_FAIL;
}
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
std::string vtkIntersonSDKCxxVideoSource::GetSdkVersion()
{
return this->Internal->GetSdkVersion();
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::SetProbeFrequency(double freq)
{
int frequency = static_cast< int >( freq * 1e6 );
HWControlsType * hwControls = this->Internal->GetHWControls();
HWControlsType::FrequenciesType supportedFrequencies;
hwControls->GetFrequency( supportedFrequencies );
// Set to the closest frequency value.
unsigned int frequencyIndex = 0;
if( frequency <= supportedFrequencies[0] )
{
frequencyIndex = 0;
}
const size_t numSupportedFrequencies = supportedFrequencies.size();
if( frequency >= supportedFrequencies[numSupportedFrequencies - 1] )
{
frequencyIndex = numSupportedFrequencies - 1;
}
for( size_t ii = 1; ii < numSupportedFrequencies - 1; ++ii )
{
const int lower = supportedFrequencies[ii - 1] +
( supportedFrequencies[ii] - supportedFrequencies[ii - 1] ) / 2;
if( frequency <= lower )
{
frequencyIndex = ii - 1;
break;
}
const int upper = supportedFrequencies[ii] +
( supportedFrequencies[ii + 1] - supportedFrequencies[ii] ) / 2;
if( frequency < upper )
{
frequencyIndex = ii;
break;
}
frequencyIndex = ii + 1;
}
frequency = supportedFrequencies[frequencyIndex];
LOG_TRACE( "Current frequency is " << frequency / 1.0e6 );
if( !hwControls->SetFrequency( frequency ) )
{
LOG_ERROR( "Could not set the frequency." );
return PLUS_FAIL;
}
this->ImagingParameters->SetFrequencyMhz( static_cast< double >( frequency / 1.0e6 ) );
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::SetDepthMm(double depthMm)
{
int depth = static_cast< int >( depthMm );
HWControlsType * hwControls = this->Internal->GetHWControls();
// Since we are not using their scan converter, this does not have much effect
// other than limiting to the maximum valid depth.
depth = hwControls->ValidDepth( depth );
this->ImagingParameters->SetDepthMm( static_cast< double >( depth ) );
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::SetFrequencyMhz(double freq)
{
return this->SetProbeFrequency( freq );
}
//----------------------------------------------------------------------------
PlusStatus vtkIntersonSDKCxxVideoSource::SetDynRangeDb(double dynRangeDb)
{
if( dynRangeDb > 0.0 )
{
const unsigned char usedGain = static_cast< unsigned char >( 255 * dynRangeDb );
HWControlsType * hwControls = this->Internal->GetHWControls();
if( !hwControls->SendDynamic( usedGain ) )
{
LOG_ERROR( "Could not set dynamic gain." );
return PLUS_FAIL;
}
}
return PLUS_SUCCESS;
}
/*=Plus=header=begin======================================================
Program: Plus
Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
See License.txt for details.
=========================================================Plus=header=end*/
#ifndef __vtkIntersonSDKCxxVideoSource_h
#define __vtkIntersonSDKCxxVideoSource_h
#include "vtkPlusDevice.h"
#include "vtkUSImagingParameters.h"
using namespace std;
/*!
\class vtkIntersonSDKCxxVideoSource
\brief Class for acquiring ultrasound images from Interson USB ultrasound systems
with C++ Wrapped SDK.
Requires the PLUS_USE_INTERSONSDKCXX option in CMake.
Requires Interson SDK 1.X and the C++ Wrappers (SDK provided by Interson,
Wrappers provided by Kitware).
\ingroup PlusLibDataCollection
*/
class VTK_EXPORT vtkIntersonSDKCxxVideoSource : public vtkPlusDevice
{
public:
static vtkIntersonSDKCxxVideoSource *New();
vtkTypeRevisionMacro(vtkIntersonSDKCxxVideoSource,vtkPlusDevice);
void PrintSelf(ostream& os, vtkIndent indent);
virtual bool IsTracker() const { return false; }
/*! Read configuration from xml data */
virtual PlusStatus ReadConfiguration(vtkXMLDataElement* config);
/*! Write configuration to xml data */
virtual PlusStatus WriteConfiguration(vtkXMLDataElement* config);
/*! Verify the device is correctly configured */
virtual PlusStatus NotifyConfigured();
virtual std::string GetSdkVersion();
vtkUsImagingParameters* ImagingParameters;
protected:
/*! Constructor */
vtkIntersonSDKCxxVideoSource();
/*! Destructor */
~vtkIntersonSDKCxxVideoSource();
/*! Device-specific connect */
virtual PlusStatus InternalConnect();
/*! Device-specific disconnect */
virtual PlusStatus InternalDisconnect();
/*! Device-specific recording start */
virtual PlusStatus InternalStartRecording();
/*! Device-specific recording stop */
virtual PlusStatus InternalStopRecording();
/*! The internal function which actually does the grab. */
virtual PlusStatus InternalUpdate();
PlusStatus GetFullIniFilePath(std::string &fullPath);
/* Set the desired probe frequency in MHz. The resulting probe speed will be approximately the value specified */
PlusStatus SetProbeFrequency(double aFreq);
PlusStatus GetProbeVelocity(double& aVel);
/* Set the probe depth in mm */
PlusStatus SetDepthMm(double depthMm);
/* Set the frquency in Mhz */
PlusStatus SetFrequencyMhz(double freq);
/* Set the gain in percent */
PlusStatus SetDynRangeDb(double dynRangeDb);
// For internal storage of additional variables (to minimize the number of included headers)
class vtkInternal;
vtkInternal* Internal;
unsigned char PulseVoltage;
private:
vtkIntersonSDKCxxVideoSource(const vtkIntersonSDKCxxVideoSource&); // Not implemented.
void operator=(const vtkIntersonSDKCxxVideoSource&); // Not implemented.
};
#endif
/*=Plus=header=begin======================================================
Program: Plus
Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
See License.txt for details.
=========================================================Plus=header=end*/
/*!
\file vtkIntersonSDKCxxVideoSourceTest.cxx
\brief Test basic connection to the Interson SDKCxx USB ultrasound probe
If the --rendering-off switch is defined then the connection is established, images are
transferred for a few seconds, then the connection is closed (useful for automatic testing).
If the --rendering-off switch is not defined then the live ultrasound image is displayed
in a window (useful for quick interactive testing of the image transfer).
\todo This is a test todo
\ingroup PlusLibDataCollection
*/
#include "PlusConfigure.h"
#include "vtkCallbackCommand.h"
#include "vtkChartXY.h"
#include "vtkCommand.h"
#include "vtkContextScene.h"
#include "vtkContextView.h"
#include "vtkFloatArray.h"
#include "vtkImageData.h"
#include "vtkImageViewer.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkPlot.h"
#include "vtkPlusBuffer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSmartPointer.h"
#include "vtkIntersonSDKCxxVideoSource.h"
#include "vtkTable.h"
#include "vtkTableAlgorithm.h"
#include "vtkXMLUtilities.h"
#include "vtksys/CommandLineArguments.hxx"
#include <stdlib.h>
//----------------------------------------------------------------------------
enum DisplayMode
{
SHOW_IMAGE,
SHOW_PLOT
};
//----------------------------------------------------------------------------
class vtkExtractImageRow : public vtkTableAlgorithm
{
public:
static vtkExtractImageRow* New();
vtkTypeMacro(vtkExtractImageRow,vtkTableAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
// Description:
// Specify the first vtkGraph input and the second vtkSelection input.
int FillInputPortInformation(int port, vtkInformation* info)
{
if (port == 0)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
return 1;
}
return 0;
}
protected:
vtkExtractImageRow()
{
this->SetNumberOfInputPorts(1);
}
virtual ~vtkExtractImageRow()
{
}
int RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector)
{
vtkImageData* inputImage = vtkImageData::GetData(inputVector[0]);
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkTable* outputTable = vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
if(!inputImage)
{
LOG_ERROR("No input image is available");
return 0;
}
// Create the tables if they haven't been created yet
if (outputTable->GetColumnByName("time")==NULL)
{
vtkSmartPointer<vtkFloatArray> arrXnew = vtkSmartPointer<vtkFloatArray>::New();
arrXnew->SetName("time");
outputTable->AddColumn(arrXnew);
}
if (outputTable->GetColumnByName("RF value")==NULL)
{
vtkSmartPointer<vtkFloatArray> arrRfValNew = vtkSmartPointer<vtkFloatArray>::New();
arrRfValNew->SetName("RF value");
outputTable->AddColumn(arrRfValNew);
}
if (inputImage->GetScalarType()!=VTK_SHORT)
{
LOG_ERROR("Plotting is only supported for signed short data");
return 0;
}
int rowCount=inputImage->GetDimensions()[1]; // number of transducer crystals
int numPoints=inputImage->GetDimensions()[0]; // number of data points (RF data values) recorded for one crystal
int selectedRow=rowCount/2; // plot the center column of the image
short* pixelBuffer=reinterpret_cast<short*>(inputImage->GetScalarPointer())+selectedRow*numPoints;
outputTable->SetNumberOfRows(numPoints);
int timeIndex=numPoints-1; // the RF data set starts with the latest time
for (int i = 0; i < numPoints; ++i)
{
outputTable->SetValue(i, 0, timeIndex);
short value=*pixelBuffer;
outputTable->SetValue(i, 1, value);
pixelBuffer++;
timeIndex--;
}
return 1;
}
private:
vtkExtractImageRow(const vtkExtractImageRow&); // Not implemented
void operator=(const vtkExtractImageRow&); // Not implemented
};
vtkStandardNewMacro(vtkExtractImageRow);
//---------------------------------------------------------------------------------
class vtkMyPlotCallback : public vtkCommand
{
public:
static vtkMyPlotCallback *New() { return new vtkMyPlotCallback; }
virtual void Execute(vtkObject *caller, unsigned long eventId, void* callData)
{
if (eventId==vtkCommand::KeyPressEvent)
{
if (m_Interactor->GetKeyCode()=='q')
{
m_Interactor->ExitCallback();
}
return;
}
m_ImageToTableAdaptor->Update();
m_Viewer->Render();
//update the timer so it will trigger again
m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
}
vtkRenderWindowInteractor *m_Interactor;
vtkContextView *m_Viewer;
vtkExtractImageRow *m_ImageToTableAdaptor;
private:
vtkMyPlotCallback()
{
m_Interactor=NULL;
m_Viewer=NULL;
m_ImageToTableAdaptor=NULL;
}
};
//----------------------------------------------------------------------------
void TestLinePlot(vtkIntersonSDKCxxVideoSource *intersonDevice)
{
// Set up a 2D scene, add an XY chart to it
vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
view->GetRenderWindow()->SetSize(400, 300);
vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
view->GetScene()->AddItem(chart);
vtkSmartPointer<vtkExtractImageRow> imageToTableAdaptor=vtkSmartPointer<vtkExtractImageRow>::New();
imageToTableAdaptor->SetInputConnection(intersonDevice->GetOutputPort());
imageToTableAdaptor->Update();
// Add multiple line plots, setting the colors etc
vtkPlot *line = chart->AddPlot(vtkChart::LINE);
line->SetInput(imageToTableAdaptor->GetOutput(), 0, 1);
line->SetColor(0, 255, 0, 255);
line->SetWidth(1.0);
vtkSmartPointer<vtkMyPlotCallback> call = vtkSmartPointer<vtkMyPlotCallback>::New();
call->m_Interactor=view->GetInteractor();
call->m_Viewer=view;
call->m_ImageToTableAdaptor=imageToTableAdaptor;
view->GetInteractor()->Initialize();
view->GetInteractor()->AddObserver(vtkCommand::TimerEvent, call);
view->GetInteractor()->CreateTimer(VTKI_TIMER_FIRST);
view->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, call);
view->GetInteractor()->Start();
}
//---------------------------------------------------------------------------------
class vtkMyCallback : public vtkCommand
{
public:
static vtkMyCallback *New() { return new vtkMyCallback; }
virtual void Execute(vtkObject *caller, unsigned long, void*)
{
m_Viewer->Render();
//update the timer so it will trigger again
m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
}
vtkRenderWindowInteractor *m_Interactor;
vtkImageViewer *m_Viewer;
private:
vtkMyCallback()
{
m_Interactor=NULL;
m_Viewer=NULL;
}
};
//-------------------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
bool printHelp(false);
bool renderingOff(false);
bool printParams(false);
std::string inputConfigFile;
double depthCm = -1;
double dynRangeDb = -1;
double frequencyMhz = -1;
std::string acqMode("B");
vtksys::CommandLineArguments args;
args.Initialize(argc, argv);
int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFile, "Config file containing the device configuration.");
args.AddArgument("--depth", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &depthCm, "Depth in cm.");
args.AddArgument("--frequencyMhz", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &frequencyMhz, "Frequency in MHz");
args.AddArgument("--dynRangeDb", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &dynRangeDb, "BMode Dynamic Range. 1 corresponds to the maximum dynamic range.");
args.AddArgument("--rendering-off", vtksys::CommandLineArguments::NO_ARGUMENT, &renderingOff, "Run test without rendering.");
args.AddArgument("--print-params", vtksys::CommandLineArguments::NO_ARGUMENT, &printParams, "Print all the supported imaging parameters (for diagnostic purposes only).");
args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level 1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
if ( !args.Parse() )
{
std::cerr << "Problem parsing arguments" << std::endl;
std::cout << "\n\nvtkIntersonSDKCxxVideoSourceTest help:" << args.GetHelp() << std::endl;
exit(EXIT_FAILURE);
}
vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
if ( printHelp )
{
std::cout << "\n\nvtkIntersonSDKCxxVideoSourceTest help:" << args.GetHelp() << std::endl;
exit(EXIT_SUCCESS);
}
vtkSmartPointer<vtkIntersonSDKCxxVideoSource> intersonDevice = vtkSmartPointer<vtkIntersonSDKCxxVideoSource>::New();
intersonDevice->SetDeviceId("VideoDevice");
/*
// Read config file
if (STRCASECMP(inputConfigFile.c_str(), "")!=0)
{
LOG_DEBUG("Reading config file...");
vtkSmartPointer<vtkXMLDataElement> configRead = vtkSmartPointer<vtkXMLDataElement>::Take(::vtkXMLUtilities::ReadElementFromFile(inputConfigFile.c_str()));
LOG_DEBUG("Reading config file finished.");
if ( configRead != NULL )
{
intersonDevice->ReadConfiguration(configRead);
}
}
intersonDevice->CreateDefaultOutputChannel();
DisplayMode displayMode=SHOW_IMAGE;
if (STRCASECMP(acqMode.c_str(), "B")==0)
{
LOG_DEBUG("Acquisition mode: B");
//intersonDevice->SetImagingMode(BMode);
//intersonDevice->SetAcquisitionDataType(udtBPost);
displayMode=SHOW_IMAGE;
}
else if (STRCASECMP(acqMode.c_str(), "RF")==0)
{
LOG_DEBUG("Acquisition mode: RF");
//intersonDevice->SetImagingMode(RfMode);
//intersonDevice->SetAcquisitionDataType(udtRF);
displayMode=SHOW_PLOT;
}
else
{
LOG_ERROR("Unsupported AcquisitionDataType requested: "<<acqMode);
exit(EXIT_FAILURE);
}
//DisplayMode displayMode=SHOW_PLOT;
if ( intersonDevice->Connect()!=PLUS_SUCCESS )
{
//LOG_ERROR( "Unable to connect to Sonix RP machine at: " << intersonDevice->GetSonixIP() );
exit(EXIT_FAILURE);
}
if (printParams)
{
LOG_INFO("List of supported imaging parameters:");
//intersonDevice->PrintListOfImagingParameters();
}
intersonDevice->StartRecording(); //start recording frame from the video
if (renderingOff)
{
// just run the recording for a few seconds then exit
LOG_DEBUG("Rendering disabled. Wait for just a few seconds to acquire data before exiting");
Sleep(5000); // no need to use accurate timer, it's just an approximate delay
intersonDevice->StopRecording();
intersonDevice->Disconnect();
}
else
{
if (displayMode==SHOW_PLOT)
{
TestLinePlot(intersonDevice);
}
else
{
// Show the live ultrasound image in a VTK renderer window
vtkSmartPointer<vtkImageViewer> viewer = vtkSmartPointer<vtkImageViewer>::New();
viewer->SetInputConnection(intersonDevice->GetOutputPort()); //set image to the render and window
viewer->SetColorWindow(255);
viewer->SetColorLevel(127.5);
viewer->SetZSlice(0);
//Create the interactor that handles the event loop
vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
iren->SetRenderWindow(viewer->GetRenderWindow());
viewer->SetupInteractor(iren);
viewer->Render(); //must be called after iren and viewer are linked or there will be problems
// Establish timer event and create timer to update the live image
vtkSmartPointer<vtkMyCallback> call = vtkSmartPointer<vtkMyCallback>::New();
call->m_Interactor=iren;
call->m_Viewer=viewer;
iren->AddObserver(vtkCommand::TimerEvent, call);
iren->CreateTimer(VTKI_TIMER_FIRST);
//iren must be initialized so that it can handle events
iren->Initialize();
iren->Start();
}
}
*/
intersonDevice->Disconnect();
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment