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