11 #include "PlusConfigure.h" 16 #include <vtkExtractVOI.h> 17 #include <vtkImageData.h> 18 #include <vtkImageImport.h> 20 #include <vtkMatrix4x4.h> 21 #include <vtkObjectFactory.h> 29 #include <markerdetector.h> 30 #include <cameraparameters.h> 31 #include <dictionary.h> 32 #include <posetracker.h> 35 #include <opencv2/highgui.hpp> 36 #include <opencv2/calib3d.hpp> 37 #include <opencv2/core.hpp> 54 TrackedTool(
int markerId,
float markerSizeMm,
const std::string& toolSourceId)
55 : ToolMarkerType(SINGLE_MARKER)
57 , MarkerSizeMm(markerSizeMm)
58 , ToolSourceId(toolSourceId)
61 TrackedTool(
const std::string& markerMapFile,
const std::string& toolSourceId)
62 : ToolMarkerType(MARKER_MAP)
63 , MarkerMapFile(markerMapFile)
64 , ToolSourceId(toolSourceId)
69 TOOL_MARKER_TYPE ToolMarkerType;
72 std::string MarkerMapFile;
73 std::string ToolSourceId;
75 aruco::MarkerPoseTracker MarkerPoseTracker;
76 vtkSmartPointer<vtkMatrix4x4> transformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
80 class vtkPlusOpticalMarkerTracker::vtkInternal
87 , MarkerDetector(std::make_shared<aruco::MarkerDetector>())
88 , CameraParameters(std::make_shared<aruco::CameraParameters>())
93 virtual ~vtkInternal()
95 MarkerDetector =
nullptr;
96 CameraParameters =
nullptr;
99 PlusStatus BuildTransformMatrix(vtkSmartPointer<vtkMatrix4x4> transformMatrix,
const cv::Mat& Rvec,
const cv::Mat& Tvec);
101 std::string CameraCalibrationFile;
103 std::string MarkerDictionary;
104 std::vector<TrackedTool>
Tools;
105 double LastProcessedInputDataTimestamp;
109 std::shared_ptr<aruco::MarkerDetector> MarkerDetector;
110 std::shared_ptr<aruco::CameraParameters> CameraParameters;
111 std::vector<aruco::Marker> Markers;
117 , Internal(new vtkInternal(this))
143 XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(CameraCalibrationFile, this->
Internal->CameraCalibrationFile, deviceConfig);
145 XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(MarkerDictionary, this->
Internal->MarkerDictionary, deviceConfig);
147 XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig,
"DataSources");
148 for (
int nestedElementIndex = 0; nestedElementIndex < dataSourcesElement->GetNumberOfNestedElements(); nestedElementIndex++)
150 vtkXMLDataElement* toolDataElement = dataSourcesElement->GetNestedElement(nestedElementIndex);
151 if (STRCASECMP(toolDataElement->GetName(),
"DataSource") != 0)
156 if (toolDataElement->GetAttribute(
"Type") != NULL && STRCASECMP(toolDataElement->GetAttribute(
"Type"),
"Tool") != 0)
162 const char* toolId = toolDataElement->GetAttribute(
"Id");
166 LOG_ERROR(
"Failed to initialize OpticalMarkerTracking tool: DataSource Id is missing");
171 std::string toolSourceId = toolTransformName.GetTransformName();
173 if (toolDataElement->GetAttribute(
"MarkerId") != NULL && toolDataElement->GetAttribute(
"MarkerSizeMm") != NULL)
177 toolDataElement->GetScalarAttribute(
"MarkerId", MarkerId);
179 toolDataElement->GetScalarAttribute(
"MarkerSizeMm", MarkerSizeMm);
180 TrackedTool newTool(MarkerId, MarkerSizeMm, toolSourceId);
181 this->
Internal->Tools.push_back(newTool);
183 else if (toolDataElement->GetAttribute(
"MarkerMapFile") != NULL)
190 LOG_ERROR(
"Incorrectly formatted tool data source.");
202 if (!this->
Internal->CameraCalibrationFile.empty())
204 deviceConfig->SetAttribute(
"CameraCalibrationFile", this->
Internal->CameraCalibrationFile.c_str());
206 if (!this->
Internal->MarkerDictionary.empty())
208 deviceConfig->SetAttribute(
"MarkerDictionary", this->
Internal->MarkerDictionary.c_str());
210 switch (this->
Internal->TrackingMethod)
213 deviceConfig->SetAttribute(
"TrackingMethod",
"OPTICAL");
216 deviceConfig->SetAttribute(
"TrackingMethod",
"OPTICAL_AND_DEPTH");
219 LOG_ERROR(
"Unknown tracking method passed to vtkPlusOpticalMarkerTracker::WriteConfiguration");
233 LOG_INFO(
"Use aruco camera calibration file located at: " << calibFilePath);
234 if (!vtksys::SystemTools::FileExists(calibFilePath.c_str(),
true))
236 LOG_ERROR(
"Unable to find aruco camera calibration file at: " << calibFilePath);
242 this->
Internal->CameraParameters->readFromXMLFile(calibFilePath);
244 catch (cv::Exception e)
246 LOG_ERROR(
"Unable to read calibration file: " << e.msg.c_str());
250 this->
Internal->MarkerDetector->setDictionary(this->
Internal->MarkerDictionary);
253 aruco::MarkerDetector::Params params;
254 params._thresParam1 = 7;
255 params._thresParam2 = 7;
256 params._thresParam1_range = 2;
257 this->
Internal->MarkerDetector->setParams(params);
259 bool lowestRateKnown =
false;
260 double lowestRate = 30;
267 lowestRateKnown =
true;
276 LOG_WARNING(
"vtkPlusOpticalMarkerTracker acquisition rate is not known");
279 this->
Internal->LastProcessedInputDataTimestamp = 0.0;
288 LOG_ERROR(
"ImageProcessor device requires exactly 1 input stream (that contains video data). Check configuration.");
296 PlusStatus vtkPlusOpticalMarkerTracker::vtkInternal::BuildTransformMatrix(vtkSmartPointer<vtkMatrix4x4> transformMatrix,
const cv::Mat& Rvec,
const cv::Mat& Tvec)
298 transformMatrix->Identity();
299 cv::Mat Rmat(3, 3, CV_32FC1);
302 cv::Rodrigues(Rvec, Rmat);
309 for (
int x = 0;
x <= 2;
x++)
313 transformMatrix->SetElement(
x, 3,
MM_PER_M * ((Tvec.rows == 3) ? Tvec.at<
float>(
x, 0) : Tvec.at<
float>(0,
x)));
314 for (
int y = 0;
y <= 2;
y++)
316 transformMatrix->SetElement(
x,
y, Rmat.at<
float>(
x,
y));
329 LOG_TRACE(
"Processed data is not generated, as no video data is available yet. Device ID: " << this->
GetDeviceId());
333 double oldestTrackingTimestamp(0);
336 if (this->
Internal->LastProcessedInputDataTimestamp > oldestTrackingTimestamp)
338 LOG_INFO(
"Processed image generation started. No tracking data was available between " << this->
Internal->LastProcessedInputDataTimestamp <<
"-" << oldestTrackingTimestamp <<
339 "sec, therefore no processed images were generated during this time period.");
340 this->
Internal->LastProcessedInputDataTimestamp = oldestTrackingTimestamp;
344 igsioTrackedFrame trackedFrame;
347 LOG_ERROR(
"Error while getting latest tracked frame. Last recorded timestamp: " << std::fixed << this->
Internal->LastProcessedInputDataTimestamp <<
". Device ID: " << this->GetDeviceId());
348 this->
Internal->LastProcessedInputDataTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
352 LOG_TRACE(
"Image to be processed: timestamp=" << trackedFrame.GetTimestamp());
355 FrameSizeType dim = trackedFrame.GetFrameSize();
356 igsioVideoFrame* frame = trackedFrame.GetImageData();
359 cv::Mat image(dim[1], dim[0], CV_8UC3, cv::Scalar(0, 0, 255));
363 image.data = (
unsigned char*)frame->GetScalarPointer();
368 if (!this->
Internal->MarkerFound && this->Internal->Markers.size() > 0)
377 cv::flip(image, image, 1);
379 if (this->
Internal->Markers.size() > 0)
384 source->SetInputImageOrientation(igsioCommon::HorizontalFlip(
source->GetInputImageOrientation()));
385 LOG_WARNING(
"Autodetected horizontal image flip problem. It has been corrected for this session. " \
386 "Be sure to save your config file or update your existing file to the new orientation: " \
387 << igsioCommon::GetStringFromUsImageOrientation(
source->GetInputImageOrientation()));
393 for (std::vector<TrackedTool>::iterator toolIt = begin(this->
Internal->Tools); toolIt != end(this->
Internal->Tools); ++toolIt)
395 bool toolInFrame =
false;
396 const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
397 for (std::vector<aruco::Marker>::iterator markerIt = begin(this->
Internal->Markers); markerIt != end(this->
Internal->Markers); ++markerIt)
399 if (toolIt->MarkerId == markerIt->id)
404 if (toolIt->MarkerPoseTracker.estimatePose(*markerIt, *this->Internal->CameraParameters, toolIt->MarkerSizeMm /
MM_PER_M, 4))
407 cv::Mat Rvec = toolIt->MarkerPoseTracker.getRvec();
408 cv::Mat Tvec = toolIt->MarkerPoseTracker.getTvec();
409 this->
Internal->BuildTransformMatrix(toolIt->transformMatrix, Rvec, Tvec);
410 ToolTimeStampedUpdate(toolIt->ToolSourceId, toolIt->transformMatrix, TOOL_OK, this->FrameNumber, unfilteredTimestamp);
416 LOG_ERROR(
"Pose estimation failed. Tool " << toolIt->ToolSourceId <<
" with marker " << toolIt->MarkerId <<
".");
424 ToolTimeStampedUpdate(toolIt->ToolSourceId, toolIt->transformMatrix, TOOL_OUT_OF_VIEW, this->FrameNumber, unfilteredTimestamp);
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
PlusStatus InternalConnect()
Abstract interface for tracker and video devices.
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
ChannelContainer InputChannels
virtual std::string GetDeviceId() const
virtual PlusStatus ToolTimeStampedUpdate(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, unsigned long frameNumber, double unfilteredtimestamp, const igsioFieldMapType *customFields=NULL)
virtual PlusStatus InternalUpdate()
Virtual device that tracks fiducial markers on the input channel in real time.
vtkStandardNewMacro(vtkPlusOpticalMarkerTracker)
DataSourceContainer Tools
static vtkPlusConfig * GetInstance()
virtual double GetAcquisitionRate() const
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *)
unsigned long FrameNumber
ChannelContainer::const_iterator ChannelContainerConstIterator
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
~vtkPlusOpticalMarkerTracker()
bool StartThreadForInternalUpdates
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
Direction vectors of rods y
virtual PlusStatus NotifyConfigured()
std::string GetToolReferenceFrameName() const
vtkPlusOpticalMarkerTracker()
vtkPlusDevice * GetOwnerDevice() const
Interface to a 3D positioning tool, video source, or generalized data stream.