PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkInfraredSeekCam.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 
6 Developed by MACBIOIDI-ULPGC & IACTEC-IAC group
7 =========================================================Plus=header=end*/
8 
9 // Local includes
10 #include "PlusConfigure.h"
11 #include "vtkPlusChannel.h"
12 #include "vtkPlusDataSource.h"
13 #include "vtkInfraredSeekCam.h"
14 
15 // VTK includes
16 #include <vtkImageData.h>
17 #include <vtkObjectFactory.h>
18 
19 //----------------------------------------------------------------------------
20 
22 
23 //----------------------------------------------------------------------------
25 {
26  CalibTemperature = false;
27  ExistsBias = false;
28  ExistsFlat = false;
30  this->StartThreadForInternalUpdates = true;
31 }
32 
33 //----------------------------------------------------------------------------
35 {
36 }
37 
38 //----------------------------------------------------------------------------
39 void vtkInfraredSeekCam::PrintSelf(ostream& os, vtkIndent indent)
40 {
41  this->Superclass::PrintSelf(os, indent);
42 
43  os << indent << "InfraredSeekCam: Pro Seek Camera" << std::endl;
44 }
45 
46 //-----------------------------------------------------------------------------
47 PlusStatus vtkInfraredSeekCam::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
48 {
49  bool calibTemperatureRead; // Temperature calibration
50  std::string calibMulStr; // Temperature calibration
51  std::string calibBiasStr; // Temperature calibration
52  std::string flatFilepath;
53  std::string biasFilepath;
54 
55  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
56  // Sensor calibration
57  XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(FlatFile, flatFilepath, deviceConfig);
58  XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(BiasFile, biasFilepath, deviceConfig);
59  // Temperature calibration
60  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_REQUIRED(CalibrateTemperature, calibTemperatureRead, deviceConfig);
61  if (calibTemperatureRead) {
62  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(TemperatureMultiplier, calibMulStr, deviceConfig);
63  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(TemperatureBias, calibBiasStr, deviceConfig);
64  CalibTemperature = calibTemperatureRead;
65  CalibMul = std::stof(calibMulStr);
66  CalibBias = std::stof(calibBiasStr);
67  }
68 
69  if (!flatFilepath.empty()) {
70  LOG_INFO("Detected Flat File: " << flatFilepath);
71  ExistsFlat = ReadImage(Flat, flatFilepath);
72  }
73 
74  if (!biasFilepath.empty()) {
75  LOG_INFO("Detected Bias File: " << biasFilepath);
76  ExistsBias = ReadImage(Bias, biasFilepath);;
77  }
78 
79  LOG_DEBUG("Configure Pro Seek Camera");
80  return PLUS_SUCCESS;
81 }
82 
83 //-----------------------------------------------------------------------------
84 bool vtkInfraredSeekCam::ReadImage(cv::Mat &output, const std::string& filename) const {
85  // Try to read with opencv read function
86  cv::Mat aux = cv::imread(filename, 0);
87  if (aux.data) {
88  aux.convertTo(output, CV_32F);
89  return true;
90  }
91  // If that didnt work, try to read as a binary file
92  if (!ReadBinaryFile(filename, output)) {
93  LOG_WARNING("Failed to open " << filename << " file. This file will not be used");
94  return false;
95  }
96 }
97 
98 //-----------------------------------------------------------------------------
99 PlusStatus vtkInfraredSeekCam::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
100 {
101  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
102  return PLUS_SUCCESS;
103 }
104 
105 //----------------------------------------------------------------------------
107 {
108  if (freeze)
109  this->Disconnect();
110  else
111  this->Connect();
112 
113  return PLUS_SUCCESS;
114 }
115 
116 //----------------------------------------------------------------------------
118 {
119  // Select the camera. Seek Pro is default.
120  this->Capture = std::make_shared<LibSeek::SeekThermalPro>();
121  this->Frame = std::make_shared<cv::Mat>();
122 
123  if (!this->Capture->open())
124  {
125  LOG_ERROR("Failed to open seek pro");
126  return PLUS_FAIL;
127  }
128 
129  return PLUS_SUCCESS;
130 }
131 
132 //----------------------------------------------------------------------------
134 {
135  this->Capture = nullptr; // automatically closes resources/connections
136  this->Frame = nullptr;
137 
138  return PLUS_SUCCESS;
139 }
140 
141 //----------------------------------------------------------------------------
143 {
144  if (!this->Capture->isOpened())
145  {
146  // No need to update if we're not able to read data
147  LOG_ERROR("vtkInfraredSeekCam::InternalUpdate Unable to read date");
148  return PLUS_SUCCESS;
149  }
150 
151  // Capture one frame from the SeekPro capture device
152  if (!this->Capture->read(FrameInt)) // 16UC1
153  {
154  LOG_ERROR("Unable to receive frame");
155  return PLUS_FAIL;
156  }
157 
158  FrameInt.convertTo(FrameFloat, CV_32F);
159 
160  if (ExistsFlat && ExistsBias) {
161  FrameFloat = FrameFloat.mul(Flat);
162  FrameFloat -= Bias;
163  }
164 
165  if (CalibTemperature) {
166  FrameFloat *= CalibMul;
168  }
169 
170  *this->Frame = FrameFloat;
171 
172  vtkPlusDataSource* aSource(nullptr);
173  if (this->GetFirstActiveOutputVideoSource(aSource) == PLUS_FAIL || aSource == nullptr)
174  {
175  LOG_ERROR("Unable to grab a video source. Skipping frame.");
176  return PLUS_FAIL;
177  }
178 
179  if (aSource->GetNumberOfItems() == 0)
180  {
181  // Init the buffer with the metadata from the first frame
182  aSource->SetImageType(US_IMG_BRIGHTNESS);
183  aSource->SetPixelType(VTK_TYPE_FLOAT32);
184  aSource->SetNumberOfScalarComponents(1);
185  aSource->SetInputFrameSize(this->Frame->cols, this->Frame->rows, 1);
186  }
187 
188  // Add the frame to the stream buffer
189  FrameSizeType frameSize = { static_cast<unsigned int>(this->Frame->cols), static_cast<unsigned int>(this->Frame->rows), 1 };
190  if (aSource->AddItem(this->Frame->data, aSource->GetInputImageOrientation(), frameSize, VTK_TYPE_FLOAT32, 1, US_IMG_BRIGHTNESS, 0, this->FrameNumber) == PLUS_FAIL)
191  {
192  return PLUS_FAIL;
193  }
194 
195  this->FrameNumber++;
196 
197  return PLUS_SUCCESS;
198 }
199 
200 //----------------------------------------------------------------------------
202 {
203  if (this->OutputChannels.size() > 1)
204  {
205  LOG_WARNING("vtkInfraredSeekCam is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
206  }
207 
208  if (this->OutputChannels.empty())
209  {
210  LOG_ERROR("No output channels defined for vtkInfraredSeekCam. Cannot proceed.");
211  this->CorrectlyConfigured = false;
212  return PLUS_FAIL;
213  }
214 
215  return PLUS_SUCCESS;
216 }
217 
218 //-----------------------------------------------------------------------------
219 bool vtkInfraredSeekCam::ReadBinaryFile(const std::string& filename, cv::Mat& mat) const {
220  float rows, cols;
221  try {
222 
223  std::ifstream ifs(filename, std::ios::binary);
224  if(!ifs.is_open()) {
225  LOG_ERROR("Cant open " << filename);
226  return false;
227  }
228 
229  ifs.read((char*)(&rows), sizeof(float));
230  ifs.read((char*)(&cols), sizeof(float));
231  if (rows == 0 || cols == 0) {
232  LOG_ERROR("File corrupted or incomplete, " << filename);
233  return false;
234  }
235 
236  mat.release();
237  mat.create(rows, cols, CV_32F);
238  ifs.read((char*)(mat.data), mat.elemSize() * mat.total());
239  return true;
240 
241  } catch (const std::ifstream::failure& ex) {
242  LOG_ERROR(ex.what() << " at " << filename);
243  return false;
244  }
245 }
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
bool ReadBinaryFile(const std::string &filename, cv::Mat &temp) 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 RequireImageOrientationInConfiguration
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
virtual PlusStatus InternalConnect() VTK_OVERRIDE
#define PLUS_FAIL
Definition: PlusCommon.h:43
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
PlusStatus FreezeDevice(bool freeze)
std::shared_ptr< LibSeek::SeekThermalPro > Capture
virtual PlusStatus Disconnect()
PlusStatus GetFirstActiveOutputVideoSource(vtkPlusDataSource *&aVideoSource)
unsigned long FrameNumber
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
std::shared_ptr< cv::Mat > Frame
virtual PlusStatus Connect()
vtkStandardNewMacro(vtkInfraredSeekCam)
virtual PlusStatus NotifyConfigured()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
PlusStatus ReadConfiguration(vtkXMLDataElement *config)
PlusStatus WriteConfiguration(vtkXMLDataElement *config)
virtual US_IMAGE_ORIENTATION GetInputImageOrientation()
bool StartThreadForInternalUpdates
bool ReadImage(cv::Mat &output, const std::string &filename) const
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
virtual PlusStatus InternalDisconnect() VTK_OVERRIDE
Class for interfacing an Infrared Seek capture device and recording frames into a Plus buffer.
virtual int GetNumberOfItems()
bool CorrectlyConfigured
Interface to a 3D positioning tool, video source, or generalized data stream.