Medical Imaging Interaction Toolkit  2018.4.99-bd7b41ba
Medical Imaging Interaction Toolkit
mitkOpenCVVideoSource.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkOpenCVVideoSource.h"
14 #include <iostream>
15 #include <algorithm>
16 
18 : m_VideoCapture(nullptr),
19  m_CurrentImage(nullptr),
20  m_CurrentVideoTexture(nullptr),
21  m_PauseImage(nullptr),
22  m_GrabbingDeviceNumber(-1),
23  m_RepeatVideo(false),
24  m_UseCVCAMLib(false),
25  m_UndistortImage(false),
26  m_FlipXAxisEnabled(false),
27  m_FlipYAxisEnabled(false)
28 {
29 }
30 
32 {
33  this->Reset();
34 }
35 
36 void mitk::OpenCVVideoSource::SetVideoFileInput(const char * filename, bool repeatVideo, bool /*useCVCAMLib*/)
37 {
38  this->Reset();
39  m_VideoFileName = filename;
40 
41  m_VideoCapture = cvCaptureFromFile(filename);
42  if(!m_VideoCapture)
43  MITK_WARN << "Error in initializing video file input!";
44 
45  m_RepeatVideo = repeatVideo;
46  //m_CurrentImage = cvCreateImage(cvSize(m_CaptureWidth,m_CaptureHeight),8,3);
47  this->Modified();
48 
49 }
50 void mitk::OpenCVVideoSource::SetVideoCameraInput(int cameraindex, bool /*useCVCAMLib*/)
51 {
52  this->Reset();
53 
54  m_GrabbingDeviceNumber = cameraindex;
55  m_VideoCapture = cvCaptureFromCAM(m_GrabbingDeviceNumber);
56  if(!m_VideoCapture)
57  MITK_ERROR << "Error in initializing CVHighGUI video camera!"<< std::endl;
58 
59  this->Modified();
60 }
61 
63 {
64  return cvGetCaptureProperty(m_VideoCapture, property_id);
65 }
66 
67 int mitk::OpenCVVideoSource::SetVideoCaptureProperty(int property_id, double value)
68 {
69  return cvSetCaptureProperty(m_VideoCapture, property_id, value);
70 }
71 
72 //method extended for "static video feature" if enabled
74 { // Fetch Frame and return pointer to opengl texture
75  FetchFrame();
76 
78  {
79  //rotate the image to get a static video
81 
82  }
83 
84  //transfer the image to a texture
85  this->UpdateVideoTexture();
86  return this->m_CurrentVideoTexture;
87  this->Modified();
88 }
89 
91 {
92  if(m_CurrentImage)
93  {
94  cv::Mat copy = cv::cvarrToMat( m_CurrentImage, false );
95  return copy.clone();
96  }
97  return cv::Mat();
98 }
99 
101 {
102  return m_CurrentImage;
103 }
104 
106 { // get last captured frame for processing the image data
107  if(m_CurrentImage)
108  {
109  if(image)
110  {
111  image->origin = m_CurrentImage->origin;
112  memcpy(image->imageData,m_CurrentImage->imageData,m_CurrentImage->width*m_CurrentImage->height*m_CurrentImage->nChannels);
113  }
114  }
115 }
116 
118 { // main procedure for updating video data
120  {
121  if(m_VideoCapture) // we use highgui
122  {
123  if(!m_CapturePaused)
124  {
125  // release old image here
126  m_CurrentImage = cvQueryFrame(m_VideoCapture);
127  ++m_FrameCount;
128  }
129 
130  if(m_CurrentImage == nullptr) // do we need to repeat the video if it is from video file?
131  {
132  double framePos = this->GetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO);
133  MITK_DEBUG << "End of video file found. framePos: " << framePos;
134  if(m_RepeatVideo && framePos >= 0.99)
135  {
136  MITK_DEBUG << "Restarting video file playback.";
137  this->SetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO, 0);
138  m_FrameCount = 0;
139  m_CurrentImage = cvQueryFrame(m_VideoCapture);
140  }
141  else
142  {
143  std::ostringstream s;
144  s << "End of video file " << m_VideoFileName;
145  std::logic_error err( s.str() );
146  throw err;
147  }
148  }
149  else
150  {
151  // only undistort if not paused
152  if(m_UndistortImage && m_UndistortCameraImage.IsNotNull())
153  m_UndistortCameraImage->UndistortImageFast(m_CurrentImage, nullptr);
154  }
155 
156  if(m_CaptureWidth == 0 || m_CaptureHeight == 0)
157  {
158  MITK_DEBUG << "Trying to set m_CaptureWidth & m_CaptureHeight.";
161  MITK_INFO << "frame width: " << m_CaptureWidth << ", height: " << m_CaptureHeight;
162  m_CurrentImage->origin = 0;
163  }
164  }
165  }
166 }
167 
169 { //write the grabbed frame into an opengl compatible array, that means flip it and swap channel order
170  if(!m_CurrentImage)
171  return;
172 
173  if(m_CurrentVideoTexture == nullptr)
175 
176  int width = m_CurrentImage->width;
177  int height = m_CurrentImage->height;
178  int widthStep = m_CurrentImage->widthStep;
179  int nChannels = m_CurrentImage->nChannels;
180  unsigned char* tex = m_CurrentVideoTexture;
181  char* data = m_CurrentImage->imageData;
182  char* currentData = m_CurrentImage->imageData;
183 
184  int hIndex=0;
185  int wIndex=0;
186  int iout,jout;
187 
188  for(int i=0;i<width*height*3;i+=3,++wIndex)
189  {
190  if(wIndex >= width)
191  {
192  wIndex=0;
193  hIndex++;
194  }
195 
196  // vertically flip the image
197  iout = -hIndex+height-1;
198  jout = wIndex;
199 
200  currentData = data + iout*widthStep;
201 
202  tex[i+2] = currentData[jout*nChannels + 0]; // B
203  tex[i+1] = currentData[jout*nChannels + 1]; // G
204  tex[i] = currentData[jout*nChannels + 2]; // R
205  }
206 
207 }
208 
210 {
211  if(m_VideoCapture != nullptr)
212  m_CapturingInProcess = true;
213  else
214  m_CapturingInProcess = false;
215 }
216 
218 {
219  m_CapturePaused = false;
220  m_CapturingInProcess = false;
221 }
222 
224 {
225  return m_UndistortCameraImage;
226 }
227 
229 {
231 
232  if(m_CapturePaused)
233  {
234  m_PauseImage = cvCloneImage(m_CurrentImage);
235 
236  // undistort this pause image if necessary
237  if(m_UndistortImage)
238  m_UndistortCameraImage->UndistortImageFast(m_PauseImage, nullptr);
240  }
241  else
242  {
243  cvReleaseImage( &m_PauseImage ); // release old pause image if necessary
244  m_CurrentImage = nullptr;
245  m_PauseImage = nullptr;
246  }
247 }
248 
250 {
251  // Initialize Undistortion
252  m_UndistortImage = true;
253  float kc[4];
254  kc[0] = distortion[0]; kc[1] = distortion[1];
255  kc[2] = distortion[2]; kc[3] = distortion[3];
256  if(m_CaptureWidth == 0 || m_CaptureHeight == 0)
257  FetchFrame();
258 
260  m_UndistortCameraImage->SetUndistortImageFastInfo(focal[0], focal[1], principal[0], principal[1], kc, (float)m_CaptureWidth, (float)m_CaptureHeight);
261 }
262 
264 {
265  m_UndistortImage = false;
266 }
267 
268 // functions for compatibility with ITK segmentation only
270 {
271  FetchFrame();
272 
273  // Prepare iteration
274  HSVConstIteratorType itImage( Image, Image->GetLargestPossibleRegion());
275  itImage.GoToBegin();
276  HSVPixelType pixel;
277  int rowsize = 3 * m_CaptureWidth;
278 
279  char* bufferend;
280  char* picture;
281  picture = this->m_CurrentImage->imageData;
282  bufferend = this->m_CurrentImage->imageData + 3*(m_CaptureHeight*m_CaptureWidth);
283 
284  float r,g,b,h,s,v;
285  try
286  {
287  // we have to flip the image
288  for(char* datapointer = bufferend - rowsize;datapointer >= picture; datapointer -= rowsize)
289  {
290  for(char* current = datapointer; current < datapointer + rowsize; current++)
291  {
292  b = *current; current++;
293  g = *current; current++;
294  r = *current;
295  RGBtoHSV(r,g,b,h,s,v);
296  pixel[0] = h;
297  pixel[1] = s;
298  pixel[2] = v;
299 
300  itImage.Set(pixel);
301  ++itImage;
302  }
303  }
304  }
305  catch( ... )
306  {
307  std::cout << "Exception raised mitkOpenCVVideoSource: get hsv itk image conversion error." << std::endl;
308  }
309 
310 }
311 
312 void mitk::OpenCVVideoSource::RGBtoHSV(float r, float g, float b, float &h, float &s, float &v)
313 {
314  if(r > 1.0)
315  r = r/255;
316  if(b > 1.0)
317  b = b/255;
318  if(g > 1.0)
319  g = g/255;
320 
321  float mn=r,mx=r;
322  int maxVal=0;
323 
324  if (g > mx){ mx=g;maxVal=1;}
325  if (b > mx){ mx=b;maxVal=2;}
326  if (g < mn) mn=g;
327  if (b < mn) mn=b;
328 
329  float delta = mx - mn;
330 
331  v = mx;
332  if( mx != 0 )
333  s = delta / mx;
334  else
335  {
336  s = 0;
337  h = 0;
338  return;
339  }
340  if (s==0.0f)
341  {
342  h=-1;
343  return;
344  }
345  else
346  {
347  switch (maxVal)
348  {
349  case 0:{h = ( g - b ) / delta;break;} // yel < h < mag
350  case 1:{h = 2 + ( b - r ) / delta;break;} // cyan < h < yel
351  case 2:{h = 4 + ( r - g ) / delta;break;} // mag < h < cyan
352  }
353  }
354 
355  h *= 60;
356  if( h < 0 ) h += 360;
357 }
358 
359 /*
360 * Rotate input image according to rotation angle around the viewing direction.
361 * Angle is supposed to be calculated in QmitkARRotationComponet in the update() method.
362 */
363 IplImage* mitk::OpenCVVideoSource::FlipImage(IplImage* input)
364 {
365  if(input == nullptr)
366  { //warn the user and quit
367  std::cout<<"openCVVideoSource: Current video image is null! "<< std::endl;
368  return input;
369  }
370 
372  {
373  cvFlip(input,nullptr,0);
374  }
376  {
377  cvFlip(input,nullptr,1);
378  }
380  {
381  cvFlip(input,nullptr,-1);
382  }
383 
384  return input;
385 }
386 
388 {
389  // set capturing to false
390  this->StopCapturing();
391  this->m_FrameCount = 0;
392  if(m_VideoCapture)
393  cvReleaseCapture(&m_VideoCapture);
394  m_VideoCapture = nullptr;
395  m_CurrentImage = nullptr;
396  m_CaptureWidth = 0;
397  m_CaptureHeight = 0;
398  delete m_CurrentVideoTexture;
399  m_CurrentVideoTexture = nullptr;
400  if(m_PauseImage)
401  cvReleaseImage(&m_PauseImage);
402  m_PauseImage = nullptr;
403  m_CapturePaused = false;
404  m_VideoFileName.clear();
406  // do not touch repeat video
407  //m_RepeatVideo = false;
408  m_UseCVCAMLib = false;
409  // do not touch undistort settings
410  // bool m_UndistortImage;
411 }
412 
414 {
415  this->m_FlipXAxisEnabled = enable;
416  this->Modified();
417 }
418 
420 {
421  this->m_FlipXAxisEnabled = enable;
422  this->Modified();
423 }
424 
virtual void SetEnableYAxisFlip(bool enable)
virtual int SetVideoCaptureProperty(int property_id, double value)
unsigned long m_FrameCount
virtual void GetCurrentFrameAsItkHSVPixelImage(HSVPixelImageType::Pointer &Image)
#define MITK_INFO
Definition: mitkLogMacros.h:18
mitk::UndistortCameraImage::Pointer m_UndistortCameraImage
itk::ImageRegionIterator< HSVPixelImageType > HSVConstIteratorType
#define MITK_ERROR
Definition: mitkLogMacros.h:20
std::string m_VideoFileName
saves the video file name (is empty if a grabbing device is used or if this is not initialized) ...
virtual double GetVideoCaptureProperty(int property_id)
virtual void EnableOnlineImageUndistortion(mitk::Point3D focal, mitk::Point3D principal, mitk::Point4D distortion)
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
void RGBtoHSV(float r, float g, float b, float &h, float &s, float &v)
virtual void GetCurrentFrameAsOpenCVImage(IplImage *image)
virtual void SetEnableXAxisFlip(bool enable)
#define MITK_WARN
Definition: mitkLogMacros.h:19
virtual void SetVideoFileInput(const char *filename, bool repeatVideo, bool useCVCAMLib=false)
virtual void SetVideoCameraInput(int cameraindex, bool useCVCAMLib=false)
Image class for storing images.
Definition: mitkImage.h:72
virtual void DisableOnlineImageUndistortion()
mitk::Image::Pointer image
unsigned char * m_CurrentVideoTexture
unsigned char * GetVideoTexture() override
virtual const IplImage * GetCurrentFrame()
virtual IplImage * FlipImage(IplImage *input)
virtual bool OnlineImageUndistortionEnabled() const
itk::FixedArray< float, 3 > HSVPixelType
short m_GrabbingDeviceNumber
saves the grabbing device number (is -1 if a videofilename is used or if this is not initialized) ...