Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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