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