Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testImageFilterHSVOldVSNew.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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 vpImageFilter::gaussianBlur() new implementation and compare it to the old one.
32 */
38
39#include <iostream>
40#include <limits>
41
42#include <visp3/core/vpRGBa.h>
43#include <visp3/core/vpHSV.h>
44#include <visp3/core/vpImage.h>
45#include <visp3/core/vpImageFilter.h>
46
47#include "hsvUtils.h"
48
49#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
50#include <type_traits>
51
52#ifdef ENABLE_VISP_NAMESPACE
53using namespace VISP_NAMESPACE_NAME;
54#endif
55
56#ifndef DOXYGEN_SHOULD_SKIP_THIS
57namespace vpOldImageFilter
58{
69template<typename ImageType>
70static void resizeAndInitializeIfNeeded(const vpImage<bool> *p_mask, const unsigned int height, const unsigned int width, vpImage<ImageType> &I)
71{
72 if (p_mask == nullptr) {
73 // Just need to resize the output image, values will be computed and overwrite what is inside the image
74 I.resize;
75 }
76 else {
77 // Need to reset the image because some points will not be computed
78 I.resize(height, width, static_cast<ImageType>(0));
79 }
80}
81
91bool checkBooleanMask(const vpImage<bool> *p_mask, const unsigned int &r, const unsigned int &c)
92{
93 bool computeVal = true;
94#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
95 if (p_mask != nullptr)
96#else
97 if (p_mask != NULL)
98#endif
99 {
100 computeVal = (*p_mask)[r][c];
101 }
102 return computeVal;
103}
104
105double filterXR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
106{
107 const unsigned int stop = (size - 1) / 2;
108 double result = 0.;
109 for (unsigned int i = 1; i <= stop; ++i) {
110 result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
111 }
112 return result + (filter[0] * static_cast<double>(I[r][c].R));
113}
114
115double filterXG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
116{
117 const unsigned int stop = (size - 1) / 2;
118 double result = 0.;
119
120 for (unsigned int i = 1; i <= stop; ++i) {
121 result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
122 }
123 return result + (filter[0] * static_cast<double>(I[r][c].G));
124}
125
126double filterXB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
127{
128 const unsigned int stop = (size - 1) / 2;
129 double result = 0.;
130
131 for (unsigned int i = 1; i <= stop; ++i) {
132 result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
133 }
134 return result + (filter[0] * static_cast<double>(I[r][c].B));
135}
136
137double filterXLeftBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
138 const double *filter, unsigned int size)
139{
140 const unsigned int stop = (size - 1) / 2;
141 double result = 0.;
142
143 for (unsigned int i = 1; i <= stop; ++i) {
144 if (c > i) {
145 result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
146 }
147 else {
148 result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][i - c].R);
149 }
150 }
151 return result + (filter[0] * static_cast<double>(I[r][c].R));
152}
153
154double filterXLeftBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
155 const double *filter, unsigned int size)
156{
157 const unsigned int stop = (size - 1) / 2;
158 double result = 0.;
159
160 for (unsigned int i = 1; i <= stop; ++i) {
161 if (c > i) {
162 result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
163 }
164 else {
165 result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][i - c].G);
166 }
167 }
168 return result + (filter[0] * static_cast<double>(I[r][c].G));
169}
170
171double filterXLeftBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
172 const double *filter, unsigned int size)
173{
174 const unsigned int stop = (size - 1) / 2;
175 double result = 0.;
176
177 for (unsigned int i = 1; i <= stop; ++i) {
178 if (c > i) {
179 result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
180 }
181 else {
182 result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][i - c].B);
183 }
184 }
185 return result + (filter[0] * static_cast<double>(I[r][c].B));
186}
187
188double filterXRightBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
189 const double *filter, unsigned int size)
190{
191 const unsigned int val_2 = 2;
192 const unsigned int stop = (size - 1) / 2;
193 const unsigned int width = I.getWidth();
194 double result = 0.;
195
196 for (unsigned int i = 1; i <= stop; ++i) {
197 if ((c + i) < width) {
198 result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
199 }
200 else {
201 result += filter[i] * static_cast<double>(I[r][((val_2 * width) - c) - i - 1].R + I[r][c - i].R);
202 }
203 }
204 return result + (filter[0] * static_cast<double>(I[r][c].R));
205}
206
207double filterXRightBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
208 const double *filter, unsigned int size)
209{
210 const unsigned int val_2 = 2;
211 const unsigned int stop = (size - 1) / 2;
212 const unsigned int width = I.getWidth();
213 double result = 0.;
214
215 for (unsigned int i = 1; i <= stop; ++i) {
216 if ((c + i) < width) {
217 result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
218 }
219 else {
220 result += filter[i] * static_cast<double>(I[r][((val_2 * width) - c) - i - 1].G + I[r][c - i].G);
221 }
222 }
223 return result + (filter[0] * static_cast<double>(I[r][c].G));
224}
225
226double filterXRightBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
227 const double *filter, unsigned int size)
228{
229 const unsigned int val_2 = 2;
230 const unsigned int stop = (size - 1) / 2;
231 const unsigned int width = I.getWidth();
232 double result = 0.;
233
234 for (unsigned int i = 1; i <= stop; ++i) {
235 if ((c + i) < width) {
236 result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
237 }
238 else {
239 result += filter[i] * static_cast<double>(I[r][(val_2 * width) - c - i - 1].B + I[r][c - i].B);
240 }
241 }
242 return result + (filter[0] * static_cast<double>(I[r][c].B));
243}
244
245double filterYR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
246{
247 const unsigned int stop = (size - 1) / 2;
248 double result = 0.;
249
250 for (unsigned int i = 1; i <= stop; ++i) {
251 result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
252 }
253 return result + (filter[0] * static_cast<double>(I[r][c].R));
254}
255
256double filterYG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
257{
258 const unsigned int stop = (size - 1) / 2;
259 double result = 0.;
260
261 for (unsigned int i = 1; i <= stop; ++i) {
262 result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
263 }
264 return result + (filter[0] * static_cast<double>(I[r][c].G));
265}
266
267double filterYB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
268{
269 const unsigned int stop = (size - 1) / 2;
270 double result = 0.;
271
272 for (unsigned int i = 1; i <= stop; ++i) {
273 result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
274 }
275 return result + (filter[0] * static_cast<double>(I[r][c].B));
276}
277
278double filterYTopBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
279{
280 const unsigned int stop = (size - 1) / 2;
281 double result = 0.;
282
283 for (unsigned int i = 1; i <= stop; ++i) {
284 if (r > i) {
285 result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
286 }
287 else {
288 result += filter[i] * static_cast<double>(I[r + i][c].R + I[i - r][c].R);
289 }
290 }
291 return result + (filter[0] * static_cast<double>(I[r][c].R));
292}
293
294double filterYTopBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
295{
296 const unsigned int stop = (size - 1) / 2;
297 double result = 0.;
298
299 for (unsigned int i = 1; i <= stop; ++i) {
300 if (r > i) {
301 result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
302 }
303 else {
304 result += filter[i] * static_cast<double>(I[r + i][c].G + I[i - r][c].G);
305 }
306 }
307 return result + (filter[0] * static_cast<double>(I[r][c].G));
308}
309
310double filterYTopBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
311{
312 const unsigned int stop = (size - 1) / 2;
313 double result = 0.;
314
315 for (unsigned int i = 1; i <= stop; ++i) {
316 if (r > i) {
317 result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
318 }
319 else {
320 result += filter[i] * static_cast<double>(I[r + i][c].B + I[i - r][c].B);
321 }
322 }
323 return result + (filter[0] * static_cast<double>(I[r][c].B));
324}
325
326double filterYBottomBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
327 const double *filter, unsigned int size)
328{
329 const unsigned int val_2 = 2;
330 const unsigned int height = I.getHeight();
331 const unsigned int stop = (size - 1) / 2;
332 double result = 0.;
333
334 for (unsigned int i = 1; i <= stop; ++i) {
335 if ((r + i) < height) {
336 result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
337 }
338 else {
339 result += filter[i] * static_cast<double>(I[((val_2 * height) - r) - i - 1][c].R + I[r - i][c].R);
340 }
341 }
342 return result + (filter[0] * static_cast<double>(I[r][c].R));
343}
344
345double filterYBottomBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
346 const double *filter, unsigned int size)
347{
348 const unsigned int val_2 = 2;
349 const unsigned int height = I.getHeight();
350 const unsigned int stop = (size - 1) / 2;
351 double result = 0.;
352
353 for (unsigned int i = 1; i <= stop; ++i) {
354 if ((r + i) < height) {
355 result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
356 }
357 else {
358 result += filter[i] * static_cast<double>(I[((val_2 * height) - r) - i - 1][c].G + I[r - i][c].G);
359 }
360 }
361 return result + (filter[0] * static_cast<double>(I[r][c].G));
362}
363
364double filterYBottomBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
365 const double *filter, unsigned int size)
366{
367 const unsigned int val_2 = 2;
368 const unsigned int height = I.getHeight();
369 const unsigned int stop = (size - 1) / 2;
370 double result = 0.;
371
372 for (unsigned int i = 1; i <= stop; ++i) {
373 if ((r + i) < height) {
374 result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
375 }
376 else {
377 result += filter[i] * static_cast<double>(I[((val_2 * height) - r) - i - 1][c].B + I[r - i][c].B);
378 }
379 }
380 return result + (filter[0] * static_cast<double>(I[r][c].B));
381}
382
383void filterX(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr);
384
385template<typename ImageType, typename FilterType>
386inline FilterType filterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
387{
388 const unsigned int stop = (size - 1) / 2;
389 FilterType result = static_cast<FilterType>(0.);
390
391 for (unsigned int i = 1; i <= stop; ++i) {
392 result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
393 }
394 return result + (filter[0] * static_cast<FilterType>(I[r][c]));
395}
396
397template <typename ImageType, typename FilterType>
398inline FilterType filterXLeftBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
399 const FilterType *filter, unsigned int size)
400{
401 const unsigned int stop = (size - 1) / 2;
402 FilterType result = static_cast<FilterType>(0.);
403
404 for (unsigned int i = 1; i <= stop; ++i) {
405 if (c > i) {
406 result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
407 }
408 else {
409 result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][i - c]);
410 }
411 }
412 return result + (filter[0] * static_cast<FilterType>(I[r][c]));
413}
414
415template <typename ImageType, typename FilterType>
416inline FilterType filterXRightBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
417 const FilterType *filter, unsigned int size)
418{
419 const unsigned int stop = (size - 1) / 2;
420 const unsigned int width = I.getWidth();
421 FilterType result = static_cast<FilterType>(0.);
422 const unsigned int twice = 2;
423
424 for (unsigned int i = 1; i <= stop; ++i) {
425 if ((c + i) < width) {
426 result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
427 }
428 else {
429 result += filter[i] * static_cast<FilterType>(I[r][((twice * width) - c) - i - 1] + I[r][c - i]);
430 }
431 }
432 return result + (filter[0] * static_cast<FilterType>(I[r][c]));
433}
434
435template <typename ImageType, typename FilterType>
436void filterX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size,
437 const vpImage<bool> *p_mask = nullptr)
438{
439 const unsigned int height = I.getHeight();
440 const unsigned int width = I.getWidth();
441 const unsigned int stop1J = (size - 1) / 2;
442 const unsigned int stop2J = width - ((size - 1) / 2);
443 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
444
445 for (unsigned int i = 0; i < height; ++i) {
446 for (unsigned int j = 0; j < stop1J; ++j) {
447 // We have to compute the value for each pixel if we don't have a mask or for
448 // pixels for which the mask is true otherwise
449 bool computeVal = checkBooleanMask(p_mask, i, j);
450 if (computeVal) {
451 dIx[i][j] = filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
452 }
453 }
454 for (unsigned int j = stop1J; j < stop2J; ++j) {
455 // We have to compute the value for each pixel if we don't have a mask or for
456 // pixels for which the mask is true otherwise
457 bool computeVal = checkBooleanMask(p_mask, i, j);
458 if (computeVal) {
459 dIx[i][j] = filterX<ImageType, FilterType>(I, i, j, filter, size);
460 }
461 }
462 for (unsigned int j = stop2J; j < width; ++j) {
463 // We have to compute the value for each pixel if we don't have a mask or for
464 // pixels for which the mask is true otherwise
465 bool computeVal = checkBooleanMask(p_mask, i, j);
466 if (computeVal) {
467 dIx[i][j] = filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
468 }
469 }
470 }
471}
472
473void filterY(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr);
474
475template<typename ImageType, typename FilterType>
476inline FilterType filterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
477{
478 const unsigned int stop = (size - 1) / 2;
479 FilterType result = static_cast<FilterType>(0.);
480
481 for (unsigned int i = 1; i <= stop; ++i) {
482 result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
483 }
484 return result + (filter[0] * static_cast<FilterType>(I[r][c]));
485}
486
487template<typename ImageType, typename FilterType>
488inline FilterType filterYTopBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
489 const FilterType *filter, unsigned int size)
490{
491 const unsigned int stop = (size - 1) / 2;
492 FilterType result = static_cast<FilterType>(0.);
493
494 for (unsigned int i = 1; i <= stop; ++i) {
495 if (r > i) {
496 result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
497 }
498 else {
499 result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[i - r][c]);
500 }
501 }
502 return result + (filter[0] * static_cast<FilterType>(I[r][c]));
503}
504
505template<typename ImageType, typename FilterType>
506inline FilterType filterYBottomBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
507 const FilterType *filter, unsigned int size)
508{
509 const unsigned int height = I.getHeight();
510 const unsigned int stop = (size - 1) / 2;
511 FilterType result = static_cast<FilterType>(0.);
512 const unsigned int twiceHeight = 2 * height;
513 for (unsigned int i = 1; i <= stop; ++i) {
514 if ((r + i) < height) {
515 result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
516 }
517 else {
518 result += filter[i] * static_cast<FilterType>(I[(twiceHeight - r) - i - 1][c] + I[r - i][c]);
519 }
520 }
521 return result + (filter[0] * static_cast<FilterType>(I[r][c]));
522}
523
524template<typename ImageType, typename FilterType>
525void filterY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size,
526 const vpImage<bool> *p_mask = nullptr)
527{
528 const unsigned int height = I.getHeight(), width = I.getWidth();
529 const unsigned int stop1I = (size - 1) / 2;
530 const unsigned int stop2I = height - ((size - 1) / 2);
531 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
532
533 for (unsigned int i = 0; i < stop1I; ++i) {
534 for (unsigned int j = 0; j < width; ++j) {
535 // We have to compute the value for each pixel if we don't have a mask or for
536 // pixels for which the mask is true otherwise
537 bool computeVal = checkBooleanMask(p_mask, i, j);
538 if (computeVal) {
539 dIy[i][j] = filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
540 }
541 }
542 }
543 for (unsigned int i = stop1I; i < stop2I; ++i) {
544 for (unsigned int j = 0; j < width; ++j) {
545 // We have to compute the value for each pixel if we don't have a mask or for
546 // pixels for which the mask is true otherwise
547 bool computeVal = checkBooleanMask(p_mask, i, j);
548 if (computeVal) {
549 dIy[i][j] = filterY<ImageType, FilterType>(I, i, j, filter, size);
550 }
551 }
552 }
553 for (unsigned int i = stop2I; i < height; ++i) {
554 for (unsigned int j = 0; j < width; ++j) {
555 // We have to compute the value for each pixel if we don't have a mask or for
556 // pixels for which the mask is true otherwise
557 bool computeVal = checkBooleanMask(p_mask, i, j);
558 if (computeVal) {
559 dIy[i][j] = filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
560 }
561 }
562 }
563}
564
565void gaussianBlur(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI, unsigned int size = 7, double sigma = 0., bool normalize = true,
566 const vpImage<bool> *p_mask = nullptr)
567{
568 if (size-1 > I.getWidth() || size-1 > I.getHeight()) {
569 std::ostringstream oss;
570 oss << "Image size (" << I.getWidth() << "x" << I.getHeight() << ") is too small for the Gaussian kernel ("
571 << "size=" << size << "), min size is " << (size-1);
572 throw vpException(vpException::dimensionError, oss.str());
573 }
574
575 double *fg = new double[(size + 1) / 2];
576 vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
577 vpImage<vpRGBa> GIx;
578 vpImageFilter::filterX(I, GIx, fg, size, p_mask);
579 vpImageFilter::filterY(GIx, GI, fg, size, p_mask);
580 GIx.destroy();
581 delete[] fg;
582}
583
584template<typename HSVType, bool useFullScale>
585double filterXH(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
586{
587 const unsigned int stop = (size - 1) / 2;
588 double result = 0.;
589 for (unsigned int i = 1; i <= stop; ++i) {
590 result += filter[i] * static_cast<double>(I[r][c + i].H + I[r][c - i].H);
591 }
592 return result + (filter[0] * static_cast<double>(I[r][c].H));
593}
594
595template<typename HSVType, bool useFullScale>
596double filterXS(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
597{
598 const unsigned int stop = (size - 1) / 2;
599 double result = 0.;
600
601 for (unsigned int i = 1; i <= stop; ++i) {
602 result += filter[i] * static_cast<double>(I[r][c + i].S + I[r][c - i].S);
603 }
604 return result + (filter[0] * static_cast<double>(I[r][c].S));
605}
606
607template<typename HSVType, bool useFullScale>
608double filterXV(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
609{
610 const unsigned int stop = (size - 1) / 2;
611 double result = 0.;
612
613 for (unsigned int i = 1; i <= stop; ++i) {
614 result += filter[i] * static_cast<double>(I[r][c + i].V + I[r][c - i].V);
615 }
616 return result + (filter[0] * static_cast<double>(I[r][c].V));
617}
618
619template<typename HSVType, bool useFullScale>
620double filterXLeftBorderH(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
621 const double *filter, unsigned int size)
622{
623 const unsigned int stop = (size - 1) / 2;
624 double result = 0.;
625
626 for (unsigned int i = 1; i <= stop; ++i) {
627 if (c > i) {
628 result += filter[i] * static_cast<double>(I[r][c + i].H + I[r][c - i].H);
629 }
630 else {
631 result += filter[i] * static_cast<double>(I[r][c + i].H + I[r][i - c].H);
632 }
633 }
634 return result + (filter[0] * static_cast<double>(I[r][c].H));
635}
636
637template<typename HSVType, bool useFullScale>
638double filterXLeftBorderS(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
639 const double *filter, unsigned int size)
640{
641 const unsigned int stop = (size - 1) / 2;
642 double result = 0.;
643
644 for (unsigned int i = 1; i <= stop; ++i) {
645 if (c > i) {
646 result += filter[i] * static_cast<double>(I[r][c + i].S + I[r][c - i].S);
647 }
648 else {
649 result += filter[i] * static_cast<double>(I[r][c + i].S + I[r][i - c].S);
650 }
651 }
652 return result + (filter[0] * static_cast<double>(I[r][c].S));
653}
654
655template<typename HSVType, bool useFullScale>
656double filterXLeftBorderV(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
657 const double *filter, unsigned int size)
658{
659 const unsigned int stop = (size - 1) / 2;
660 double result = 0.;
661
662 for (unsigned int i = 1; i <= stop; ++i) {
663 if (c > i) {
664 result += filter[i] * static_cast<double>(I[r][c + i].V + I[r][c - i].V);
665 }
666 else {
667 result += filter[i] * static_cast<double>(I[r][c + i].V + I[r][i - c].V);
668 }
669 }
670 return result + (filter[0] * static_cast<double>(I[r][c].V));
671}
672
673template<typename HSVType, bool useFullScale>
674double filterXRightBorderH(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
675 const double *filter, unsigned int size)
676{
677 const unsigned int val_2 = 2;
678 const unsigned int stop = (size - 1) / 2;
679 const unsigned int width = I.getWidth();
680 double result = 0.;
681
682 for (unsigned int i = 1; i <= stop; ++i) {
683 if ((c + i) < width) {
684 result += filter[i] * static_cast<double>(I[r][c + i].H + I[r][c - i].H);
685 }
686 else {
687 result += filter[i] * static_cast<double>(I[r][((val_2 * width) - c) - i - 1].H + I[r][c - i].H);
688 }
689 }
690 return result + (filter[0] * static_cast<double>(I[r][c].H));
691}
692
693template<typename HSVType, bool useFullScale>
694double filterXRightBorderS(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
695 const double *filter, unsigned int size)
696{
697 const unsigned int val_2 = 2;
698 const unsigned int stop = (size - 1) / 2;
699 const unsigned int width = I.getWidth();
700 double result = 0.;
701
702 for (unsigned int i = 1; i <= stop; ++i) {
703 if ((c + i) < width) {
704 result += filter[i] * static_cast<double>(I[r][c + i].S + I[r][c - i].S);
705 }
706 else {
707 result += filter[i] * static_cast<double>(I[r][((val_2 * width) - c) - i - 1].S + I[r][c - i].S);
708 }
709 }
710 return result + (filter[0] * static_cast<double>(I[r][c].S));
711}
712
713template<typename HSVType, bool useFullScale>
714double filterXRightBorderV(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
715 const double *filter, unsigned int size)
716{
717 const unsigned int val_2 = 2;
718 const unsigned int stop = (size - 1) / 2;
719 const unsigned int width = I.getWidth();
720 double result = 0.;
721
722 for (unsigned int i = 1; i <= stop; ++i) {
723 if ((c + i) < width) {
724 result += filter[i] * static_cast<double>(I[r][c + i].V + I[r][c - i].V);
725 }
726 else {
727 result += filter[i] * static_cast<double>(I[r][(val_2 * width) - c - i - 1].V + I[r][c - i].V);
728 }
729 }
730 return result + (filter[0] * static_cast<double>(I[r][c].V));
731}
732
733template<typename HSVType, bool useFullScale>
734void filterX(const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<vpHSV<HSVType, useFullScale>> &dIx, const double *filter, unsigned int size,
735 const vpImage<bool> *p_mask)
736{
737 const unsigned int heightI = I.getHeight(), widthI = I.getWidth();
738 const unsigned int stop1J = (size - 1) / 2;
739 const unsigned int stop2J = widthI - ((size - 1) / 2);
740 resizeAndInitializeIfNeeded(p_mask, heightI, widthI, dIx);
741
742 for (unsigned int i = 0; i < heightI; ++i) {
743 for (unsigned int j = 0; j < stop1J; ++j) {
744 // We have to compute the value for each pixel if we don't have a mask or for
745 // pixels for which the mask is true otherwise
746 bool computeVal = checkBooleanMask(p_mask, i, j);
747 if (computeVal) {
748 dIx[i][j].H = static_cast<HSVType>(filterXLeftBorderH(I, i, j, filter, size));
749 dIx[i][j].S = static_cast<HSVType>(filterXLeftBorderS(I, i, j, filter, size));
750 dIx[i][j].V = static_cast<HSVType>(filterXLeftBorderV(I, i, j, filter, size));
751 }
752 }
753 for (unsigned int j = stop1J; j < stop2J; ++j) {
754 // We have to compute the value for each pixel if we don't have a mask or for
755 // pixels for which the mask is true otherwise
756 bool computeVal = checkBooleanMask(p_mask, i, j);
757 if (computeVal) {
758 dIx[i][j].H = static_cast<HSVType>(filterXH(I, i, j, filter, size));
759 dIx[i][j].S = static_cast<HSVType>(filterXS(I, i, j, filter, size));
760 dIx[i][j].V = static_cast<HSVType>(filterXV(I, i, j, filter, size));
761 }
762 }
763 for (unsigned int j = stop2J; j < widthI; ++j) {
764 // We have to compute the value for each pixel if we don't have a mask or for
765 // pixels for which the mask is true otherwise
766 bool computeVal = checkBooleanMask(p_mask, i, j);
767 if (computeVal) {
768 dIx[i][j].H = static_cast<HSVType>(filterXRightBorderH(I, i, j, filter, size));
769 dIx[i][j].S = static_cast<HSVType>(filterXRightBorderS(I, i, j, filter, size));
770 dIx[i][j].V = static_cast<HSVType>(filterXRightBorderV(I, i, j, filter, size));
771 }
772 }
773 }
774}
775
776// ------------- Filtering along Y for HSV images ----------------
777
778template<typename HSVType, bool useFullScale>
779double filterYH(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
780{
781 const unsigned int stop = (size - 1) / 2;
782 double result = 0.;
783
784 for (unsigned int i = 1; i <= stop; ++i) {
785 result += filter[i] * static_cast<double>(I[r + i][c].H + I[r - i][c].H);
786 }
787 return result + (filter[0] * static_cast<double>(I[r][c].H));
788}
789
790template<typename HSVType, bool useFullScale>
791double filterYS(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
792{
793 const unsigned int stop = (size - 1) / 2;
794 double result = 0.;
795
796 for (unsigned int i = 1; i <= stop; ++i) {
797 result += filter[i] * static_cast<double>(I[r + i][c].S + I[r - i][c].S);
798 }
799 return result + (filter[0] * static_cast<double>(I[r][c].S));
800}
801
802template<typename HSVType, bool useFullScale>
803double filterYV(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
804{
805 const unsigned int stop = (size - 1) / 2;
806 double result = 0.;
807
808 for (unsigned int i = 1; i <= stop; ++i) {
809 result += filter[i] * static_cast<double>(I[r + i][c].V + I[r - i][c].V);
810 }
811 return result + (filter[0] * static_cast<double>(I[r][c].V));
812}
813
814template<typename HSVType, bool useFullScale>
815double filterYTopBorderH(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
816{
817 const unsigned int stop = (size - 1) / 2;
818 double result = 0.;
819
820 for (unsigned int i = 1; i <= stop; ++i) {
821 if (r > i) {
822 result += filter[i] * static_cast<double>(I[r + i][c].H + I[r - i][c].H);
823 }
824 else {
825 result += filter[i] * static_cast<double>(I[r + i][c].H + I[i - r][c].H);
826 }
827 }
828 return result + (filter[0] * static_cast<double>(I[r][c].H));
829}
830
831template<typename HSVType, bool useFullScale>
832double filterYTopBorderS(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
833{
834 const unsigned int stop = (size - 1) / 2;
835 double result = 0.;
836
837 for (unsigned int i = 1; i <= stop; ++i) {
838 if (r > i) {
839 result += filter[i] * static_cast<double>(I[r + i][c].S + I[r - i][c].S);
840 }
841 else {
842 result += filter[i] * static_cast<double>(I[r + i][c].S + I[i - r][c].S);
843 }
844 }
845 return result + (filter[0] * static_cast<double>(I[r][c].S));
846}
847
848template<typename HSVType, bool useFullScale>
849double filterYTopBorderV(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
850{
851 const unsigned int stop = (size - 1) / 2;
852 double result = 0.;
853
854 for (unsigned int i = 1; i <= stop; ++i) {
855 if (r > i) {
856 result += filter[i] * static_cast<double>(I[r + i][c].V + I[r - i][c].V);
857 }
858 else {
859 result += filter[i] * static_cast<double>(I[r + i][c].V + I[i - r][c].V);
860 }
861 }
862 return result + (filter[0] * static_cast<double>(I[r][c].V));
863}
864
865template<typename HSVType, bool useFullScale>
866double filterYBottomBorderH(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
867 const double *filter, unsigned int size)
868{
869 const unsigned int val_2 = 2;
870 const unsigned int height = I.getHeight();
871 const unsigned int stop = (size - 1) / 2;
872 double result = 0.;
873
874 for (unsigned int i = 1; i <= stop; ++i) {
875 if ((r + i) < height) {
876 result += filter[i] * static_cast<double>(I[r + i][c].H + I[r - i][c].H);
877 }
878 else {
879 result += filter[i] * static_cast<double>(I[((val_2 * height) - r) - i - 1][c].H + I[r - i][c].H);
880 }
881 }
882 return result + (filter[0] * static_cast<double>(I[r][c].H));
883}
884
885template<typename HSVType, bool useFullScale>
886double filterYBottomBorderS(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
887 const double *filter, unsigned int size)
888{
889 const unsigned int val_2 = 2;
890 const unsigned int height = I.getHeight();
891 const unsigned int stop = (size - 1) / 2;
892 double result = 0.;
893
894 for (unsigned int i = 1; i <= stop; ++i) {
895 if ((r + i) < height) {
896 result += filter[i] * static_cast<double>(I[r + i][c].S + I[r - i][c].S);
897 }
898 else {
899 result += filter[i] * static_cast<double>(I[((val_2 * height) - r) - i - 1][c].S + I[r - i][c].S);
900 }
901 }
902 return result + (filter[0] * static_cast<double>(I[r][c].S));
903}
904
905template<typename HSVType, bool useFullScale>
906double filterYBottomBorderV(const vpImage<vpHSV<HSVType, useFullScale>> &I, unsigned int r, unsigned int c,
907 const double *filter, unsigned int size)
908{
909 const unsigned int val_2 = 2;
910 const unsigned int height = I.getHeight();
911 const unsigned int stop = (size - 1) / 2;
912 double result = 0.;
913
914 for (unsigned int i = 1; i <= stop; ++i) {
915 if ((r + i) < height) {
916 result += filter[i] * static_cast<double>(I[r + i][c].V + I[r - i][c].V);
917 }
918 else {
919 result += filter[i] * static_cast<double>(I[((val_2 * height) - r) - i - 1][c].V + I[r - i][c].V);
920 }
921 }
922 return result + (filter[0] * static_cast<double>(I[r][c].V));
923}
924
925template<typename HSVType, bool useFullScale>
926void filterY(const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<vpHSV<HSVType, useFullScale>> &dIy, const double *filter, unsigned int size,
927 const vpImage<bool> *p_mask)
928{
929 const unsigned int heightI = I.getHeight(), widthI = I.getWidth();
930 const unsigned int stop1I = (size - 1) / 2;
931 const unsigned int stop2I = heightI - ((size - 1) / 2);
932 resizeAndInitializeIfNeeded(p_mask, heightI, widthI, dIy);
933
934 for (unsigned int i = 0; i < stop1I; ++i) {
935 for (unsigned int j = 0; j < widthI; ++j) {
936 // We have to compute the value for each pixel if we don't have a mask or for
937 // pixels for which the mask is true otherwise
938 bool computeVal = checkBooleanMask(p_mask, i, j);
939 if (computeVal) {
940 dIy[i][j].H = static_cast<HSVType>(filterYTopBorderH(I, i, j, filter, size));
941 dIy[i][j].S = static_cast<HSVType>(filterYTopBorderS(I, i, j, filter, size));
942 dIy[i][j].V = static_cast<HSVType>(filterYTopBorderV(I, i, j, filter, size));
943 }
944 }
945 }
946 for (unsigned int i = stop1I; i < stop2I; ++i) {
947 for (unsigned int j = 0; j < widthI; ++j) {
948 // We have to compute the value for each pixel if we don't have a mask or for
949 // pixels for which the mask is true otherwise
950 bool computeVal = checkBooleanMask(p_mask, i, j);
951 if (computeVal) {
952 dIy[i][j].H = static_cast<HSVType>(filterYH(I, i, j, filter, size));
953 dIy[i][j].S = static_cast<HSVType>(filterYS(I, i, j, filter, size));
954 dIy[i][j].V = static_cast<HSVType>(filterYV(I, i, j, filter, size));
955 }
956 }
957 }
958 for (unsigned int i = stop2I; i < heightI; ++i) {
959 for (unsigned int j = 0; j < widthI; ++j) {
960 // We have to compute the value for each pixel if we don't have a mask or for
961 // pixels for which the mask is true otherwise
962 bool computeVal = checkBooleanMask(p_mask, i, j);
963 if (computeVal) {
964 dIy[i][j].H = static_cast<HSVType>(filterYBottomBorderH(I, i, j, filter, size));
965 dIy[i][j].S = static_cast<HSVType>(filterYBottomBorderS(I, i, j, filter, size));
966 dIy[i][j].V = static_cast<HSVType>(filterYBottomBorderV(I, i, j, filter, size));
967 }
968 }
969 }
970}
971
984template<typename HSVType, bool useFullScale>
985void gaussianBlur(const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<vpHSV<HSVType, useFullScale>> &GI, unsigned int size = 7, double sigma = 0., bool normalize = true,
986 const vpImage<bool> *p_mask = nullptr)
987{
988 double *fg = new double[(size + 1) / 2];
989 vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
990 vpImage<vpHSV<HSVType, useFullScale>> GIx;
991 vpImageFilter::filterX(I, GIx, fg, size, p_mask);
992 vpImageFilter::filterY(GIx, GI, fg, size, p_mask);
993 GIx.destroy();
994 delete[] fg;
995}
996
997template <typename ImageType, typename FilterType>
998static void gaussianBlur(const vpImage<ImageType> &I, vpImage<FilterType> &GI, unsigned int size = 7, FilterType sigma = 0., bool normalize = true,
999 const vpImage<bool> *p_mask = nullptr)
1000{
1001 FilterType *fg = new FilterType[(size + 1) / 2];
1002 vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
1003 vpImage<FilterType> GIx;
1004 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
1005 vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
1006 GIx.destroy();
1007 delete[] fg;
1008}
1009}
1010#endif
1011
1012int main()
1013{
1014 bool isSuccess = true;
1015
1016 // Inputs
1017 vpHSVTests::vpInputDataset dataset;
1018
1019 // Outputs
1020 vpImage<double> Iuc_filtered_old, Iuc_filtered_new;
1021 vpImage<vpRGBa> Irgba(11, 11, vpRGBa(125U, 125U, 125U)), Irgba_filtered_old, Irgba_filtered_new;
1022 vpImage<vpHSV<unsigned char, true>> Ihsv_uc_filtered_old_true, Ihsv_uc_filtered_new_true;
1023 vpImage<vpHSV<unsigned char, false>> Ihsv_uc_filtered_old_false, Ihsv_uc_filtered_new_false;
1024 vpImage<vpHSV<double>> Ihsv_double_filtered_old, Ihsv_double_filtered_new;
1025
1026 for (unsigned int size = 3; (size < 7) && isSuccess; size += 2) {
1027 for (auto input: dataset.m_ucImages) {
1028 vpHSVTests::print(input.second.m_I, input.first);
1029 vpOldImageFilter::gaussianBlur(input.second.m_I, Iuc_filtered_old, size);
1030 vpImageFilter::gaussianBlur(input.second.m_I, Iuc_filtered_new, size, 0.);
1031 bool ucSuccess = vpHSVTests::areAlmostEqual(Iuc_filtered_old, "Iuc_filtered_old", Iuc_filtered_new, "Iuc_filtered_new");
1032 isSuccess = isSuccess && ucSuccess;
1033 if (!isSuccess) {
1034 std::cerr << "ERROR: filter on uchar failed ! " << std::endl;
1035 }
1036 }
1037
1038 vpOldImageFilter::gaussianBlur(Irgba, Irgba_filtered_old, size);
1039 vpImageFilter::gaussianBlur(Irgba, Irgba_filtered_new, size, 0.);
1040 bool rgbaSuccess = vpHSVTests::areAlmostEqual(Irgba_filtered_old, "Irgba_filtered_old", Irgba_filtered_new, "Irgba_filtered_new");
1041 isSuccess = isSuccess && rgbaSuccess;
1042 if (!rgbaSuccess) {
1043 std::cerr << "ERROR: filter on RGBa failed ! " << std::endl;
1044 }
1045
1046 for (auto input: dataset.m_hsvUCtrue) {
1047 vpHSVTests::print(input.second.m_I, input.first);
1048 vpOldImageFilter::gaussianBlur(input.second.m_I, Ihsv_uc_filtered_old_true, size);
1049 vpImageFilter::gaussianBlur(input.second.m_I, Ihsv_uc_filtered_new_true, size, 0.);
1050 bool hsvucSuccessTrue = vpHSVTests::areAlmostEqual(Ihsv_uc_filtered_old_true, "Ihsv_uc_filtered_old_true", Ihsv_uc_filtered_new_true, "Ihsv_uc_filtered_new_true");
1051 isSuccess = isSuccess && hsvucSuccessTrue;
1052 if (!hsvucSuccessTrue) {
1053 std::cerr << "ERROR: filter on HSV<uchar, true> failed ! " << std::endl;
1054 }
1055 }
1056
1057 for (auto input: dataset.m_hsvUCfalse) {
1058 vpHSVTests::print(input.second.m_I, input.first);
1059 vpOldImageFilter::gaussianBlur(input.second.m_I, Ihsv_uc_filtered_old_false, size);
1060 vpImageFilter::gaussianBlur(input.second.m_I, Ihsv_uc_filtered_new_false, size, 0.);
1061 bool hsvucSuccessTrue = vpHSVTests::areAlmostEqual(Ihsv_uc_filtered_old_false, "Ihsv_uc_filtered_old_false", Ihsv_uc_filtered_new_false, "Ihsv_uc_filtered_new_false");
1062 isSuccess = isSuccess && hsvucSuccessTrue;
1063 if (!hsvucSuccessTrue) {
1064 std::cerr << "ERROR: filter on HSV<uchar, false> failed ! " << std::endl;
1065 }
1066 }
1067
1068 for (auto input: dataset.m_hsvDouble) {
1069 vpHSVTests::print(input.second.m_I, input.first);
1070 vpOldImageFilter::gaussianBlur(input.second.m_I, Ihsv_double_filtered_old, size);
1071 vpImageFilter::gaussianBlur(input.second.m_I, Ihsv_double_filtered_new, size, 0.);
1072 bool hsvucSuccessTrue = vpHSVTests::areAlmostEqual(Ihsv_double_filtered_old, "Ihsv_double_filtered_old", Ihsv_double_filtered_new, "Ihsv_double_filtered_new");
1073 isSuccess = isSuccess && hsvucSuccessTrue;
1074 if (!hsvucSuccessTrue) {
1075 std::cerr << "ERROR: filter on HSV<double> failed ! " << std::endl;
1076 }
1077 }
1078 }
1079
1080 if (isSuccess) {
1081 std::cout << "All tests were successful !" << std::endl;
1082 return EXIT_SUCCESS;
1083 }
1084 std::cerr << "ERROR: Something went wrong !" << std::endl;
1085 return EXIT_FAILURE;
1086}
1087
1088#else
1089int main()
1090{
1091 std::cout << "vpHSV class is not available, please use CXX 11 standard" << std::endl;
1092 return EXIT_SUCCESS;
1093}
1094#endif
@ dimensionError
Bad dimension.
Definition vpException.h:71
static void filterY(const vpImage< ImageType > &I, vpImage< OutputType > &dIy, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
Filter along the vertical direction.
static void filterX(const vpImage< ImageType > &I, vpImage< OutputType > &dIx, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
Filter along the horizontal direction.
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< OutputType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true, const vpImage< bool > *p_mask=nullptr)
static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
Definition of the vpImage class member functions.
Definition vpImage.h:131
void destroy()
Destructor : Memory de-allocation.
Definition vpImage.h:573
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getHeight() const
Definition vpImage.h:181