frame_helper
FrameQImageConverter.h
Go to the documentation of this file.
1 /*
2  * FrameQImageConverter.h
3  *
4  * Created on: Oct 15, 2010
5  * Author: aduda
6  */
7 
8 /*
9  * This Class is Qt depended !!!
10  * It can be used in Qt projects to convert base::samples::frame::Frame
11  * to QImages
12  *
13  */
14 
15 #ifndef FRAMEQIMAGECONVERTER_H_
16 #define FRAMEQIMAGECONVERTER_H_
17 
18 #include <QtGui/QImage>
19 #include "FrameHelper.h"
20 #include <stdexcept>
21 #include <math.h>
22 #include <limits>
23 #include <opencv2/core/core.hpp>
24 #include <opencv2/imgproc/imgproc.hpp>
25 #include <opencv2/highgui/highgui.hpp>
26 
27 // cv::applyColorMap was moved to imgproc
28 // and contrib no longer exists
29 #if CV_MAJOR_VERSION < 3
30  #include <opencv2/contrib/contrib.hpp>
31 #endif
32 
33 namespace frame_helper
34 {
35  //to a rgb image
36  //if a vaule of 10 is reached ==> h = 360° but s will be reduced
37  static const float MAX_H = 10.0f; //this value is used to convert a 64Bit grayscale image
39  {
40  public:
42  virtual
44 
56  void hsvToRgb(float h, float s, float v,int &r, int &g, int &b)
57  {
58  int i = h * 6;
59  float f = h * 6 - i;
60  float p = v * (1 - s);
61  float q = v * (1 - f * s);
62  float t = v * (1 - (1 - f) * s);
63  switch(i % 6){
64  case 0: r = v*255; g = t*255; b = p*255; break;
65  case 1: r = q*255; g = v*255; b = p*255; break;
66  case 2: r = p*255; g = v*255; b = t*255; break;
67  case 3: r = p*255; g = q*255; b = v*255; break;
68  case 4: r = t*255; g = p*255; b = v*255; break;
69  case 5: r = v*255; g = p*255; b = q*255; break;
70  }
71  }
72 
73  //returns 1 if the size or format of dst has been changed otherwise 0
74  //int copyFrameToQImageRGB888(QImage &dst,base::samples::frame::frame_mode_t mode,int pixel_size, int width,int height,const char* pbuffer)
75  //{
76  int copyFrameToQImageRGB888(QImage &dst,base::samples::frame::frame_mode_t mode,int pixel_size, unsigned int width,unsigned int height, const char* pbuffer, const size_t buffer_size=0)
77  {
78  //Safty check to prevent error on empty images
79  if(width == 0 || height == 0 || buffer_size == 0)
80  {
81  //TODO could be replaced by dummy "no-Image" image
82  dst = QImage();
83  return 0;
84  }
85 
86  int ireturn = 0;
87  //check if dst has the right format
88  if((unsigned int) dst.width() != width || (unsigned int) dst.height()!= height || dst.format() != QImage::Format_RGB888)
89  {
90  dst = QImage(width,height,QImage::Format_RGB888);
91  ireturn = 1;
92  }
93  switch(mode)
94  {
95  case base::samples::frame::MODE_UNDEFINED:
96  throw std::runtime_error(" FrameQImageConverter::copyFrameToQImageRGB888: Unknown frame mode!");
97  break;
98 
99  case base::samples::frame::MODE_BAYER_RGGB:
100  case base::samples::frame::MODE_BAYER_GRBG:
101  case base::samples::frame::MODE_BAYER_BGGR:
102  case base::samples::frame::MODE_BAYER_GBRG:
103  FrameHelper::convertBayerToRGB24((const uint8_t*)pbuffer,(uint8_t*) dst.bits(), width, height ,mode);
104  break;
105 
106  case base::samples::frame::MODE_BGR:
107  // Provide the buffer as const uchar* and call bits() to make QImage
108  // do a deep copy. This is needed to ensure that QImage gets proper
109  // buffer alignment
110  dst = QImage((const uchar*)pbuffer, width, height, width*pixel_size, QImage::Format_RGB888);
111  dst = dst.rgbSwapped();
112  break;
113 
114  case base::samples::frame::MODE_RGB:
115  // Provide the buffer as const uchar* and do a deep copy
116  // This is needed to ensure that QImage gets proper
117  // buffer alignment
118  dst = QImage((const uchar*)pbuffer, width, height, width*pixel_size, QImage::Format_RGB888).copy();
119  break;
120  case base::samples::frame::MODE_PJPG:
121  {
122  FrameHelper::convertPJPGToRGB24((const uint8_t*)pbuffer,(uint8_t*) dst.bits(),buffer_size, width, height);
123  break;
124  }
125  case base::samples::frame::MODE_JPEG:
126  {
127  FrameHelper::convertJPEGToRGB24((const uint8_t*)pbuffer,(uint8_t*) dst.bits(),buffer_size, width, height);
128  break;
129  }
130  case base::samples::frame::MODE_UYVY:
131  {
132  // WARNING
133  // WARNING: this code has been changed in order to account for the
134  // WARNING: 4-byte line padding requirements of QImage
135  // WARNING: due to the lack of an UYVY image provider at the moment,
136  // WARNING: it cannot be tested
137  // WARNING
138  // WARNING: please contact rock-dev if it does not work.
139  unsigned int i,j;
140  uint8_t u,v,y1,y2,cb,cr,r1,r2,b1,b2,g1,g2;
141  for(i = 0 ;i < height ;++i){
142  uint8_t* output_line = dst.scanLine(i);
143  for(j = 0 ;j < width ;j+=2){
144  u = pbuffer[(i*width*2)+j*2+0];
145  y1 = pbuffer[(i*width*2)+j*2+1];
146  v = pbuffer[(i*width*2)+j*2+2];
147  y2 = pbuffer[(i*width*2)+j*2+3];
148 
149  cb = u;
150  cr = v;
151 
152  //no-rounding conversion method
153  r1 = (255/219)*(y1-16) + (255/112)*0.701*(cr-128);
154  g1 = (255/219)*(y1-16) + (255/112)*0.886*(0.114/0.587)*(cb-128)-(255/112)*0.701*(0.299/0.587)*(cr-128);
155  b1 = (255/219)*(y1-16) + (255/112)*0.886*(cb-128);
156 
157  r2 = (255/219)*(y2-16) + (255/112)*0.701*(cr-128);
158  g2 = (255/219)*(y2-16) + (255/112)*0.886*(0.114/0.587)*(cb-128)-(255/112)*0.701*(0.299/0.587)*(cr-128);
159  b2 = (255/219)*(y2-16) + (255/112)*0.886*(cb-128);
160 
161  output_line[j*3+0] = r1;
162  output_line[j*3+1] = g1;
163  output_line[j*3+2] = b1;
164  output_line[j*3+3] = r2;
165  output_line[j*3+4] = g2;
166  output_line[j*3+5] = b2;
167  }
168  }
169  break;
170  }
171  case base::samples::frame::MODE_GRAYSCALE:
172  {
173  switch(pixel_size)
174  {
175  case 1:
176  dst = QImage((uchar*)pbuffer, width, height, width, QImage::Format_Indexed8).convertToFormat(QImage::Format_RGB888);
177  break;
178  case 2:
179  {
180  dst = QImage(width, height, QImage::Format_RGB888);
181 
182  //The CV functions does not work in 16bit images, so using only 8bit
183  //image from below
184  const cv::Mat mat_src(height,width,CV_16U,(void*)pbuffer);
185  cv::Mat src_new(height,width,CV_8U);
186  cv::MatConstIterator_<uint16_t> it_src = mat_src.begin<uint16_t>();
187  cv::MatIterator_<uint8_t> it_dst = src_new.begin<uint8_t>();
188 
189  //Create a logarhitmic scale for visualization
190  for (; it_src != mat_src.end<uint16_t>(); ++it_src, ++it_dst)
191  {
192  uint16_t v = *it_src;
193  static double base = 2.2;
194  double v_log = log((double)v+1) / log(base);
195  (*it_dst) = v_log*(255.0/ log((double)65536) / log(base));
196  }
197 
198  cv::Mat mat_dst(height,width,CV_8UC3);
199  cv::applyColorMap(src_new,mat_dst,cv::COLORMAP_RAINBOW);
200 
201  //Manual copy the array, to make zero values black
202  cv::Vec3b black = cv::Vec3b(0, 0, 255); //*mat_dst.begin<cv::Vec3b>();
203  for (cv::Mat3b::iterator it = mat_dst.begin<cv::Vec3b>(); it != mat_dst.end<cv::Vec3b>(); ++it)
204  {
205  if (*it == black)
206  {
207  *it = cv::Vec3b(0, 0, 0);
208  }
209  }
210  dst = QImage((const uchar*)mat_dst.data, width, height, width*3, QImage::Format_RGB888).copy();
211 
212  break;
213  }
214  case 8: //we have to scale the 64 data depth --> a rgb color coding is used
215  {
216  static const float SCALE_H = 1/MAX_H;
217  static const double SCALE_S = 1/floor(std::numeric_limits<double>::max()*SCALE_H);
218 
219  int pixels = width*height;
220  double *data = (double*)pbuffer;
221  unsigned char* data2 = dst.bits();
222  int r,g,b;
223  float h,s,v;
224  v = 1; //use always a value of one for the color coding
225  //h and s are changed accordingly to the pixel value
226 
227  //for each pixel of the map
228  for(int i=0;i < pixels;++i,++data)
229  {
230  //display black if value is +- infinity
231  if(fabs(*data) == std::numeric_limits<double>::infinity())
232  {
233  r = 0;
234  g = 0;
235  b = 0;
236  }
237  else
238  {
239  //+ and - values are displayed in the same way
240  if(*data > 0)
241  {
242  h = ::fmod(*data,MAX_H)*SCALE_H;
243  s = 1-floor(*data*SCALE_H)*SCALE_S;
244  }
245  else
246  {
247  h = ::fmod(-*data,MAX_H)*SCALE_H;
248  s = 1-floor(-*data*SCALE_H)*SCALE_S;
249  }
250  hsvToRgb(h,s,v,r,g,b);
251  }
252  //copy data to dest image
253  *data2 = (unsigned char) r;
254  ++data2;
255  *data2 = (unsigned char) g;
256  ++data2;
257  *data2 = (unsigned char) b;
258  ++data2;
259  }
260  break;
261  }
262  default:
263  throw std::runtime_error("Pixel size is not supported by FrameQImageConverter!");
264  }
265  break;
266  }
267  case base::samples::frame::MODE_RGB32:
268  {
269  switch(pixel_size)
270  {
271  case 8:
272  dst = QImage((uchar*)pbuffer, width, height, width, QImage::Format_RGB32).convertToFormat(QImage::Format_RGB888);
273  }
274  break;
275  }
276 
277  case base::samples::frame::MODE_PNG:
278  {
279  char *buffer = const_cast<char*>(pbuffer); // workaround for Mat non const constructor
280  const cv::Mat input(1,buffer_size,CV_8UC1,buffer); // ensure buffer will not be modified !!!
281  cv::Mat img = cv::imdecode(input,CV_LOAD_IMAGE_COLOR);
282  dst = QImage((const uchar*)img.data,img.cols,img.rows,QImage::Format_RGB888);
283  dst = dst.rgbSwapped();
284  break;
285  }
286 
287  default:
288  throw std::runtime_error(" FrameQImageConverter::copyFrameToQImageRGB888: Can not convert frame to RGB888!");
289  }
290  return ireturn;
291  };
292 
293  int copyFrameToQImageRGB888(QImage &dst,const base::samples::frame::Frame &frame)
294  {
295  return copyFrameToQImageRGB888(dst,
296  frame.frame_mode,
297  frame.pixel_size,
298  frame.getWidth(),
299  frame.getHeight(),
300  (const char*)frame.getImageConstPtr(),
301  frame.image.size());
302  };
303 
304  int copyFrameToQImageRGB888(QImage &dst,const QString &mode,int pixel_size, int width,int height, const char* pbuffer, const size_t size=0)
305  {
306  base::samples::frame::frame_mode_t _mode = base::samples::frame::Frame::toFrameMode(mode.toStdString());
307  return copyFrameToQImageRGB888(dst,_mode,pixel_size,width,height,pbuffer,size);
308  };
309 
310  private:
311  QImage image_buffer;
312  };
313  };
314 
315 #endif /* FRAMEQIMAGECONVERTER_H_ */
int copyFrameToQImageRGB888(QImage &dst, const base::samples::frame::Frame &frame)
Definition: FrameQImageConverter.h:293
virtual ~FrameQImageConverter()
Definition: FrameQImageConverter.h:43
Definition: FrameQImageConverter.h:38
void hsvToRgb(float h, float s, float v, int &r, int &g, int &b)
Definition: FrameQImageConverter.h:56
static void convertPJPGToRGB24(const base::samples::frame::Frame &src, base::samples::frame::Frame &dst)
Definition: FrameHelper.cpp:1058
int copyFrameToQImageRGB888(QImage &dst, base::samples::frame::frame_mode_t mode, int pixel_size, unsigned int width, unsigned int height, const char *pbuffer, const size_t buffer_size=0)
Definition: FrameQImageConverter.h:76
int copyFrameToQImageRGB888(QImage &dst, const QString &mode, int pixel_size, int width, int height, const char *pbuffer, const size_t size=0)
Definition: FrameQImageConverter.h:304
static void convertBayerToRGB24(const base::samples::frame::Frame &src, base::samples::frame::Frame &dst)
Definition: FrameHelper.cpp:865
FrameQImageConverter()
Definition: FrameQImageConverter.h:41
static void convertJPEGToRGB24(uint8_t const *src, uint8_t *dst, size_t const src_size, int const width, int const height)
Definition: FrameHelper.cpp:1102
Definition: Calibration.h:10