Visual Servoing Platform  version 3.6.1 under development (2024-04-16)
testColorConversion.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Test image conversion.
33  *
34 *****************************************************************************/
35 
42 #include <visp3/core/vpConfig.h>
43 
44 #if defined(VISP_HAVE_CATCH2)
45 #define CATCH_CONFIG_RUNNER
46 #include "common.hpp"
47 #include <catch.hpp>
48 #include <visp3/core/vpImageConvert.h>
49 #include <visp3/core/vpIoTools.h>
50 #include <visp3/io/vpImageIo.h>
51 
52 static const double maxMeanPixelError = 1.5; // conversion to gray produce an error = 1.0
53 static const unsigned int width = 223, height = 151;
54 
55 TEST_CASE("Gray to RGBa conversion", "[image_conversion]")
56 {
57  SECTION("Image 1x16 (SSE41 aligned=true)")
58  {
59  unsigned int h = 1, w = 16;
60  vpImage<unsigned char> gray(h, w);
61  common_tools::fill(gray);
62 
63  vpImage<vpRGBa> rgba_ref(h, w);
64  common_tools::grayToRGBaRef(gray.bitmap, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), gray.getSize());
65 
66  vpImage<vpRGBa> rgba;
67  vpImageConvert::convert(gray, rgba);
68  CHECK((rgba == rgba_ref));
69  }
70  SECTION("Image 1x17 (SSE41 aligned=false)")
71  {
72  unsigned int h = 1, w = 17;
73  vpImage<unsigned char> gray(h, w);
74  common_tools::fill(gray);
75 
76  vpImage<vpRGBa> rgba_ref(h, w);
77  common_tools::grayToRGBaRef(gray.bitmap, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), gray.getSize());
78 
79  vpImage<vpRGBa> rgba;
80  vpImageConvert::convert(gray, rgba);
81  CHECK((rgba == rgba_ref));
82  }
83  SECTION("Image 1x32 (AVX2 aligned=true)")
84  {
85  unsigned int h = 1, w = 32;
86  vpImage<unsigned char> gray(h, w);
87  common_tools::fill(gray);
88 
89  vpImage<vpRGBa> rgba_ref(h, w);
90  common_tools::grayToRGBaRef(gray.bitmap, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), gray.getSize());
91 
92  vpImage<vpRGBa> rgba;
93  vpImageConvert::convert(gray, rgba);
94  CHECK((rgba == rgba_ref));
95  }
96  SECTION("Image 1x33 (AVX2 aligned=false)")
97  {
98  unsigned int h = 1, w = 33;
99  vpImage<unsigned char> gray(h, w);
100  common_tools::fill(gray);
101 
102  vpImage<vpRGBa> rgba_ref(h, w);
103  common_tools::grayToRGBaRef(gray.bitmap, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), gray.getSize());
104 
105  vpImage<vpRGBa> rgba;
106  vpImageConvert::convert(gray, rgba);
107  CHECK((rgba == rgba_ref));
108  }
109  SECTION("Image 4x64 (general aligned = true")
110  {
111  unsigned int h = 4, w = 64;
112  vpImage<unsigned char> gray(h, w);
113  common_tools::fill(gray);
114 
115  vpImage<vpRGBa> rgba_ref(h, w);
116  common_tools::grayToRGBaRef(gray.bitmap, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), gray.getSize());
117 
118  vpImage<vpRGBa> rgba;
119  vpImageConvert::convert(gray, rgba);
120  CHECK((rgba == rgba_ref));
121  }
122  SECTION("Image 5x65 (general aligned = false")
123  {
124  unsigned int h = 5, w = 65;
125  vpImage<unsigned char> gray(h, w);
126  common_tools::fill(gray);
127 
128  vpImage<vpRGBa> rgba_ref(h, w);
129  common_tools::grayToRGBaRef(gray.bitmap, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), gray.getSize());
130 
131  vpImage<vpRGBa> rgba;
132  vpImageConvert::convert(gray, rgba);
133  CHECK((rgba == rgba_ref));
134  }
135 }
136 
137 TEST_CASE("RGBa to Gray conversion", "[image_conversion]")
138 {
139  SECTION("Image 1x16 (SSE41 aligned=true)")
140  {
141  unsigned int h = 1, w = 16;
142  vpImage<vpRGBa> rgba(h, w);
143  common_tools::fill(rgba);
144 
145  vpImage<unsigned char> gray_ref(h, w);
146  common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
147 
148  vpImage<unsigned char> gray(h, w);
149  vpImageConvert::convert(rgba, gray);
150  double error = 0;
151  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
152  std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
153  }
154  SECTION("Image 1x17 (SSE41 aligned=false)")
155  {
156  unsigned int h = 1, w = 17;
157  vpImage<vpRGBa> rgba(h, w);
158  common_tools::fill(rgba);
159 
160  vpImage<unsigned char> gray_ref(h, w);
161  common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
162 
163  vpImage<unsigned char> gray(h, w);
164  vpImageConvert::convert(rgba, gray);
165  double error = 0;
166  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
167  std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
168  }
169  SECTION("Image 1x32 (AVX2 aligned=true)")
170  {
171  unsigned int h = 1, w = 32;
172  vpImage<vpRGBa> rgba(h, w);
173  common_tools::fill(rgba);
174 
175  vpImage<unsigned char> gray_ref(h, w);
176  common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
177 
178  vpImage<unsigned char> gray(h, w);
179  vpImageConvert::convert(rgba, gray);
180  double error = 0;
181  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
182  std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
183  }
184  SECTION("Image 1x33 (AVX2 aligned=false)")
185  {
186  unsigned int h = 1, w = 33;
187  vpImage<vpRGBa> rgba(h, w);
188  common_tools::fill(rgba);
189 
190  vpImage<unsigned char> gray_ref(h, w);
191  common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
192 
193  vpImage<unsigned char> gray(h, w);
194  vpImageConvert::convert(rgba, gray);
195  double error = 0;
196  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
197  std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
198  }
199  SECTION("Image 4x64 (general aligned = true")
200  {
201  unsigned int h = 4, w = 64;
202  vpImage<vpRGBa> rgba(h, w);
203  common_tools::fill(rgba);
204 
205  vpImage<unsigned char> gray_ref(h, w);
206  common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
207 
208  vpImage<unsigned char> gray(h, w);
209  vpImageConvert::convert(rgba, gray);
210  double error = 0;
211  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
212  std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
213  }
214  SECTION("Image 5x65 (general aligned = false")
215  {
216  unsigned int h = 5, w = 65;
217  vpImage<vpRGBa> rgba(h, w);
218  common_tools::fill(rgba);
219 
220  vpImage<unsigned char> gray_ref(h, w);
221  common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
222 
223  vpImage<unsigned char> gray(h, w);
224  vpImageConvert::convert(rgba, gray);
225  double error = 0;
226  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
227  std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
228  }
229 }
230 
231 TEST_CASE("RGB to Gray conversion", "[image_conversion]")
232 {
233  SECTION("Image 1x16 (SSE41 aligned=true)")
234  {
235  unsigned int h = 1, w = 16;
236  std::vector<unsigned char> rgb(h * w * 3);
237  common_tools::fill(rgb);
238 
239  vpImage<unsigned char> gray_ref(h, w);
240  common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
241 
242  vpImage<unsigned char> gray(h, w);
243  vpImageConvert::RGBToGrey(rgb.data(), gray.bitmap, w, h, false);
244  double error = 0;
245  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
246  std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
247 
248  vpImage<unsigned char> gray2(h, w);
249  vpImageConvert::RGBToGrey(rgb.data(), gray2.bitmap, w * h);
250  CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
251  std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
252  }
253  SECTION("Image 1x17 (SSE41 aligned=false)")
254  {
255  unsigned int h = 1, w = 17;
256  std::vector<unsigned char> rgb(h * w * 3);
257  common_tools::fill(rgb);
258 
259  vpImage<unsigned char> gray_ref(h, w);
260  common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
261 
262  vpImage<unsigned char> gray(h, w);
263  vpImageConvert::RGBToGrey(rgb.data(), gray.bitmap, w, h, false);
264  double error = 0;
265  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
266  std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
267 
268  vpImage<unsigned char> gray2(h, w);
269  vpImageConvert::RGBToGrey(rgb.data(), gray2.bitmap, w * h);
270  CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
271  std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
272  }
273  SECTION("Image 1x32 (AVX2 aligned=true)")
274  {
275  unsigned int h = 1, w = 32;
276  std::vector<unsigned char> rgb(h * w * 3);
277  common_tools::fill(rgb);
278 
279  vpImage<unsigned char> gray_ref(h, w);
280  common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
281 
282  vpImage<unsigned char> gray(h, w);
283  vpImageConvert::RGBToGrey(rgb.data(), gray.bitmap, w, h, false);
284  double error = 0;
285  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
286  std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
287  vpImage<unsigned char> gray2(h, w);
288  vpImageConvert::RGBToGrey(rgb.data(), gray2.bitmap, w * h);
289  CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
290  std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
291  }
292  SECTION("Image 1x33 (AVX2 aligned=false)")
293  {
294  unsigned int h = 1, w = 33;
295  std::vector<unsigned char> rgb(h * w * 3);
296  common_tools::fill(rgb);
297 
298  vpImage<unsigned char> gray_ref(h, w);
299  common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
300 
301  vpImage<unsigned char> gray(h, w);
302  vpImageConvert::RGBToGrey(rgb.data(), gray.bitmap, w, h, false);
303  double error = 0;
304  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
305  std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
306 
307  vpImage<unsigned char> gray2(h, w);
308  vpImageConvert::RGBToGrey(rgb.data(), gray2.bitmap, w * h);
309  CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
310  std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
311  }
312  SECTION("Image 4x64 (general aligned = true")
313  {
314  unsigned int h = 4, w = 64;
315  std::vector<unsigned char> rgb(h * w * 3);
316  common_tools::fill(rgb);
317 
318  vpImage<unsigned char> gray_ref(h, w);
319  common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
320 
321  vpImage<unsigned char> gray(h, w);
322  vpImageConvert::RGBToGrey(rgb.data(), gray.bitmap, w, h, false);
323  double error = 0;
324  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
325  std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
326 
327  vpImage<unsigned char> gray2(h, w);
328  vpImageConvert::RGBToGrey(rgb.data(), gray2.bitmap, w * h);
329  CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
330  std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
331  }
332  SECTION("Image 5x65 (general aligned = false")
333  {
334  unsigned int h = 5, w = 65;
335  std::vector<unsigned char> rgb(h * w * 3);
336  common_tools::fill(rgb);
337 
338  vpImage<unsigned char> gray_ref(h, w);
339  common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
340 
341  vpImage<unsigned char> gray(h, w);
342  vpImageConvert::RGBToGrey(rgb.data(), gray.bitmap, w, h, false);
343  double error = 0;
344  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
345  std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
346 
347  vpImage<unsigned char> gray2(h, w);
348  vpImageConvert::RGBToGrey(rgb.data(), gray2.bitmap, w * h);
349  CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
350  std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
351  }
352 }
353 
354 TEST_CASE("RGB <==> RGBa conversion", "[image_conversion]")
355 {
356  SECTION("Image 1x16 (SSE41 aligned=true)")
357  {
358  unsigned int h = 1, w = 16;
359  vpImage<vpRGBa> rgba_ref(h, w);
360  common_tools::fill(rgba_ref);
361 
362  std::vector<unsigned char> rgb(h * w * 3);
363  vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(rgba_ref.bitmap), rgb.data(), rgba_ref.getSize());
364 
365  vpImage<vpRGBa> rgba(h, w);
366  vpImageConvert::RGBToRGBa(rgb.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba_ref.getSize());
367 
368  CHECK((rgba == rgba_ref));
369  }
370  SECTION("Image 1x17 (SSE41 aligned=false)")
371  {
372  unsigned int h = 1, w = 17;
373  vpImage<vpRGBa> rgba_ref(h, w);
374  common_tools::fill(rgba_ref);
375 
376  std::vector<unsigned char> rgb(h * w * 3);
377  vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(rgba_ref.bitmap), rgb.data(), rgba_ref.getSize());
378 
379  vpImage<vpRGBa> rgba(h, w);
380  vpImageConvert::RGBToRGBa(rgb.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba_ref.getSize());
381 
382  CHECK((rgba == rgba_ref));
383  }
384  SECTION("Image 1x32 (AVX2 aligned=true)")
385  {
386  unsigned int h = 1, w = 32;
387  vpImage<vpRGBa> rgba_ref(h, w);
388  common_tools::fill(rgba_ref);
389 
390  std::vector<unsigned char> rgb(h * w * 3);
391  vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(rgba_ref.bitmap), rgb.data(), rgba_ref.getSize());
392 
393  vpImage<vpRGBa> rgba(h, w);
394  vpImageConvert::RGBToRGBa(rgb.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba_ref.getSize());
395 
396  CHECK((rgba == rgba_ref));
397  }
398  SECTION("Image 1x33 (AVX2 aligned=false)")
399  {
400  unsigned int h = 1, w = 33;
401  vpImage<vpRGBa> rgba_ref(h, w);
402  common_tools::fill(rgba_ref);
403 
404  std::vector<unsigned char> rgb(h * w * 3);
405  vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(rgba_ref.bitmap), rgb.data(), rgba_ref.getSize());
406 
407  vpImage<vpRGBa> rgba(h, w);
408  vpImageConvert::RGBToRGBa(rgb.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba_ref.getSize());
409 
410  CHECK((rgba == rgba_ref));
411  }
412  SECTION("Image 4x64 (general aligned = true")
413  {
414  unsigned int h = 4, w = 64;
415  vpImage<vpRGBa> rgba_ref(h, w);
416  common_tools::fill(rgba_ref);
417 
418  std::vector<unsigned char> rgb(h * w * 3);
419  vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(rgba_ref.bitmap), rgb.data(), rgba_ref.getSize());
420 
421  vpImage<vpRGBa> rgba(h, w);
422  vpImageConvert::RGBToRGBa(rgb.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba_ref.getSize());
423 
424  CHECK((rgba == rgba_ref));
425  }
426  SECTION("Image 5x65 (general aligned = false")
427  {
428  unsigned int h = 5, w = 65;
429  vpImage<vpRGBa> rgba_ref(h, w);
430  common_tools::fill(rgba_ref);
431 
432  std::vector<unsigned char> rgb(h * w * 3);
433  vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(rgba_ref.bitmap), rgb.data(), rgba_ref.getSize());
434 
435  vpImage<vpRGBa> rgba(h, w);
436  vpImageConvert::RGBToRGBa(rgb.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba_ref.getSize());
437 
438  CHECK((rgba == rgba_ref));
439  }
440 }
441 
442 TEST_CASE("BGR to Gray conversion", "[image_conversion]")
443 {
444  SECTION("Image 1x16 (SSE41 aligned=true)")
445  {
446  unsigned int h = 1, w = 16;
447  vpImage<vpRGBa> rgba_ref(h, w);
448  common_tools::fill(rgba_ref);
449 
450  vpImage<unsigned char> gray_ref;
451  vpImageConvert::convert(rgba_ref, gray_ref);
452 
453  std::vector<unsigned char> bgr;
454  common_tools::RGBaToBGR(rgba_ref, bgr);
455 
456  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
457  vpImageConvert::BGRToGrey(bgr.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
458 
459  double error = 0;
460  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
461  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
462  }
463  SECTION("Image 1x17 (SSE41 aligned=false)")
464  {
465  unsigned int h = 1, w = 17;
466  vpImage<vpRGBa> rgba_ref(h, w);
467  common_tools::fill(rgba_ref);
468 
469  vpImage<unsigned char> gray_ref;
470  vpImageConvert::convert(rgba_ref, gray_ref);
471 
472  std::vector<unsigned char> bgr;
473  common_tools::RGBaToBGR(rgba_ref, bgr);
474 
475  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
476  vpImageConvert::BGRToGrey(bgr.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
477 
478  double error = 0;
479  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
480  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
481  }
482  SECTION("Image 1x32 (AVX2 aligned=true)")
483  {
484  unsigned int h = 1, w = 32;
485  vpImage<vpRGBa> rgba_ref(h, w);
486  common_tools::fill(rgba_ref);
487 
488  vpImage<unsigned char> gray_ref;
489  vpImageConvert::convert(rgba_ref, gray_ref);
490 
491  std::vector<unsigned char> bgr;
492  common_tools::RGBaToBGR(rgba_ref, bgr);
493 
494  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
495  vpImageConvert::BGRToGrey(bgr.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
496 
497  double error = 0;
498  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
499  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
500  }
501  SECTION("Image 1x33 (AVX2 aligned=false)")
502  {
503  unsigned int h = 1, w = 33;
504  vpImage<vpRGBa> rgba_ref(h, w);
505  common_tools::fill(rgba_ref);
506 
507  vpImage<unsigned char> gray_ref;
508  vpImageConvert::convert(rgba_ref, gray_ref);
509 
510  std::vector<unsigned char> bgr;
511  common_tools::RGBaToBGR(rgba_ref, bgr);
512 
513  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
514  vpImageConvert::BGRToGrey(bgr.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
515 
516  double error = 0;
517  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
518  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
519  }
520  SECTION("Image 4x64 (general aligned = true")
521  {
522  unsigned int h = 4, w = 64;
523  vpImage<vpRGBa> rgba_ref(h, w);
524  common_tools::fill(rgba_ref);
525 
526  vpImage<unsigned char> gray_ref;
527  vpImageConvert::convert(rgba_ref, gray_ref);
528 
529  std::vector<unsigned char> bgr;
530  common_tools::RGBaToBGR(rgba_ref, bgr);
531 
532  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
533  vpImageConvert::BGRToGrey(bgr.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
534 
535  double error = 0;
536  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
537  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
538  }
539  SECTION("Image 5x65 (general aligned = false")
540  {
541  unsigned int h = 5, w = 65;
542  vpImage<vpRGBa> rgba_ref(h, w);
543  common_tools::fill(rgba_ref);
544 
545  vpImage<unsigned char> gray_ref;
546  vpImageConvert::convert(rgba_ref, gray_ref);
547 
548  std::vector<unsigned char> bgr;
549  common_tools::RGBaToBGR(rgba_ref, bgr);
550 
551  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
552  vpImageConvert::BGRToGrey(bgr.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
553 
554  double error = 0;
555  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
556  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
557  }
558 }
559 
560 TEST_CASE("BGRa to Gray conversion", "[image_conversion]")
561 {
562  SECTION("Image 1x16 (SSE41 aligned=true)")
563  {
564  unsigned int h = 1, w = 16;
565  vpImage<vpRGBa> rgba_ref(h, w);
566  common_tools::fill(rgba_ref);
567 
568  vpImage<unsigned char> gray_ref;
569  vpImageConvert::convert(rgba_ref, gray_ref);
570 
571  std::vector<unsigned char> bgra;
572  common_tools::RGBaToBGRa(rgba_ref, bgra);
573 
574  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
575  vpImageConvert::BGRaToGrey(bgra.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
576 
577  double error = 0;
578  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
579  std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
580  }
581  SECTION("Image 1x17 (SSE41 aligned=false)")
582  {
583  unsigned int h = 1, w = 17;
584  vpImage<vpRGBa> rgba_ref(h, w);
585  common_tools::fill(rgba_ref);
586 
587  vpImage<unsigned char> gray_ref;
588  vpImageConvert::convert(rgba_ref, gray_ref);
589 
590  std::vector<unsigned char> bgra;
591  common_tools::RGBaToBGRa(rgba_ref, bgra);
592 
593  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
594  vpImageConvert::BGRaToGrey(bgra.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
595 
596  double error = 0;
597  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
598  std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
599  }
600  SECTION("Image 1x32 (AVX2 aligned=true)")
601  {
602  unsigned int h = 1, w = 32;
603  vpImage<vpRGBa> rgba_ref(h, w);
604  common_tools::fill(rgba_ref);
605 
606  vpImage<unsigned char> gray_ref;
607  vpImageConvert::convert(rgba_ref, gray_ref);
608 
609  std::vector<unsigned char> bgra;
610  common_tools::RGBaToBGRa(rgba_ref, bgra);
611 
612  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
613  vpImageConvert::BGRaToGrey(bgra.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
614 
615  double error = 0;
616  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
617  std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
618  }
619  SECTION("Image 1x33 (AVX2 aligned=false)")
620  {
621  unsigned int h = 1, w = 33;
622  vpImage<vpRGBa> rgba_ref(h, w);
623  common_tools::fill(rgba_ref);
624 
625  vpImage<unsigned char> gray_ref;
626  vpImageConvert::convert(rgba_ref, gray_ref);
627 
628  std::vector<unsigned char> bgra;
629  common_tools::RGBaToBGRa(rgba_ref, bgra);
630 
631  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
632  vpImageConvert::BGRaToGrey(bgra.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
633 
634  double error = 0;
635  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
636  std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
637  }
638  SECTION("Image 4x64 (general aligned = true")
639  {
640  unsigned int h = 4, w = 64;
641  vpImage<vpRGBa> rgba_ref(h, w);
642  common_tools::fill(rgba_ref);
643 
644  vpImage<unsigned char> gray_ref;
645  vpImageConvert::convert(rgba_ref, gray_ref);
646 
647  std::vector<unsigned char> bgra;
648  common_tools::RGBaToBGRa(rgba_ref, bgra);
649 
650  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
651  vpImageConvert::BGRaToGrey(bgra.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
652 
653  double error = 0;
654  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
655  std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
656  }
657  SECTION("Image 5x65 (general aligned = false")
658  {
659  unsigned int h = 5, w = 65;
660  vpImage<vpRGBa> rgba_ref(h, w);
661  common_tools::fill(rgba_ref);
662 
663  vpImage<unsigned char> gray_ref;
664  vpImageConvert::convert(rgba_ref, gray_ref);
665 
666  std::vector<unsigned char> bgra;
667  common_tools::RGBaToBGRa(rgba_ref, bgra);
668 
669  vpImage<unsigned char> gray(gray_ref.getHeight(), gray_ref.getWidth());
670  vpImageConvert::BGRaToGrey(bgra.data(), gray.bitmap, gray.getWidth(), gray.getHeight());
671 
672  double error = 0;
673  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
674  std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
675  }
676 }
677 
678 TEST_CASE("BGRa to RGBa conversion", "[image_conversion]")
679 {
680  SECTION("Image 1x16 (SSE41 aligned=true)")
681  {
682  unsigned int h = 1, w = 16;
683  vpImage<vpRGBa> rgba_ref(h, w);
684  common_tools::fill(rgba_ref);
685 
686  std::vector<unsigned char> bgra_ref;
687  common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
688 
689  vpImage<vpRGBa> rgba(rgba_ref.getHeight(), rgba_ref.getWidth());
690  vpImageConvert::BGRaToRGBa(bgra_ref.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba.getWidth(),
691  rgba.getHeight());
692  double error = 0;
693  CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
694  std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
695  }
696  SECTION("Image 1x17 (SSE41 aligned=false)")
697  {
698  unsigned int h = 1, w = 17;
699  vpImage<vpRGBa> rgba_ref(h, w);
700  common_tools::fill(rgba_ref);
701 
702  std::vector<unsigned char> bgra_ref;
703  common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
704 
705  vpImage<vpRGBa> rgba(rgba_ref.getHeight(), rgba_ref.getWidth());
706  vpImageConvert::BGRaToRGBa(bgra_ref.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba.getWidth(),
707  rgba.getHeight());
708  double error = 0;
709  CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
710  std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
711  }
712  SECTION("Image 1x32 (AVX2 aligned=true)")
713  {
714  unsigned int h = 1, w = 32;
715  vpImage<vpRGBa> rgba_ref(h, w);
716  common_tools::fill(rgba_ref);
717 
718  std::vector<unsigned char> bgra_ref;
719  common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
720 
721  vpImage<vpRGBa> rgba(rgba_ref.getHeight(), rgba_ref.getWidth());
722  vpImageConvert::BGRaToRGBa(bgra_ref.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba.getWidth(),
723  rgba.getHeight());
724  double error = 0;
725  CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
726  std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
727  }
728  SECTION("Image 1x33 (AVX2 aligned=false)")
729  {
730  unsigned int h = 1, w = 33;
731  vpImage<vpRGBa> rgba_ref(h, w);
732  common_tools::fill(rgba_ref);
733 
734  std::vector<unsigned char> bgra_ref;
735  common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
736 
737  vpImage<vpRGBa> rgba(rgba_ref.getHeight(), rgba_ref.getWidth());
738  vpImageConvert::BGRaToRGBa(bgra_ref.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba.getWidth(),
739  rgba.getHeight());
740  double error = 0;
741  CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
742  std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
743  }
744  SECTION("Image 4x64 (general aligned = true")
745  {
746  unsigned int h = 4, w = 64;
747  vpImage<vpRGBa> rgba_ref(h, w);
748  common_tools::fill(rgba_ref);
749 
750  std::vector<unsigned char> bgra_ref;
751  common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
752 
753  vpImage<vpRGBa> rgba(rgba_ref.getHeight(), rgba_ref.getWidth());
754  vpImageConvert::BGRaToRGBa(bgra_ref.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba.getWidth(),
755  rgba.getHeight());
756  double error = 0;
757  CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
758  std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
759  }
760  SECTION("Image 5x65 (general aligned = false")
761  {
762  unsigned int h = 5, w = 65;
763  vpImage<vpRGBa> rgba_ref(h, w);
764  common_tools::fill(rgba_ref);
765 
766  std::vector<unsigned char> bgra_ref;
767  common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
768 
769  vpImage<vpRGBa> rgba(rgba_ref.getHeight(), rgba_ref.getWidth());
770  vpImageConvert::BGRaToRGBa(bgra_ref.data(), reinterpret_cast<unsigned char *>(rgba.bitmap), rgba.getWidth(),
771  rgba.getHeight());
772  double error = 0;
773  CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
774  std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
775  }
776 }
777 
778 TEST_CASE("Split <==> Merge conversion", "[image_conversion]")
779 {
780  vpImage<vpRGBa> rgba_ref(height, width);
781  common_tools::fill(rgba_ref);
782 
783  vpImage<unsigned char> R, G, B, A;
784  vpImageConvert::split(rgba_ref, &R, &G, &B, &A);
785 
786  vpImage<vpRGBa> rgba;
787  vpImageConvert::merge(&R, &G, &B, &A, rgba);
788 
789  CHECK((rgba == rgba_ref));
790 }
791 
792 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
793 TEST_CASE("OpenCV Mat <==> vpImage conversion", "[image_conversion]")
794 {
795  SECTION("CV_8UC3 to vpRGBa")
796  {
797  cv::Mat img(height, width, CV_8UC3);
798  common_tools::fill(img);
799 
800  vpImage<vpRGBa> rgba_ref(height, width);
801  common_tools::BGRToRGBaRef(img.data, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), img.cols, img.rows, false);
802 
803  vpImage<vpRGBa> rgba;
804  vpImageConvert::convert(img, rgba);
805  CHECK((rgba_ref == rgba));
806  }
807 
808  SECTION("CV_8UC1 to vpRGBa")
809  {
810  cv::Mat img(height, width, CV_8UC1);
811  common_tools::fill(img);
812 
813  vpImage<vpRGBa> rgba_ref(height, width);
814  common_tools::grayToRGBaRef(img.data, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), height * width);
815 
816  vpImage<vpRGBa> rgba;
817  vpImageConvert::convert(img, rgba);
818  CHECK((rgba_ref == rgba));
819  }
820 
821  SECTION("CV_8UC3 to unsigned char")
822  {
823  cv::Mat img(height, width, CV_8UC3);
824  common_tools::fill(img);
825 
826  vpImage<unsigned char> gray_ref(height, width);
827  common_tools::BGRToGrayRef(img.data, gray_ref.bitmap, img.cols, img.rows, false);
828 
830  vpImageConvert::convert(img, gray);
831  double error = 0;
832  CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
833  std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
834  }
835 
836  SECTION("CV_8UC1 to unsigned char")
837  {
838  cv::Mat img(height, width, CV_8UC1);
839  common_tools::fill(img);
840 
842  vpImageConvert::convert(img, gray);
843 
844  REQUIRE(gray.getHeight() == height);
845  REQUIRE(gray.getWidth() == width);
846 
847  for (int i = 0; i < img.rows; i++) {
848  for (int j = 0; j < img.cols; j++) {
849  REQUIRE(img.at<uchar>(i, j) == gray[i][j]);
850  }
851  }
852  }
853 
854  SECTION("CV_16UC1 to uint16_t")
855  {
856  // Test when data in cv::Mat is continuous
857  unsigned int w = 3, h = 3;
858  cv::Mat img = (cv::Mat_<uint16_t>(h, w) << 65, 650, 6500, 65000, 60000, 6000, 600, 60, 6);
859  vpImage<uint16_t> gray16;
860  vpImageConvert::convert(img, gray16);
861 
862  REQUIRE(gray16.getHeight() == h);
863  REQUIRE(gray16.getWidth() == w);
864 
865  for (int i = 0; i < img.rows; i++) {
866  for (int j = 0; j < img.cols; j++) {
867  REQUIRE(img.at<uint16_t>(i, j) == gray16[i][j]);
868  }
869  }
870 
871  // Test when data in cv::Mat is discontinuous
872  cv::Mat img_col1 = img.col(1);
873  vpImage<uint16_t> gray16_col1;
874  vpImageConvert::convert(img_col1, gray16_col1);
875 
876  REQUIRE(gray16_col1.getHeight() == h);
877  REQUIRE(gray16_col1.getWidth() == 1);
878 
879  for (int i = 0; i < img_col1.rows; i++) {
880  for (int j = 0; j < img_col1.cols; j++) {
881  REQUIRE(img_col1.at<uint16_t>(i, j) == gray16_col1[i][j]);
882  }
883  }
884  }
885 }
886 #endif
887 
888 #if (VISP_HAVE_DATASET_VERSION >= 0x030500)
889 void col2im(const std::vector<uint8_t> &buffer, vpImage<uint8_t> &I_Bayer_8U)
890 {
891  for (unsigned int i = 0; i < I_Bayer_8U.getHeight(); i++) {
892  for (unsigned int j = 0; j < I_Bayer_8U.getWidth(); j++) {
893  I_Bayer_8U[i][j] = buffer[j * I_Bayer_8U.getHeight() + i];
894  }
895  }
896 }
897 
898 static void col2im(const std::vector<uint16_t> &buffer, vpImage<uint16_t> &I_Bayer_16U)
899 {
900  for (unsigned int i = 0; i < I_Bayer_16U.getHeight(); i++) {
901  for (unsigned int j = 0; j < I_Bayer_16U.getWidth(); j++) {
902  I_Bayer_16U[i][j] = buffer[j * I_Bayer_16U.getHeight() + i];
903  }
904  }
905 }
906 
907 static void convertTo(const vpImage<uint16_t> &I_RGBA_16U, vpImage<vpRGBa> &I_RGBA_8U, int divisor = 1 << (12 - 8))
908 {
909  for (unsigned int i = 0; i < I_RGBA_8U.getHeight(); i++) {
910  for (unsigned int j = 0; j < I_RGBA_8U.getWidth(); j++) {
911  I_RGBA_8U[i][j] = vpRGBa(
912  vpMath::saturate<unsigned char>(I_RGBA_16U[0][(i * I_RGBA_8U.getWidth() + j) * 4 + 0] / (float)divisor),
913  vpMath::saturate<unsigned char>(I_RGBA_16U[0][(i * I_RGBA_8U.getWidth() + j) * 4 + 1] / (float)divisor),
914  vpMath::saturate<unsigned char>(I_RGBA_16U[0][(i * I_RGBA_8U.getWidth() + j) * 4 + 2] / (float)divisor));
915  }
916  }
917 }
918 
919 static double computePSNR(const vpImage<vpRGBa> &I_RGBA_8U, const vpImage<vpRGBa> &I_RGBA_8U_ref)
920 {
921  double mse = 0;
922  for (unsigned int i = 0; i < I_RGBA_8U.getHeight(); i++) {
923  for (unsigned int j = 0; j < I_RGBA_8U.getWidth(); j++) {
924  vpColVector err = I_RGBA_8U[i][j] - I_RGBA_8U_ref[i][j];
925  mse += vpMath::sqr(err[0]) + vpMath::sqr(err[1]) + vpMath::sqr(err[2]);
926  }
927  }
928  mse /= I_RGBA_8U.getHeight() * I_RGBA_8U.getWidth() * 3;
929 
930  return 10 * std::log10(255 * 255 / mse);
931 }
932 
933 static bool readBinaryFile(const std::string &filename, std::vector<uint16_t> &buffer)
934 {
935  std::FILE *f = std::fopen(filename.c_str(), "rb");
936  CHECK(f != nullptr);
937  if (f == nullptr) {
938  return false;
939  }
940 
941  size_t sread = std::fread(&buffer[0], sizeof buffer[0], buffer.size(), f);
942  REQUIRE(sread == buffer.size());
943 
944 #ifdef VISP_BIG_ENDIAN
945  std::vector<uint16_t> tmp = buffer;
946  for (size_t i = 0; i < tmp.size(); i++) {
947  buffer[i] = vpEndian::swap16bits(tmp[i]);
948  }
949 #endif
950  std::fclose(f);
951  return true;
952 }
953 
954 static bool readBinaryFile(const std::string &filename, std::vector<uint8_t> &buffer)
955 {
956  std::FILE *f = std::fopen(filename.c_str(), "rb");
957  CHECK(f != nullptr);
958  if (f == nullptr) {
959  return false;
960  }
961 
962  size_t sread = std::fread(&buffer[0], sizeof buffer[0], buffer.size(), f);
963  REQUIRE(sread == buffer.size());
964 
965  std::fclose(f);
966  return true;
967 }
968 
969 TEST_CASE("Bayer conversion", "[image_conversion]")
970 {
971  // Load original Klimt image
972  vpImage<vpRGBa> I_RGBA_8U_ref;
973  vpImageIo::read(I_RGBA_8U_ref, vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Klimt/Klimt.ppm"));
974 
975  vpImage<vpRGBa> I_RGBA_8U(I_RGBA_8U_ref.getHeight(), I_RGBA_8U_ref.getWidth());
976  int height = I_RGBA_8U_ref.getHeight(), width = I_RGBA_8U_ref.getWidth();
977  const double min_PSNR_bilinear = 21, min_PSNR_Malvar = 24;
978 
979  SECTION("16-bit")
980  {
981  std::vector<uint16_t> buffer(height * width);
982  vpImage<uint16_t> I_Bayer_16U(height, width);
983  vpImage<uint16_t> I_RGBA_16U(1, I_Bayer_16U.getHeight() * I_Bayer_16U.getWidth() * 4);
984 
985  SECTION("BGGR")
986  {
987  const std::string filename =
988  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_BGGR_12bits.raw");
989  if (readBinaryFile(filename, buffer)) {
990  col2im(buffer, I_Bayer_16U);
991 
992  SECTION("Bilinear")
993  {
994  vpImageConvert::demosaicBGGRToRGBaBilinear(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
995  I_Bayer_16U.getHeight());
996 
997  convertTo(I_RGBA_16U, I_RGBA_8U);
998  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
999  std::cout << "16-bit - BGGR - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1000  CHECK(PSNR >= min_PSNR_bilinear);
1001  }
1002 
1003  SECTION("Malvar")
1004  {
1005  vpImageConvert::demosaicBGGRToRGBaMalvar(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1006  I_Bayer_16U.getHeight());
1007 
1008  convertTo(I_RGBA_16U, I_RGBA_8U);
1009  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1010  std::cout << "16-bit - BGGR - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1011  CHECK(PSNR >= min_PSNR_Malvar);
1012  }
1013  }
1014  }
1015 
1016  SECTION("GBRG")
1017  {
1018  const std::string filename =
1019  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_GBRG_12bits.raw");
1020  if (readBinaryFile(filename, buffer)) {
1021  col2im(buffer, I_Bayer_16U);
1022 
1023  SECTION("Bilinear")
1024  {
1025  vpImageConvert::demosaicGBRGToRGBaBilinear(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1026  I_Bayer_16U.getHeight());
1027 
1028  convertTo(I_RGBA_16U, I_RGBA_8U);
1029  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1030  std::cout << "16-bit - GBRG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1031  CHECK(PSNR >= min_PSNR_bilinear);
1032  }
1033 
1034  SECTION("Malvar")
1035  {
1036  vpImageConvert::demosaicGBRGToRGBaMalvar(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1037  I_Bayer_16U.getHeight());
1038 
1039  convertTo(I_RGBA_16U, I_RGBA_8U);
1040  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1041  std::cout << "16-bit - GBRG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1042  CHECK(PSNR >= min_PSNR_Malvar);
1043  }
1044  }
1045  }
1046 
1047  SECTION("GRBG")
1048  {
1049  const std::string filename =
1050  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_GRBG_12bits.raw");
1051  if (readBinaryFile(filename, buffer)) {
1052  col2im(buffer, I_Bayer_16U);
1053 
1054  SECTION("Bilinear")
1055  {
1056  vpImageConvert::demosaicGRBGToRGBaBilinear(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1057  I_Bayer_16U.getHeight());
1058 
1059  convertTo(I_RGBA_16U, I_RGBA_8U);
1060  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1061  std::cout << "16-bit - GRBG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1062  CHECK(PSNR >= min_PSNR_bilinear);
1063  }
1064 
1065  SECTION("Malvar")
1066  {
1067  vpImageConvert::demosaicGRBGToRGBaMalvar(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1068  I_Bayer_16U.getHeight());
1069 
1070  convertTo(I_RGBA_16U, I_RGBA_8U);
1071  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1072  std::cout << "16-bit - GRBG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1073  CHECK(PSNR >= min_PSNR_Malvar);
1074  }
1075  }
1076  }
1077 
1078  SECTION("RGGB")
1079  {
1080  const std::string filename =
1081  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_RGGB_12bits.raw");
1082  if (readBinaryFile(filename, buffer)) {
1083  col2im(buffer, I_Bayer_16U);
1084 
1085  SECTION("Bilinear")
1086  {
1087  vpImageConvert::demosaicRGGBToRGBaBilinear(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1088  I_Bayer_16U.getHeight());
1089 
1090  convertTo(I_RGBA_16U, I_RGBA_8U);
1091  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1092  std::cout << "16-bit - RGGB - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1093  CHECK(PSNR >= min_PSNR_bilinear);
1094  }
1095 
1096  SECTION("Malvar")
1097  {
1098  vpImageConvert::demosaicRGGBToRGBaMalvar(I_Bayer_16U.bitmap, I_RGBA_16U.bitmap, I_Bayer_16U.getWidth(),
1099  I_Bayer_16U.getHeight());
1100 
1101  convertTo(I_RGBA_16U, I_RGBA_8U);
1102  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1103  std::cout << "16-bit - RGGB - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1104  CHECK(PSNR >= min_PSNR_Malvar);
1105  }
1106  }
1107  }
1108  }
1109 
1110  SECTION("8-bit")
1111  {
1112  std::vector<uint8_t> buffer(height * width);
1113  vpImage<uint8_t> I_Bayer_8U(height, width);
1114  vpImage<vpRGBa> I_RGBA_8U(I_Bayer_8U.getHeight(), I_Bayer_8U.getWidth());
1115 
1116  SECTION("BGGR")
1117  {
1118  const std::string filename =
1119  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_BGGR_08bits.raw");
1120 
1121  if (readBinaryFile(filename, buffer)) {
1122  col2im(buffer, I_Bayer_8U);
1123 
1124  SECTION("Bilinear")
1125  {
1126  vpImageConvert::demosaicBGGRToRGBaBilinear(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1127  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1128 
1129  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1130  std::cout << "8-bit - BGGR - Bilinear - PSNR: " << PSNR <<" min required: " << min_PSNR_bilinear << std::endl;
1131  CHECK(PSNR >= min_PSNR_bilinear);
1132  }
1133 
1134  SECTION("Malvar")
1135  {
1136  vpImageConvert::demosaicBGGRToRGBaMalvar(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1137  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1138 
1139  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1140  std::cout << "8-bit - BGGR - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1141  CHECK(PSNR >= min_PSNR_Malvar);
1142  }
1143  }
1144  }
1145 
1146  SECTION("GBRG")
1147  {
1148  const std::string filename =
1149  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_GBRG_08bits.raw");
1150 
1151  if (readBinaryFile(filename, buffer)) {
1152  col2im(buffer, I_Bayer_8U);
1153 
1154  SECTION("Bilinear")
1155  {
1156  vpImageConvert::demosaicGBRGToRGBaBilinear(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1157  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1158 
1159  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1160  std::cout << "8-bit - GBRG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1161  CHECK(PSNR >= min_PSNR_bilinear);
1162  }
1163 
1164  SECTION("Malvar")
1165  {
1166  vpImageConvert::demosaicGBRGToRGBaMalvar(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1167  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1168 
1169  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1170  std::cout << "8-bit - GBRG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1171  CHECK(PSNR >= min_PSNR_Malvar);
1172  }
1173  }
1174  }
1175 
1176  SECTION("GRBG")
1177  {
1178  const std::string filename =
1179  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_GRBG_08bits.raw");
1180 
1181  if (readBinaryFile(filename, buffer)) {
1182  col2im(buffer, I_Bayer_8U);
1183 
1184  SECTION("Bilinear")
1185  {
1186  vpImageConvert::demosaicGRBGToRGBaBilinear(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1187  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1188 
1189  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1190  std::cout << "8-bit - GRBG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1191  CHECK(PSNR >= min_PSNR_bilinear);
1192  }
1193 
1194  SECTION("Malvar")
1195  {
1196  vpImageConvert::demosaicGRBGToRGBaMalvar(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1197  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1198 
1199  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1200  std::cout << "8-bit - GRBG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1201  CHECK(PSNR >= min_PSNR_Malvar);
1202  }
1203  }
1204  }
1205 
1206  SECTION("RGGB")
1207  {
1208  const std::string filename =
1209  vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Bayer/Klimt_Bayer_560x558_RGGB_08bits.raw");
1210 
1211  if (readBinaryFile(filename, buffer)) {
1212  col2im(buffer, I_Bayer_8U);
1213 
1214  SECTION("Bilinear")
1215  {
1216  vpImageConvert::demosaicRGGBToRGBaBilinear(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1217  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1218 
1219  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1220  std::cout << "8-bit - RGGB - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
1221  CHECK(PSNR >= min_PSNR_bilinear);
1222  }
1223 
1224  SECTION("Malvar")
1225  {
1226  vpImageConvert::demosaicRGGBToRGBaMalvar(I_Bayer_8U.bitmap, reinterpret_cast<uint8_t *>(I_RGBA_8U.bitmap),
1227  I_Bayer_8U.getWidth(), I_Bayer_8U.getHeight());
1228 
1229  double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
1230  std::cout << "8-bit - RGGB - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
1231  CHECK(PSNR >= min_PSNR_Malvar);
1232  }
1233  }
1234  }
1235  }
1236 }
1237 #endif
1238 
1239 template<typename Type>
1240 bool test_hsv(const std::vector<Type> &hue, const std::vector<Type> &saturation,
1241  const std::vector<Type> &value, const std::vector< std::vector<unsigned char> > &rgb_truth,
1242  const std::vector< std::vector<double> > &hsv_truth, size_t step, size_t size, double max_range)
1243 {
1244  // Compare HSV values
1245  for (size_t i = 0; i < size; ++i) {
1246  if (((hue[i]*max_range) != static_cast<Type>(hsv_truth[i][0])) ||
1247  ((saturation[i]*max_range) != static_cast<Type>(hsv_truth[i][1])) ||
1248  ((value[i]*max_range) != static_cast<Type>(hsv_truth[i][2]))) {
1249  if (step == 3) {
1250  std::cout << "Error in rgb to hsv conversion for rgb (";
1251  }
1252  else {
1253  std::cout << "Error in rgba to hsv conversion for rgba (";
1254  }
1255  std::cout << static_cast<int>(rgb_truth[i][0]) << ","
1256  << static_cast<int>(rgb_truth[i][1]) << ","
1257  << static_cast<int>(rgb_truth[i][2]) << "): Expected hsv value: ("
1258  << static_cast<int>(hsv_truth[i][0]) << ","
1259  << static_cast<int>(hsv_truth[i][1]) << ","
1260  << static_cast<int>(hsv_truth[i][2]) << ") converted value: ("
1261  << static_cast<int>(hue[i]) << ","
1262  << static_cast<int>(saturation[i]) << ","
1263  << static_cast<int>(value[i]) << ")" << std::endl;
1264  return false;
1265  }
1266  }
1267  return true;
1268 }
1269 
1270 bool test_rgb(const std::vector<unsigned char> &rgb, const std::vector< std::vector<unsigned char> > rgb_truth,
1271  const std::vector< std::vector<double> > &hsv_truth, size_t step, size_t size, double epsilon = 0.)
1272 {
1273  // Compare RGB values
1274  if (epsilon > 0.) {
1275  for (size_t i = 0; i < size; ++i) {
1276  if ((!vpMath::equal(rgb[i*step], rgb_truth[i][0], epsilon)) ||
1277  (!vpMath::equal(rgb[i*step+1], rgb_truth[i][1], epsilon)) ||
1278  (!vpMath::equal(rgb[i*step+2], rgb_truth[i][2], epsilon))) {
1279  std::cout << "Error in hsv to rgb conversion for hsv ("
1280  << static_cast<int>(hsv_truth[i][0]) << ","
1281  << static_cast<int>(hsv_truth[i][1]) << ","
1282  << static_cast<int>(hsv_truth[i][2]) << "): Expected rgb value: ("
1283  << static_cast<int>(rgb_truth[i][0]) << ","
1284  << static_cast<int>(rgb_truth[i][1]) << ","
1285  << static_cast<int>(rgb_truth[i][2]) << ") converted value: ("
1286  << static_cast<int>(rgb[i*step]) << ","
1287  << static_cast<int>(rgb[(i*step)+1]) << ","
1288  << static_cast<int>(rgb[(i*step)+2]) << ") epsilon: " << epsilon << std::endl;
1289  return false;
1290  }
1291  }
1292  }
1293  else {
1294  for (size_t i = 0; i < size; ++i) {
1295  if ((rgb[i*step] != rgb_truth[i][0]) || (rgb[i*step+1] != rgb_truth[i][1]) || (rgb[i*step+2] != rgb_truth[i][2])) {
1296  std::cout << "Error in hsv to rgb conversion for hsv ("
1297  << static_cast<int>(hsv_truth[i][0]) << ","
1298  << static_cast<int>(hsv_truth[i][1]) << ","
1299  << static_cast<int>(hsv_truth[i][2]) << "): Expected rgb value: ("
1300  << static_cast<int>(rgb_truth[i][0]) << ","
1301  << static_cast<int>(rgb_truth[i][1]) << ","
1302  << static_cast<int>(rgb_truth[i][2]) << ") converted value: ("
1303  << static_cast<int>(rgb[i*step]) << ","
1304  << static_cast<int>(rgb[(i*step)+1]) << ","
1305  << static_cast<int>(rgb[(i*step)+2]) << ")" << std::endl;
1306  return false;
1307  }
1308  }
1309  }
1310 
1311  return true;
1312 }
1313 
1314 TEST_CASE("RGB to HSV conversion", "[image_conversion]")
1315 {
1316  std::vector< std::vector<unsigned char> > rgb_truth;
1317  rgb_truth.push_back({ 0, 0, 0 });
1318  rgb_truth.push_back({ 255, 255, 255 });
1319  rgb_truth.push_back({ 255, 0, 0 });
1320  rgb_truth.push_back({ 0, 255, 0 });
1321  rgb_truth.push_back({ 0, 0, 255 });
1322  rgb_truth.push_back({ 255, 255, 0 });
1323  rgb_truth.push_back({ 0, 255, 255 });
1324  rgb_truth.push_back({ 255, 0, 255 });
1325  rgb_truth.push_back({ 128, 128, 128 });
1326  rgb_truth.push_back({ 128, 128, 0 });
1327  rgb_truth.push_back({ 128, 0, 0 });
1328  rgb_truth.push_back({ 0, 128, 0 });
1329  rgb_truth.push_back({ 0, 128, 128 });
1330  rgb_truth.push_back({ 0, 0, 128 });
1331  rgb_truth.push_back({ 128, 0, 128 });
1332 
1333  double h_max;
1334  bool h_full;
1335 
1336  for (size_t test = 0; test < 2; ++test) {
1337  if (test == 0) {
1338  h_max = 255;
1339  h_full = true;
1340  }
1341  else {
1342  h_max = 180;
1343  h_full = false;
1344  }
1345  std::vector< std::vector<double> > hsv_truth;
1346  // See https://www.rapidtables.com/convert/color/hsv-to-rgb.html
1347  hsv_truth.push_back({ 0, 0, 0 });
1348  hsv_truth.push_back({ 0, 0, 255 });
1349  hsv_truth.push_back({ 0, 255, 255 });
1350  hsv_truth.push_back({ h_max * 120 / 360, 255, 255 });
1351  hsv_truth.push_back({ h_max * 240 / 360, 255, 255 });
1352  hsv_truth.push_back({ h_max * 60 / 360, 255, 255 });
1353  hsv_truth.push_back({ h_max * 180 / 360, 255, 255 });
1354  hsv_truth.push_back({ h_max * 300 / 360, 255, 255 });
1355  hsv_truth.push_back({ 0, 0, 128 });
1356  hsv_truth.push_back({ h_max * 60 / 360, 255, 128 });
1357  hsv_truth.push_back({ 0, 255, 128 });
1358  hsv_truth.push_back({ h_max * 120 / 360, 255, 128 });
1359  hsv_truth.push_back({ h_max * 180 / 360, 255, 128 });
1360  hsv_truth.push_back({ h_max * 240 / 360, 255, 128 });
1361  hsv_truth.push_back({ h_max * 300 / 360, 255, 128 });
1362 
1363  size_t size = rgb_truth.size();
1364 
1365  std::vector<unsigned char> rgb_truth_continuous;
1366  for (size_t i = 0; i < size; ++i) {
1367  for (size_t j = 0; j < rgb_truth[i].size(); ++j) {
1368  rgb_truth_continuous.push_back(rgb_truth[i][j]);
1369  }
1370  }
1371  std::vector<unsigned char> rgba_truth_continuous;
1372  for (size_t i = 0; i < size; ++i) {
1373  for (size_t j = 0; j < rgb_truth[i].size(); ++j) {
1374  rgba_truth_continuous.push_back(rgb_truth[i][j]);
1375  }
1376  rgba_truth_continuous.push_back(vpRGBa::alpha_default);
1377  }
1378  SECTION("RGB -> HSV (unsigned char) -> RGB")
1379  {
1380  std::vector<unsigned char> hue(size);
1381  std::vector<unsigned char> saturation(size);
1382  std::vector<unsigned char> value(size);
1383  std::cout << "Test rgb -> hsv (unsigned char) conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
1384  vpImageConvert::RGBToHSV(reinterpret_cast<unsigned char *>(&rgb_truth_continuous.front()),
1385  reinterpret_cast<unsigned char *>(&hue.front()),
1386  reinterpret_cast<unsigned char *>(&saturation.front()),
1387  reinterpret_cast<unsigned char *>(&value.front()), size, h_full);
1388  CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 3, size, 1.));
1389 
1390  std::cout << "Test hsv (unsigned char) -> rgb conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
1391  std::vector< unsigned char> rgb_continuous(rgb_truth_continuous.size() * 3);
1392  vpImageConvert::HSVToRGB(&hue.front(), &saturation.front(), &value.front(), &rgb_continuous.front(), size, h_full);
1393  CHECK(test_rgb(rgb_continuous, rgb_truth, hsv_truth, 3, size, 5.));
1394  }
1395  SECTION("RGBa -> HSV (unsigned char) -> RGBa")
1396  {
1397  std::vector<unsigned char> hue(size);
1398  std::vector<unsigned char> saturation(size);
1399  std::vector<unsigned char> value(size);
1400  std::cout << "Test rgba -> hsv (unsigned char) conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
1401  vpImageConvert::RGBaToHSV(reinterpret_cast<unsigned char *>(&rgba_truth_continuous.front()),
1402  reinterpret_cast<unsigned char *>(&hue.front()),
1403  reinterpret_cast<unsigned char *>(&saturation.front()),
1404  reinterpret_cast<unsigned char *>(&value.front()), size, h_full);
1405  CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 4, size, 1.));
1406 
1407  std::cout << "Test hsv (unsigned char) -> rgba conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
1408  std::vector< unsigned char> rgba_continuous(rgb_truth_continuous.size() * 4);
1409  vpImageConvert::HSVToRGBa(&hue.front(), &saturation.front(), &value.front(), &rgba_continuous.front(), size, h_full);
1410  CHECK(test_rgb(rgba_continuous, rgb_truth, hsv_truth, 4, size, 5.));
1411  }
1412  if (h_full) {
1413  SECTION("RGB -> HSV (double) -> RGB")
1414  {
1415  std::vector<double> hue(size);
1416  std::vector<double> saturation(size);
1417  std::vector<double> value(size);
1418  std::cout << "Test rgb -> hsv (double) conversion" << std::endl;
1419  vpImageConvert::RGBToHSV(reinterpret_cast<unsigned char *>(&rgb_truth_continuous.front()),
1420  reinterpret_cast<double *>(&hue.front()),
1421  reinterpret_cast<double *>(&saturation.front()),
1422  reinterpret_cast<double *>(&value.front()), size);
1423  CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 3, size, 255.));
1424 
1425  std::cout << "Test hsv (double) -> rgb conversion" << std::endl;
1426  std::vector< unsigned char> rgb_continuous(rgb_truth_continuous.size());
1427  vpImageConvert::HSVToRGB(&hue.front(), &saturation.front(), &value.front(), &rgb_continuous.front(), size);
1428  CHECK(test_rgb(rgb_continuous, rgb_truth, hsv_truth, 3, size));
1429  }
1430  }
1431 
1432  if (h_full) {
1433  SECTION("RGBa -> HSV (double) -> RGBa")
1434  {
1435  std::vector<double> hue(size);
1436  std::vector<double> saturation(size);
1437  std::vector<double> value(size);
1438  std::cout << "Test rgba -> hsv (double) conversion" << std::endl;
1439  vpImageConvert::RGBaToHSV(reinterpret_cast<unsigned char *>(&rgba_truth_continuous.front()),
1440  reinterpret_cast<double *>(&hue.front()),
1441  reinterpret_cast<double *>(&saturation.front()),
1442  reinterpret_cast<double *>(&value.front()), size);
1443  CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 4, size, 255.));
1444 
1445  std::cout << "Test hsv (double) -> rgba conversion" << std::endl;
1446  std::vector< unsigned char> rgba_continuous(rgb_truth_continuous.size()*4);
1447  vpImageConvert::HSVToRGBa(&hue.front(), &saturation.front(), &value.front(), &rgba_continuous.front(), size);
1448  CHECK(test_rgb(rgba_continuous, rgb_truth, hsv_truth, 4, size));
1449  }
1450  }
1451  }
1452 }
1453 
1454 int main(int argc, char *argv[])
1455 {
1456  Catch::Session session; // There must be exactly one instance
1457 
1458  // Let Catch (using Clara) parse the command line
1459  session.applyCommandLine(argc, argv);
1460 
1461  int numFailed = session.run();
1462 
1463  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
1464  // This clamping has already been applied, so just return it here
1465  // You can also do any post run clean-up here
1466  std::cout << (numFailed ? "Test failed" : "Test succeed") << std::endl;
1467  return numFailed;
1468 }
1469 #else
1470 int main() { return EXIT_SUCCESS; }
1471 #endif
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
static void HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba, unsigned int size)
static void demosaicBGGRToRGBaBilinear(const uint8_t *bggr, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void demosaicGRBGToRGBaBilinear(const uint8_t *grbg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value, unsigned int size)
static void demosaicGRBGToRGBaMalvar(const uint8_t *grbg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void demosaicGBRGToRGBaMalvar(const uint8_t *gbrg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void merge(const vpImage< unsigned char > *R, const vpImage< unsigned char > *G, const vpImage< unsigned char > *B, const vpImage< unsigned char > *a, vpImage< vpRGBa > &RGBa)
static void demosaicBGGRToRGBaMalvar(const uint8_t *bggr, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void demosaicGBRGToRGBaBilinear(const uint8_t *gbrg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=nullptr)
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
static void demosaicRGGBToRGBaMalvar(const uint8_t *rggb, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void RGBToGrey(unsigned char *rgb, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false)
static void RGBToRGBa(unsigned char *rgb, unsigned char *rgba, unsigned int size)
static void BGRaToGrey(unsigned char *bgra, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false, unsigned int nThreads=0)
static void BGRToGrey(unsigned char *bgr, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false, unsigned int nThreads=0)
static void demosaicRGGBToRGBaBilinear(const uint8_t *rggb, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void BGRaToRGBa(unsigned char *bgra, unsigned char *rgba, unsigned int width, unsigned int height, bool flip=false)
static void RGBaToRGB(unsigned char *rgba, unsigned char *rgb, unsigned int size)
static void HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb, unsigned int size)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:143
unsigned int getWidth() const
Definition: vpImage.h:245
unsigned int getSize() const
Definition: vpImage.h:224
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:184
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1795
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:2156
static double sqr(double x)
Definition: vpMath.h:201
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:449
Definition: vpRGBa.h:61
@ alpha_default
Definition: vpRGBa.h:63
VISP_EXPORT uint16_t swap16bits(uint16_t val)
Definition: vpEndian.cpp:49