8 #include "PlusConfigure.h" 16 #include <vtkIGSIOAccurateTimer.h> 17 #include <igsioMath.h> 21 #include <vtkImageData.h> 22 #include <vtkImageImport.h> 23 #include <vtkMatrix4x4.h> 24 #include <vtkObjectFactory.h> 25 #include <vtkSmartPointer.h> 26 #include <vtkTransform.h> 27 #include <vtkXMLUtilities.h> 40 #include "MadgwickAhrsAlgo.h" 41 #include "MahonyAhrsAlgo.h" 44 #include <opencv2/imgproc.hpp> 45 #include <opencv2/core/mat.hpp> 46 #include <opencv2/opencv.hpp> 57 #define BLOCKINGCALL nullptr 58 #define DEFAULT_FRAME_WIDTH 640 59 #define DEFAULT_FRAME_HEIGHT 480 60 #define DEFAULT_PATH_TO_SEC_KEY "/tmp/" 66 class vtkPlusClarius::vtkInternal
71 virtual ~vtkInternal() =
default;
79 static void ErrorFn(
const char* err);
80 static void FreezeFn(
int val);
81 static void ProgressFn(
int progress);
82 static void ButtonFn(CusButton button,
int clicks);
87 static void NewProcessedImageFn(
const void* newImage,
const CusProcessedImageInfo* nfo,
int npos,
const CusPosInfo* pos);
88 static void NewRawImageFn(
const void* newImage,
const CusRawImageInfo* nfo,
int npos,
const CusPosInfo* pos);
94 static void ConnectReturnFn(
int udpPort,
int swRevMatch);
99 static void RawDataRequestFn(
int rawDataSize,
const char* extension);
104 static void RawDataWriteFn(
int rawDataSize);
109 void AllocateRawData(
int size);
119 PlusStatus WritePosesToCsv(
const CusProcessedImageInfo* nfo,
int npos,
const CusPosInfo* pos,
int frameNum,
double systemTime,
double convertedTime);
124 PlusStatus ProcessPositionInfo(
int nfo,
const CusPosInfo* posInfo);
129 static double NanoSecondsToSeconds(
long long int ns);
130 static long long int SecondsToNanoSeconds(
double s);
142 vtkNew<vtkMatrix4x4> LastAccelerometerToTrackerTransform;
143 vtkNew<vtkMatrix4x4> LastGyroscopeToTrackerTransform;
144 vtkNew<vtkMatrix4x4> LastMagnetometerToTrackerTransform;
145 vtkNew<vtkMatrix4x4> LastTiltSensorToTrackerTransform;
146 vtkNew<vtkMatrix4x4> LastFilteredTiltSensorToTrackerTransform;
147 vtkNew<vtkMatrix4x4> LastOrientationSensorToTrackerTransform;
149 AhrsAlgo* FilteredTiltSensorAhrsAlgo;
157 bool AhrsUseMagnetometer;
160 double AhrsLastUpdateTime;
161 double FilteredTiltSensorAhrsLastUpdateTime;
163 std::ofstream RawImuDataStream;
164 bool IsReceivingRawData;
167 void* RawDataPointer;
169 std::string PathToSecKey;
171 double SystemStartTimestampSeconds;
172 double ClariusStartTimestampSeconds;
173 double ClariusLastTimestamp;
184 , AccelerometerTool(NULL)
185 , GyroscopeTool(NULL)
186 , MagnetometerTool(NULL)
187 , TiltSensorTool(NULL)
188 , FilteredTiltSensorTool(NULL)
189 , OrientationSensorTool(NULL)
190 , AhrsAlgo(new MadgwickAhrsAlgo())
191 , AhrsUseMagnetometer(true)
192 , AhrsLastUpdateTime(-1)
193 , FilteredTiltSensorAhrsLastUpdateTime(-1)
194 , FilteredTiltSensorAhrsAlgo(new MadgwickAhrsAlgo())
196 , RawDataPointer(NULL)
197 , IsReceivingRawData(false)
199 , SystemStartTimestampSeconds(0.0)
200 , ClariusStartTimestampSeconds(0.0)
201 , ClariusLastTimestamp(0.0)
209 double vtkPlusClarius::vtkInternal::NanoSecondsToSeconds(
long long int ns)
211 return ns / 1000000000.0;
216 long long int vtkPlusClarius::vtkInternal::SecondsToNanoSeconds(
double s)
218 return static_cast<long long int>(1000000000 * s);
222 void vtkPlusClarius::vtkInternal::ConnectReturnFn(
int udpPort,
int swRevMatch)
227 LOG_ERROR(
"Clarius instance is NULL");
230 vtkInternal*
self = device->
Internal;
232 if (swRevMatch != CUS_SUCCESS)
234 LOG_ERROR(
"...Clarius version mismatch");
238 self->UdpPort = udpPort;
240 if (self->UdpPort != -1)
242 LOG_DEBUG(
"... Clarius device connected, streaming port: " << self->UdpPort);
246 LOG_ERROR(
"... Clarius device connected but could not get valid udp port");
255 void vtkPlusClarius::vtkInternal::ErrorFn(
const char* err)
257 LOG_ERROR(
"error: " << err);
263 void vtkPlusClarius::vtkInternal::FreezeFn(
int val)
267 LOG_INFO(
"Clarius Frozen");
272 LOG_INFO(
"Clarius Imaging");
279 void vtkPlusClarius::vtkInternal::ProgressFn(
int progress)
281 LOG_DEBUG(
"Download: " << progress <<
"%");
288 void vtkPlusClarius::vtkInternal::ButtonFn(CusButton btn,
int clicks)
290 LOG_DEBUG(
"button: " << btn <<
"clicks: " << clicks <<
"%");
300 void vtkPlusClarius::vtkInternal::NewProcessedImageFn(
const void* newImage,
const CusProcessedImageInfo* nfo,
int npos,
const CusPosInfo* pos)
302 LOG_TRACE(
"vtkPlusClarius::NewProcessedImageFn");
306 LOG_ERROR(
"Clarius instance is NULL");
309 vtkInternal*
self = device->
Internal;
312 LOG_TRACE(
"New image (" << newImage <<
"): " << nfo->width <<
" x " << nfo->height <<
" @ " << nfo->bitsPerPixel
313 <<
"bits. @ " << nfo->micronsPerPixel <<
" microns per pixel. imu points: " << npos);
318 LOG_ERROR(
"Trouble connecting to Clarius Device. IpAddress = " << device->
IpAddress 319 <<
" port = " << device->
TcpPort);
323 if (newImage == NULL)
325 LOG_ERROR(
"No frame received by the device");
331 std::vector<vtkPlusDataSource*> bModeSources;
333 if (!bModeSources.empty())
335 bModeSource = bModeSources[0];
339 LOG_WARNING(
"Processed image was received, however no output B-Mode video source was found.");
345 vtkSmartPointer<vtkImageData> rgbImage = vtkSmartPointer<vtkImageData>::New();
346 rgbImage->SetExtent(0, nfo->width - 1, 0, nfo->height - 1, 0, 0);
347 rgbImage->SetOrigin(0.0, 0.0, 0.0);
348 rgbImage->SetSpacing(1.0, 1.0, 1.0);
349 rgbImage->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
350 PixelCodec::BGRA32ToRGB24(nfo->width, nfo->height, (
unsigned char*)newImage, (
unsigned char*)rgbImage->GetScalarPointer());
352 vtkSmartPointer<vtkImageData> outputImage = rgbImage;
353 US_IMAGE_TYPE outputUSImageType = US_IMG_RGB_COLOR;
360 vtkSmartPointer<vtkImageData> grayscaleImage = vtkSmartPointer<vtkImageData>::New();
361 grayscaleImage->SetExtent(0, nfo->width - 1, 0, nfo->height - 1, 0, 1);
362 grayscaleImage->SetOrigin(0.0, 0.0, 0.0);
363 grayscaleImage->SetSpacing(1.0, 1.0, 1.0);
364 grayscaleImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
365 outputImage = grayscaleImage;
371 (
unsigned char*)rgbImage->GetScalarPointer(),
372 (
unsigned char*)grayscaleImage->GetScalarPointer());
373 outputUSImageType = US_IMG_BRIGHTNESS;
377 self->ClariusLastTimestamp = vtkInternal::NanoSecondsToSeconds(nfo->tm);
379 double systemTime = vtkIGSIOAccurateTimer::GetSystemTime();
382 self->SystemStartTimestampSeconds = systemTime;
383 self->ClariusStartTimestampSeconds =
self->ClariusLastTimestamp;
388 double convertedTimestamp =
self->SystemStartTimestampSeconds + (
self->ClariusLastTimestamp -
self->ClariusStartTimestampSeconds);
391 self->WritePosesToCsv(nfo, npos, pos, device->
FrameNumber, systemTime, convertedTimestamp);
397 cv::Mat cvimg = cv::Mat(nfo->width, nfo->height, CV_8UC4);
398 cvimg.data = cvimg.data = (
unsigned char*)newImage;
399 if (cv::imwrite(
"Clarius_Image" +
std::to_string(self->ClariusLastTimestamp) +
".bmp", cvimg) ==
false)
401 LOG_ERROR(
"ERROR writing clarius image" +
std::to_string(self->ClariusLastTimestamp) +
" to disk");
405 igsioFieldMapType customField;
406 customField[
"micronsPerPixel"] = std::make_pair(igsioFrameFieldFlags::FRAMEFIELD_FORCE_SERVER_SEND,
std::to_string(nfo->micronsPerPixel));
408 outputImage->GetScalarPointer(),
422 self->ProcessPositionInfo(npos, pos);
434 void vtkPlusClarius::vtkInternal::NewRawImageFn(
const void* newImage,
const CusRawImageInfo* nfo,
int npos,
const CusPosInfo* pos)
436 LOG_TRACE(
"vtkPlusClarius::NewRawImageFn");
440 LOG_ERROR(
"Clarius instance is NULL");
443 vtkInternal*
self = device->
Internal;
447 LOG_TRACE(
"New raw image is envelope, not Rf.");
451 LOG_TRACE(
"New raw image (" << newImage <<
"): " << nfo->lines <<
" lines using " << nfo->samples <<
" samples, @ " << nfo->bitsPerSample <<
" bits." 452 << nfo->axialSize <<
" axial microns per sample, " << nfo->lateralSize <<
" lateral microns per line.");
457 LOG_ERROR(
"Trouble connecting to Clarius Device. IpAddress = " << device->
IpAddress 458 <<
" port = " << device->
TcpPort);
462 if (newImage == NULL)
464 LOG_ERROR(
"No frame received by the device");
469 std::vector<vtkPlusDataSource*> rfModeSources;
471 if (!rfModeSources.empty())
473 rfModeSource = rfModeSources[0];
477 LOG_WARNING(
"Raw image was received, however no output RF video source was found.");
482 int pixelType = VTK_UNSIGNED_CHAR;
483 int frameBufferBytesPerSample = (nfo->bitsPerSample / 8);
485 switch (frameBufferBytesPerSample)
487 case VTK_SIZEOF_LONG_LONG:
488 pixelType = VTK_LONG_LONG;
493 case VTK_SIZEOF_SHORT:
494 pixelType = VTK_SHORT;
496 case VTK_SIZEOF_CHAR:
498 pixelType = VTK_CHAR;
507 int frameSizeInBytes = nfo->lines * nfo->samples * frameBufferBytesPerSample;
510 self->ClariusLastTimestamp = vtkInternal::NanoSecondsToSeconds(nfo->tm);
512 double systemTime = vtkIGSIOAccurateTimer::GetSystemTime();
513 if (self->FrameNumber == 0)
515 self->SystemStartTimestampSeconds = systemTime;
516 self->ClariusStartTimestampSeconds =
self->ClariusLastTimestamp;
519 double convertedTimestamp =
self->SystemStartTimestampSeconds + (
self->ClariusLastTimestamp -
self->ClariusStartTimestampSeconds);
533 self->ProcessPositionInfo(npos, pos);
539 PlusStatus vtkPlusClarius::vtkInternal::ProcessPositionInfo(
int npos,
const CusPosInfo* pos)
544 LOG_ERROR(
"Invalid device");
547 vtkInternal*
self = device->
Internal;
550 for (
int i = 0;
i < npos;
i++)
552 const CusPosInfo currentPos = pos[
i];
557 double poseTimeStampSeconds = vtkInternal::NanoSecondsToSeconds(currentPos.tm);
558 poseTimeStampSeconds =
self->SystemStartTimestampSeconds + (poseTimeStampSeconds -
self->ClariusStartTimestampSeconds);
560 double acceleration[3] = { currentPos.ax , currentPos.ay , currentPos.az };
561 if (self->AccelerometerTool != NULL)
563 self->LastAccelerometerToTrackerTransform->Identity();
564 self->LastAccelerometerToTrackerTransform->SetElement(0, 3,
acceleration[0]);
565 self->LastAccelerometerToTrackerTransform->SetElement(1, 3,
acceleration[1]);
566 self->LastAccelerometerToTrackerTransform->SetElement(2, 3,
acceleration[2]);
570 double angularRate[3] = { currentPos.gx , currentPos.gy , currentPos.gz };
571 if (self->GyroscopeTool != NULL)
573 self->LastGyroscopeToTrackerTransform->Identity();
574 self->LastGyroscopeToTrackerTransform->SetElement(0, 3,
angularRate[0]);
575 self->LastGyroscopeToTrackerTransform->SetElement(1, 3,
angularRate[1]);
576 self->LastGyroscopeToTrackerTransform->SetElement(2, 3,
angularRate[2]);
580 double magneticField[3] = { currentPos.mx , currentPos.my , currentPos.mz };
581 if (self->MagnetometerTool != NULL)
584 self->LastMagnetometerToTrackerTransform->Identity();
585 self->LastMagnetometerToTrackerTransform->SetElement(0, 3,
magneticField[0]);
586 self->LastMagnetometerToTrackerTransform->SetElement(1, 3,
magneticField[1]);
587 self->LastMagnetometerToTrackerTransform->SetElement(2, 3,
magneticField[2]);
591 double orientationQuat[4] = { currentPos.qw, currentPos.qx, currentPos.qy, currentPos.qz };
592 if (self->OrientationSensorTool != NULL)
594 double orientationMatrix[3][3] = {
599 vtkMath::QuaternionToMatrix3x3(orientationQuat, orientationMatrix);
600 for (
int c = 0; c < 3; c++)
602 for (
int r = 0; r < 3; r++)
604 self->LastOrientationSensorToTrackerTransform->SetElement(r, c, orientationMatrix[r][c]);
607 device->
ToolTimeStampedUpdateWithoutFiltering(self->OrientationSensorTool->GetId(),
self->LastOrientationSensorToTrackerTransform, TOOL_OK, poseTimeStampSeconds, poseTimeStampSeconds);
610 if (self->TiltSensorTool != NULL)
613 vtkMath::Normalize(downVector_Sensor);
615 igsioMath::ConstrainRotationToTwoAxes(downVector_Sensor, device->
TiltSensorWestAxisIndex, self->LastTiltSensorToTrackerTransform);
620 if (self->FilteredTiltSensorTool != NULL)
622 self->FilteredTiltSensorAhrsAlgo->UpdateIMUWithTimestamp(
626 double rotQuat[4] = { 0.0, 0.0, 0.0, 0.0 };
627 self->AhrsAlgo->GetOrientation(rotQuat[0], rotQuat[1], rotQuat[2], rotQuat[3]);
629 double rotMatrix[3][3] = {
634 vtkMath::QuaternionToMatrix3x3(rotQuat, rotMatrix);
636 double filteredDownVector_Sensor[4] = { rotMatrix[2][0], rotMatrix[2][1], rotMatrix[2][2], 0.0 };
637 vtkMath::Normalize(filteredDownVector_Sensor);
639 igsioMath::ConstrainRotationToTwoAxes(filteredDownVector_Sensor, device->
FilteredTiltSensorWestAxisIndex, self->LastFilteredTiltSensorToTrackerTransform);
641 device->
ToolTimeStampedUpdateWithoutFiltering(self->FilteredTiltSensorTool->GetId(),
self->LastFilteredTiltSensorToTrackerTransform, TOOL_OK, poseTimeStampSeconds, poseTimeStampSeconds);
644 for (
int c = 0; c < 3; c++)
646 for (
int r = 0; r < 3; r++)
648 rotMatrix[r][c] =
self->LastFilteredTiltSensorToTrackerTransform->GetElement(r, c);
651 double filteredTiltSensorRotQuat[4] = { 0 };
652 vtkMath::Matrix3x3ToQuaternion(rotMatrix, filteredTiltSensorRotQuat);
653 self->FilteredTiltSensorAhrsAlgo->SetOrientation(filteredTiltSensorRotQuat[0], filteredTiltSensorRotQuat[1], filteredTiltSensorRotQuat[2], filteredTiltSensorRotQuat[3]);
661 PlusStatus vtkPlusClarius::vtkInternal::WritePosesToCsv(
const CusProcessedImageInfo* nfo,
int npos,
const CusPosInfo* pos,
int frameNum,
double systemTime,
double convertedTime)
663 LOG_TRACE(
"vtkPlusClarius::WritePosesToCsv");
666 LOG_TRACE(
"timestamp in nanoseconds CusPosInfo" << pos[0].tm);
667 std::string posInfo =
"";
668 for (
auto i = 0;
i < npos;
i++)
688 this->RawImuDataStream.open(this->External->ImuOutputFileName, std::ofstream::app);
689 if (this->RawImuDataStream.is_open() ==
false)
691 LOG_ERROR(
"Error opening file for raw imu data");
695 this->RawImuDataStream << posInfo;
696 this->RawImuDataStream.close();
705 void vtkPlusClarius::vtkInternal::RawDataRequestFn(
int rawDataSize,
const char* extension)
710 LOG_ERROR(
"Invalid device");
713 vtkInternal*
self = device->
Internal;
717 self->IsReceivingRawData =
false;
718 LOG_ERROR(
"Error requesting raw data!");
722 if (rawDataSize == 0)
724 self->IsReceivingRawData =
false;
725 LOG_TRACE(
"No data to read!");
729 self->ReceiveRawData(rawDataSize);
733 PlusStatus vtkPlusClarius::vtkInternal::ReceiveRawData(
int dataSize)
735 LOG_INFO(
"Receiving " << dataSize <<
" bytes of raw data");
737 CusReturnFn returnFunction = (CusReturnFn)(&vtkInternal::RawDataWriteFn);
738 this->AllocateRawData(dataSize);
739 cusCastReadRawData(&this->RawDataPointer, returnFunction);
744 void vtkPlusClarius::vtkInternal::RawDataWriteFn(
int retCode)
749 LOG_ERROR(
"Invalid device");
752 vtkInternal*
self = device->
Internal;
754 self->IsReceivingRawData =
false;
758 LOG_ERROR(
"Could not read raw data!");
762 LOG_INFO(
"Raw data received successfully!");
764 std::string filename = device->GetRawDataOutputFilename();
765 if (filename.empty())
767 filename = vtkIGSIOAccurateTimer::GetDateAndTimeString() +
"_ClariusData.tar";
770 if (device->
CompressRawData && vtksys::SystemTools::GetFilenameLastExtension(filename) !=
".gz")
772 filename = filename +
".gz";
775 if (!vtksys::SystemTools::FileIsFullPath(filename.c_str()))
783 gzFile file = gzopen(filename.c_str(),
"wb");
784 gzwrite(file, self->RawDataPointer, self->RawDataSize);
789 FILE* file = fopen(filename.c_str(),
"wb");
790 fwrite((
char*)self->RawDataPointer, 1, self->RawDataSize, file);
794 LOG_INFO(
"Raw data saved as: " << filename);
798 void vtkPlusClarius::vtkInternal::AllocateRawData(
int dataSize)
800 if (this->RawDataPointer)
802 delete[] this->RawDataPointer;
803 this->RawDataPointer =
nullptr;
808 this->RawDataPointer =
new char[dataSize];
810 this->RawDataSize = dataSize;
843 LOG_TRACE(
"vtkPlusClarius: Constructor");
851 this->
Internal->AllocateRawData(-1);
865 int destroyed = cusCastDestroy();
868 LOG_ERROR(
"Error destoying the listener");
883 LOG_TRACE(
"vtkPlusClarius: GetInstance()");
891 LOG_ERROR(
"Instance is null, creating new instance");
901 os << indent <<
"ipAddress" << this->
IpAddress << std::endl;
902 os << indent <<
"tcpPort" << this->
TcpPort << std::endl;
903 os << indent <<
"UdpPort" << this->
Internal->UdpPort << std::endl;
904 os << indent <<
"FrameNumber" << this->
FrameNumber << std::endl;
905 os << indent <<
"FrameWidth" << this->
FrameWidth << std::endl;
906 os << indent <<
"FrameHeight" << this->
FrameHeight << std::endl;
912 LOG_TRACE(
"vtkPlusClarius::ReadConfiguration");
915 XML_READ_STRING_ATTRIBUTE_REQUIRED(
IpAddress, deviceConfig);
916 XML_READ_SCALAR_ATTRIBUTE_REQUIRED(
int,
TcpPort, deviceConfig);
918 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
FrameWidth, deviceConfig);
919 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
FrameHeight, deviceConfig);
920 XML_READ_BOOL_ATTRIBUTE_OPTIONAL(
ImuEnabled, deviceConfig);
927 int tiltSensorWestAxisIndex = 0;
928 if (deviceConfig->GetScalarAttribute(
"TiltSensorWestAxisIndex", tiltSensorWestAxisIndex))
930 if (tiltSensorWestAxisIndex < 0 || tiltSensorWestAxisIndex > 2)
932 LOG_ERROR(
"TiltSensorWestAxisIndex is invalid. Specified value: " << tiltSensorWestAxisIndex <<
". Valid values: 0, 1, 2. Keep using the default value: " 944 if (FilteredTiltSensorWestAxisIndex < 0 || FilteredTiltSensorWestAxisIndex > 2)
946 LOG_ERROR(
"FilteredTiltSensorWestAxisIndex is invalid. Specified value: " <<
FilteredTiltSensorWestAxisIndex <<
". Valid values: 0, 1, 2. Keep using the default value: " 947 << this->FilteredTiltSensorWestAxisIndex);
958 const char* ahrsAlgoName = deviceConfig->GetAttribute(
"AhrsAlgorithm");
959 if (ahrsAlgoName != NULL)
961 if (STRCASECMP(
"MADGWICK_MARG", ahrsAlgoName) == 0 || STRCASECMP(
"MADGWICK_IMU", ahrsAlgoName) == 0)
963 if (dynamic_cast<MadgwickAhrsAlgo*>(this->
Internal->AhrsAlgo) == 0)
968 this->
Internal->AhrsAlgo =
new MadgwickAhrsAlgo;
970 if (STRCASECMP(
"MADGWICK_MARG", ahrsAlgoName) == 0)
972 this->
Internal->AhrsUseMagnetometer =
true;
976 this->
Internal->AhrsUseMagnetometer =
false;
979 else if (STRCASECMP(
"MAHONY_MARG", ahrsAlgoName) == 0 || STRCASECMP(
"MAHONY_IMU", ahrsAlgoName) == 0)
981 if (dynamic_cast<MahonyAhrsAlgo*>(this->
Internal->AhrsAlgo) == 0)
986 this->
Internal->AhrsAlgo =
new MahonyAhrsAlgo;
988 if (STRCASECMP(
"MAHONY_MARG", ahrsAlgoName) == 0)
990 this->
Internal->AhrsUseMagnetometer =
true;
994 this->
Internal->AhrsUseMagnetometer =
false;
999 LOG_ERROR(
"Unable to recognize AHRS algorithm type: " << ahrsAlgoName <<
". Supported types: MADGWICK_MARG, MAHONY_MARG, MADGWICK_IMU, MAHONY_IMU");
1003 const char* FilteredTiltSensorAhrsAlgoName = deviceConfig->GetAttribute(
"FilteredTiltSensorAhrsAlgorithm");
1004 if (FilteredTiltSensorAhrsAlgoName != NULL)
1006 if (STRCASECMP(
"MADGWICK_IMU", FilteredTiltSensorAhrsAlgoName) == 0)
1008 if (dynamic_cast<MadgwickAhrsAlgo*>(this->
Internal->FilteredTiltSensorAhrsAlgo) == 0)
1012 delete this->
Internal->FilteredTiltSensorAhrsAlgo;
1013 this->
Internal->FilteredTiltSensorAhrsAlgo =
new MadgwickAhrsAlgo;
1016 else if (STRCASECMP(
"MAHONY_IMU", FilteredTiltSensorAhrsAlgoName) == 0)
1018 if (dynamic_cast<MahonyAhrsAlgo*>(this->
Internal->FilteredTiltSensorAhrsAlgo) == 0)
1022 delete this->
Internal->FilteredTiltSensorAhrsAlgo;
1023 this->
Internal->FilteredTiltSensorAhrsAlgo =
new MahonyAhrsAlgo;
1028 LOG_ERROR(
"Unable to recognize AHRS algorithm type for Filtered Tilt: " << FilteredTiltSensorAhrsAlgoName <<
". Supported types: MADGWICK_IMU, MAHONY_IMU");
1039 LOG_TRACE(
"vtkPlusClarius::WriteConfiguration");
1042 XML_WRITE_STRING_ATTRIBUTE(
IpAddress, deviceConfig);
1043 deviceConfig->SetIntAttribute(
"TcpPort", this->
TcpPort);
1044 deviceConfig->SetIntAttribute(
"FrameWidth", this->
FrameWidth);
1045 deviceConfig->SetIntAttribute(
"FrameHeight", this->
FrameHeight);
1046 XML_WRITE_BOOL_ATTRIBUTE(
ImuEnabled, deviceConfig);
1057 LOG_TRACE(
"vtkPlusClarius::NotifyConfigured");
1062 LOG_WARNING(
"vtkPlusClarius is expecting one output channel and there are " <<
1063 this->
OutputChannels.size() <<
" channels. First output channel will be used.");
1068 LOG_ERROR(
"No output channels defined for vtkPlusClarius. Cannot proceed.");
1073 std::vector<vtkPlusDataSource*> sources;
1075 if (sources.size() > 1)
1077 LOG_WARNING(
"More than one output video source found. First will be used");
1079 if (sources.size() == 0)
1081 LOG_ERROR(
"Video source required in configuration. Cannot proceed.");
1089 LOG_ERROR(
"Unable to retrieve the video source in the vtkPlusClarius device.");
1099 LOG_TRACE(
"vtkPlusClarius: Probe");
1109 std::string vtkPlusClarius::vtkPlusClarius::GetSdkVersion()
1111 std::ostringstream version;
1112 version <<
"Sdk version not available" <<
"\n";
1113 return version.str();
1119 LOG_DEBUG(
"vtkPlusClarius: InternalConnect");
1124 this->
Internal->RawImuDataStream <<
"FrameNum,SystemTimestamp,ConvertedTimestamp,ImageTimestamp,ImuTimeStamp,ax,ay,az,gx,gy,gz,mx,my,mz,\n";
1126 this->
Internal->RawImuDataStream.close();
1129 this->
Internal->AccelerometerTool = NULL;
1132 this->
Internal->GyroscopeTool = NULL;
1135 this->
Internal->MagnetometerTool = NULL;
1138 this->
Internal->TiltSensorTool = NULL;
1141 this->
Internal->FilteredTiltSensorTool = NULL;
1144 this->
Internal->OrientationSensorTool = NULL;
1151 CusNewProcessedImageFn processedImageCallbackPtr = static_cast<CusNewProcessedImageFn>(&vtkInternal::NewProcessedImageFn);
1152 CusNewRawImageFn rawDataCallBackPtr = static_cast<CusNewRawImageFn>(&vtkInternal::NewRawImageFn);
1153 CusFreezeFn freezeCallBackFnPtr = static_cast<CusFreezeFn>(&vtkInternal::FreezeFn);
1154 CusButtonFn buttonCallBackFnPtr = static_cast<CusButtonFn>(&vtkInternal::ButtonFn);
1155 CusProgressFn progressCallBackFnPtr = static_cast<CusProgressFn>(&vtkInternal::ProgressFn);
1156 CusErrorFn errorCallBackFnPtr = static_cast<CusErrorFn>(&vtkInternal::ErrorFn);
1159 std::vector<vtkPlusDataSource*> bModeSources;
1161 if (bModeSources.empty())
1163 processedImageCallbackPtr =
nullptr;
1167 std::vector<vtkPlusDataSource*> rfModeSources;
1169 if (rfModeSources.empty())
1171 rawDataCallBackPtr =
nullptr;
1176 if (cusCastInit(0, NULL, this->
Internal->PathToSecKey.c_str(),
1177 processedImageCallbackPtr,
1181 freezeCallBackFnPtr,
1182 buttonCallBackFnPtr,
1183 progressCallBackFnPtr,
1190 this->
Internal->Initialized =
true;
1192 catch (
const std::runtime_error& re)
1194 LOG_ERROR(
"Runtime error: " << re.what());
1197 catch (
const std::exception& ex)
1199 LOG_ERROR(
"Error occurred: " << ex.what());
1204 LOG_ERROR(
"Unknown failure occured");
1209 const char* ip = this->
IpAddress.c_str();
1212 CusConnectFn returnFunction = (CusConnectFn)(&vtkInternal::ConnectReturnFn);
1213 cusCastConnect(ip, this->
TcpPort,
"research", returnFunction);
1216 int maxConnectionAttempts = 20;
1217 for (
int i = 0;
i < 20; ++
i)
1220 const double connectionDelaySeconds = 1.0;
1221 vtkIGSIOAccurateTimer::DelayWithEventProcessing(connectionDelaySeconds);
1225 vtkIGSIOAccurateTimer::DelayWithEventProcessing(connectionDelaySeconds);
1230 catch (
const std::runtime_error& re)
1232 LOG_ERROR(
"Runtime error: " << re.what());
1235 catch (
const std::exception& ex)
1237 LOG_ERROR(
"Error occurred: " << ex.what());
1242 LOG_ERROR(
"Unknown failure occured");
1250 LOG_DEBUG(
"Clarius Output size can not be set, falling back to default 640*480");
1265 LOG_ERROR(
"Could not connect to scanner at ip: " << ip <<
" port number: " << this->
TcpPort);
1271 LOG_DEBUG(
"Scanner already connected to IP address=" << this->
IpAddress 1272 <<
" TCP Port Number =" << this->
TcpPort <<
"Streaming Image at UDP Port=" << this->
Internal->UdpPort);
1282 LOG_DEBUG(
"vtkPlusClarius: InternalDisconnect");
1286 if (cusCastDisconnect(
nullptr) < 0)
1288 LOG_ERROR(
"could not disconnect from scanner");
1294 LOG_DEBUG(
"Clarius device is now disconnected");
1300 LOG_DEBUG(
"...Clarius device already disconnected");
1308 if (lastNSeconds <= 0)
1313 LOG_INFO(
"Requesting raw data for last " << lastNSeconds <<
" seconds");
1314 long long int endTimestamp = vtkInternal::SecondsToNanoSeconds(this->
Internal->ClariusLastTimestamp);
1315 long long int lastNNanoSeconds = vtkInternal::SecondsToNanoSeconds(lastNSeconds);
1316 long long int startTimestamp = std::max((
long long)0, endTimestamp - lastNNanoSeconds);
1323 if (this->
Internal->IsReceivingRawData)
1325 LOG_ERROR(
"Receive data already in progress!");
1329 if (startTimestamp < 0 || endTimestamp < 0)
1331 LOG_ERROR(
"Start and end timestamps must be > 0 nanoseconds");
1334 if (startTimestamp == 0 && endTimestamp == 0)
1336 LOG_INFO(
"Requesting all available raw data");
1340 LOG_INFO(
"Requesting raw data between " << startTimestamp <<
"ns and " << endTimestamp <<
"ns");
1343 this->
Internal->IsReceivingRawData =
true;
1345 CusRawRequestFn returnFunction = (CusRawRequestFn)(&vtkInternal::RawDataRequestFn);
1346 cusCastRequestRawData(startTimestamp, endTimestamp, 0, returnFunction);
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
static const std::string RFMODE_PORT_NAME
PlusStatus RequestRawData(long long startTimestampNanoSeconds, long long endTimestampNanoSeconds)
virtual PlusStatus SetOutputImageOrientation(US_IMAGE_ORIENTATION imageOrientation)
static void BGRA32ToRGB24(int width, int height, unsigned char *s, unsigned char *d)
US_IMAGE_TYPE GetImageType()
virtual PlusStatus InternalDisconnect()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
virtual PlusStatus ToolTimeStampedUpdateWithoutFiltering(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, double unfilteredtimestamp, double filteredtimestamp, const igsioFieldMapType *customFields=NULL)
static vtkPlusClarius * New()
static const std::string BMODE_PORT_NAME
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
std::vector< vtkPlusDataSource * > GetVideoSources() const
virtual PlusStatus AddItem(vtkImageData *frame, US_IMAGE_ORIENTATION usImageOrientation, US_IMAGE_TYPE imageType, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
bool RequirePortNameInDeviceSetConfiguration
#define DEFAULT_PATH_TO_SEC_KEY
std::string to_string(ClariusAvailability avail)
virtual unsigned int GetNumberOfScalarComponents()
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
PlusStatus GetVideoSourcesByPortName(const char *aPortName, std::vector< vtkPlusDataSource * > &sources)
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
static vtkPlusConfig * GetInstance()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
virtual igsioCommon::VTKScalarPixelType GetPixelType()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
#define DEFAULT_FRAME_HEIGHT
double AhrsAlgorithmGain[2]
unsigned long FrameNumber
PlusStatus GetToolByPortName(const char *aPortName, vtkPlusDataSource *&aSource)
virtual PlusStatus Probe()
PlusStatus RequestLastNSecondsRawData(double lastNSeconds)
std::string GetOutputDirectory()
static vtkPlusClarius * GetInstance()
std::string ImuOutputFileName
virtual PlusStatus StopRecording()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual PlusStatus InternalConnect()
#define DEFAULT_FRAME_WIDTH
virtual US_IMAGE_ORIENTATION GetInputImageOrientation()
virtual bool IsConnected() const
bool StartThreadForInternalUpdates
int TiltSensorWestAxisIndex
static PlusStatus ConvertToGray(int inputCompression, int width, int height, unsigned char *s, unsigned char *d)
virtual int GetConnected() const
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
Interface to the Clarius ultrasound scans This class talks with a Clarius Scanner over the Clarius AP...
static vtkPlusClarius * Instance
FrameSizeType GetInputFrameSize() const
double FilteredTiltSensorAhrsAlgorithmGain[2]
void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual PlusStatus NotifyConfigured()
int FilteredTiltSensorWestAxisIndex
Interface to a 3D positioning tool, video source, or generalized data stream.