Visual Servoing Platform  version 3.5.1 under development (2023-06-06)
vpImageFilter.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Various image tools, convolution, ...
33  *
34  * Authors:
35  * Eric Marchand
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpImageConvert.h>
40 #include <visp3/core/vpImageFilter.h>
41 #include <visp3/core/vpRGBa.h>
42 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408)
43 #include <opencv2/imgproc/imgproc.hpp>
44 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020101)
45 #include <opencv2/imgproc/imgproc_c.h>
46 #elif defined(VISP_HAVE_OPENCV)
47 #include <cv.h>
48 #endif
49 
77 void vpImageFilter::filter(const vpImage<unsigned char> &I, vpImage<double> &If, const vpMatrix &M, bool convolve)
78 {
79  unsigned int size_y = M.getRows(), size_x = M.getCols();
80  unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
81 
82  If.resize(I.getHeight(), I.getWidth(), 0.0);
83 
84  if (convolve) {
85  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
86  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
87  double conv = 0;
88 
89  for (unsigned int a = 0; a < size_y; a++) {
90  for (unsigned int b = 0; b < size_x; b++) {
91  double val = I[i + half_size_y - a][j + half_size_x - b]; // Convolution
92  conv += M[a][b] * val;
93  }
94  }
95  If[i][j] = conv;
96  }
97  }
98  } else {
99  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
100  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
101  double corr = 0;
102 
103  for (unsigned int a = 0; a < size_y; a++) {
104  for (unsigned int b = 0; b < size_x; b++) {
105  double val = I[i - half_size_y + a][j - half_size_x + b]; // Correlation
106  corr += M[a][b] * val;
107  }
108  }
109  If[i][j] = corr;
110  }
111  }
112  }
113 }
114 
128  bool convolve)
129 {
130  unsigned int size = M.getRows();
131  unsigned int half_size = size / 2;
132 
133  Iu.resize(I.getHeight(), I.getWidth(), 0.0);
134  Iv.resize(I.getHeight(), I.getWidth(), 0.0);
135 
136  if (convolve) {
137  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
138  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
139  double conv_u = 0;
140  double conv_v = 0;
141 
142  for (unsigned int a = 0; a < size; a++) {
143  for (unsigned int b = 0; b < size; b++) {
144  double val = I[v + half_size - a][u + half_size - b]; // Convolution
145  conv_u += M[a][b] * val;
146  conv_v += M[b][a] * val;
147  }
148  }
149  Iu[v][u] = conv_u;
150  Iv[v][u] = conv_v;
151  }
152  }
153  } else {
154  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
155  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
156  double conv_u = 0;
157  double conv_v = 0;
158 
159  for (unsigned int a = 0; a < size; a++) {
160  for (unsigned int b = 0; b < size; b++) {
161  double val = I[v - half_size + a][u - half_size + b]; // Correlation
162  conv_u += M[a][b] * val;
163  conv_v += M[b][a] * val;
164  }
165  }
166  Iu[v][u] = conv_u;
167  Iv[v][u] = conv_v;
168  }
169  }
170  }
171 }
172 
226  const vpColVector &kernelV)
227 {
228  unsigned int size = kernelH.size();
229  unsigned int half_size = size / 2;
230 
231  If.resize(I.getHeight(), I.getWidth(), 0.0);
232  vpImage<double> I_filter(I.getHeight(), I.getWidth(), 0.0);
233 
234  for (unsigned int i = 0; i < I.getHeight(); i++) {
235  for (unsigned int j = half_size; j < I.getWidth() - half_size; j++) {
236  double conv = 0.0;
237  for (unsigned int a = 0; a < kernelH.size(); a++) {
238  conv += kernelH[a] * I[i][j + half_size - a];
239  }
240 
241  I_filter[i][j] = conv;
242  }
243  }
244 
245  for (unsigned int i = half_size; i < I.getHeight() - half_size; i++) {
246  for (unsigned int j = 0; j < I.getWidth(); j++) {
247  double conv = 0.0;
248  for (unsigned int a = 0; a < kernelV.size(); a++) {
249  conv += kernelV[a] * I_filter[i + half_size - a][j];
250  }
251 
252  If[i][j] = conv;
253  }
254  }
255 }
256 
257 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
299  unsigned int gaussianFilterSize, double thresholdCanny, unsigned int apertureSobel)
300 {
301 #if (VISP_HAVE_OPENCV_VERSION < 0x020408)
302  IplImage *img_ipl = NULL;
303  vpImageConvert::convert(Isrc, img_ipl);
304  IplImage *edges_ipl;
305  edges_ipl = cvCreateImage(cvSize(img_ipl->width, img_ipl->height), img_ipl->depth, img_ipl->nChannels);
306 
307  cvSmooth(img_ipl, img_ipl, CV_GAUSSIAN, (int)gaussianFilterSize, (int)gaussianFilterSize, 0, 0);
308  cvCanny(img_ipl, edges_ipl, thresholdCanny, thresholdCanny, (int)apertureSobel);
309 
310  vpImageConvert::convert(edges_ipl, Ires);
311  cvReleaseImage(&img_ipl);
312  cvReleaseImage(&edges_ipl);
313 #else
314  cv::Mat img_cvmat, edges_cvmat;
315  vpImageConvert::convert(Isrc, img_cvmat);
316  cv::GaussianBlur(img_cvmat, img_cvmat, cv::Size((int)gaussianFilterSize, (int)gaussianFilterSize), 0, 0);
317  cv::Canny(img_cvmat, edges_cvmat, thresholdCanny, thresholdCanny, (int)apertureSobel);
318  vpImageConvert::convert(edges_cvmat, Ires);
319 #endif
320 }
321 #endif
322 
326 void vpImageFilter::filter(const vpImage<unsigned char> &I, vpImage<double> &GI, const double *filter,
327  unsigned int size)
328 {
329  vpImage<double> GIx;
330  filterX(I, GIx, filter, size);
331  filterY(GIx, GI, filter, size);
332  GIx.destroy();
333 }
334 
338 void vpImageFilter::filter(const vpImage<double> &I, vpImage<double> &GI, const double *filter, unsigned int size)
339 {
340  vpImage<double> GIx;
341  filterX(I, GIx, filter, size);
342  filterY(GIx, GI, filter, size);
343  GIx.destroy();
344 }
345 
346 void vpImageFilter::filterX(const vpImage<unsigned char> &I, vpImage<double> &dIx, const double *filter,
347  unsigned int size)
348 {
349  dIx.resize(I.getHeight(), I.getWidth());
350  for (unsigned int i = 0; i < I.getHeight(); i++) {
351  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
352  dIx[i][j] = vpImageFilter::filterXLeftBorder(I, i, j, filter, size);
353  // dIx[i][j]=0;
354  }
355  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
356  dIx[i][j] = vpImageFilter::filterX(I, i, j, filter, size);
357  }
358  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
359  dIx[i][j] = vpImageFilter::filterXRightBorder(I, i, j, filter, size);
360  // dIx[i][j]=0;
361  }
362  }
363 }
364 void vpImageFilter::filterX(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size)
365 {
366  dIx.resize(I.getHeight(), I.getWidth());
367  for (unsigned int i = 0; i < I.getHeight(); i++) {
368  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
369  dIx[i][j].R = static_cast<unsigned char>(vpImageFilter::filterXLeftBorderR(I, i, j, filter, size));
370  dIx[i][j].G = static_cast<unsigned char>(vpImageFilter::filterXLeftBorderG(I, i, j, filter, size));
371  dIx[i][j].B = static_cast<unsigned char>(vpImageFilter::filterXLeftBorderB(I, i, j, filter, size));
372  }
373  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
374  dIx[i][j].R = static_cast<unsigned char>(vpImageFilter::filterXR(I, i, j, filter, size));
375  dIx[i][j].G = static_cast<unsigned char>(vpImageFilter::filterXG(I, i, j, filter, size));
376  dIx[i][j].B = static_cast<unsigned char>(vpImageFilter::filterXB(I, i, j, filter, size));
377  }
378  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
379  dIx[i][j].R = static_cast<unsigned char>(vpImageFilter::filterXRightBorderR(I, i, j, filter, size));
380  dIx[i][j].G = static_cast<unsigned char>(vpImageFilter::filterXRightBorderG(I, i, j, filter, size));
381  dIx[i][j].B = static_cast<unsigned char>(vpImageFilter::filterXRightBorderB(I, i, j, filter, size));
382  }
383  }
384 }
385 void vpImageFilter::filterX(const vpImage<double> &I, vpImage<double> &dIx, const double *filter, unsigned int size)
386 {
387  dIx.resize(I.getHeight(), I.getWidth());
388  for (unsigned int i = 0; i < I.getHeight(); i++) {
389  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
390  dIx[i][j] = vpImageFilter::filterXLeftBorder(I, i, j, filter, size);
391  // dIx[i][j]=0;
392  }
393  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
394  dIx[i][j] = vpImageFilter::filterX(I, i, j, filter, size);
395  }
396  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
397  dIx[i][j] = vpImageFilter::filterXRightBorder(I, i, j, filter, size);
398  // dIx[i][j]=0;
399  }
400  }
401 }
402 void vpImageFilter::filterY(const vpImage<unsigned char> &I, vpImage<double> &dIy, const double *filter,
403  unsigned int size)
404 {
405  dIy.resize(I.getHeight(), I.getWidth());
406  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
407  for (unsigned int j = 0; j < I.getWidth(); j++) {
408  dIy[i][j] = vpImageFilter::filterYTopBorder(I, i, j, filter, size);
409  }
410  }
411  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
412  for (unsigned int j = 0; j < I.getWidth(); j++) {
413  dIy[i][j] = vpImageFilter::filterY(I, i, j, filter, size);
414  }
415  }
416  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
417  for (unsigned int j = 0; j < I.getWidth(); j++) {
418  dIy[i][j] = vpImageFilter::filterYBottomBorder(I, i, j, filter, size);
419  }
420  }
421 }
422 void vpImageFilter::filterY(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIy, const double *filter, unsigned int size)
423 {
424  dIy.resize(I.getHeight(), I.getWidth());
425  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
426  for (unsigned int j = 0; j < I.getWidth(); j++) {
427  dIy[i][j].R = static_cast<unsigned char>(vpImageFilter::filterYTopBorderR(I, i, j, filter, size));
428  dIy[i][j].G = static_cast<unsigned char>(vpImageFilter::filterYTopBorderG(I, i, j, filter, size));
429  dIy[i][j].B = static_cast<unsigned char>(vpImageFilter::filterYTopBorderB(I, i, j, filter, size));
430  }
431  }
432  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
433  for (unsigned int j = 0; j < I.getWidth(); j++) {
434  dIy[i][j].R = static_cast<unsigned char>(vpImageFilter::filterYR(I, i, j, filter, size));
435  dIy[i][j].G = static_cast<unsigned char>(vpImageFilter::filterYG(I, i, j, filter, size));
436  dIy[i][j].B = static_cast<unsigned char>(vpImageFilter::filterYB(I, i, j, filter, size));
437  }
438  }
439  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
440  for (unsigned int j = 0; j < I.getWidth(); j++) {
441  dIy[i][j].R = static_cast<unsigned char>(vpImageFilter::filterYBottomBorderR(I, i, j, filter, size));
442  dIy[i][j].G = static_cast<unsigned char>(vpImageFilter::filterYBottomBorderG(I, i, j, filter, size));
443  dIy[i][j].B = static_cast<unsigned char>(vpImageFilter::filterYBottomBorderB(I, i, j, filter, size));
444  }
445  }
446 }
447 void vpImageFilter::filterY(const vpImage<double> &I, vpImage<double> &dIy, const double *filter, unsigned int size)
448 {
449  dIy.resize(I.getHeight(), I.getWidth());
450  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
451  for (unsigned int j = 0; j < I.getWidth(); j++) {
452  dIy[i][j] = vpImageFilter::filterYTopBorder(I, i, j, filter, size);
453  }
454  }
455  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
456  for (unsigned int j = 0; j < I.getWidth(); j++) {
457  dIy[i][j] = vpImageFilter::filterY(I, i, j, filter, size);
458  }
459  }
460  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
461  for (unsigned int j = 0; j < I.getWidth(); j++) {
462  dIy[i][j] = vpImageFilter::filterYBottomBorder(I, i, j, filter, size);
463  }
464  }
465 }
466 
479 void vpImageFilter::gaussianBlur(const vpImage<unsigned char> &I, vpImage<double> &GI, unsigned int size, double sigma,
480  bool normalize)
481 {
482  double *fg = new double[(size + 1) / 2];
483  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
484  vpImage<double> GIx;
485  vpImageFilter::filterX(I, GIx, fg, size);
486  vpImageFilter::filterY(GIx, GI, fg, size);
487  GIx.destroy();
488  delete[] fg;
489 }
490 
502 void vpImageFilter::gaussianBlur(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI, unsigned int size, double sigma,
503  bool normalize)
504 {
505  double *fg = new double[(size + 1) / 2];
506  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
507  vpImage<vpRGBa> GIx;
508  vpImageFilter::filterX(I, GIx, fg, size);
509  vpImageFilter::filterY(GIx, GI, fg, size);
510  GIx.destroy();
511  delete[] fg;
512 }
513 
525 void vpImageFilter::gaussianBlur(const vpImage<double> &I, vpImage<double> &GI, unsigned int size, double sigma,
526  bool normalize)
527 {
528  double *fg = new double[(size + 1) / 2];
529  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
530  vpImage<double> GIx;
531  vpImageFilter::filterX(I, GIx, fg, size);
532  vpImageFilter::filterY(GIx, GI, fg, size);
533  GIx.destroy();
534  delete[] fg;
535 }
536 
553 void vpImageFilter::getGaussianKernel(double *filter, unsigned int size, double sigma, bool normalize)
554 {
555  if (size % 2 != 1)
556  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
557 
558  if (sigma <= 0)
559  sigma = (size - 1) / 6.0;
560 
561  int middle = (int)(size - 1) / 2;
562  double sigma2 = vpMath::sqr(sigma);
563  for (int i = 0; i <= middle; i++) {
564  filter[i] = (1. / (sigma * sqrt(2. * M_PI))) * exp(-(i * i) / (2. * sigma2));
565  }
566  if (normalize) {
567  // renormalization
568  double sum = 0;
569  for (int i = 1; i <= middle; i++) {
570  sum += 2 * filter[i];
571  }
572  sum += filter[0];
573 
574  for (int i = 0; i <= middle; i++) {
575  filter[i] = filter[i] / sum;
576  }
577  }
578 }
579 
593 void vpImageFilter::getGaussianDerivativeKernel(double *filter, unsigned int size, double sigma, bool normalize)
594 {
595  if (size % 2 != 1)
596  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
597 
598  if (sigma <= 0)
599  sigma = (size - 1) / 6.0;
600 
601  int middle = (int)(size - 1) / 2;
602  double sigma2 = vpMath::sqr(sigma);
603  filter[0] = 0.;
604  for (int i = 1; i <= middle; i++) {
605  filter[i] = -(1. / (sigma * sqrt(2. * M_PI))) *
606  (exp(-((i + 1) * (i + 1)) / (2. * sigma2)) - exp(-((i - 1) * (i - 1)) / (2. * sigma2))) / 2.;
607  }
608 
609  if (normalize) {
610  double sum = 0;
611  for (int i = 1; i <= middle; i++) {
612  sum += 2. * (1. / (sigma * sqrt(2. * M_PI))) * exp(-(i * i) / (2. * sigma2));
613  }
614  sum += (1. / (sigma * sqrt(2. * M_PI)));
615 
616  for (int i = 1; i <= middle; i++) {
617  filter[i] = filter[i] / sum;
618  }
619  }
620 }
621 
623 {
624  dIx.resize(I.getHeight(), I.getWidth());
625  // dIx=0;
626  for (unsigned int i = 0; i < I.getHeight(); i++) {
627  for (unsigned int j = 0; j < 3; j++) {
628  dIx[i][j] = 0;
629  }
630  for (unsigned int j = 3; j < I.getWidth() - 3; j++) {
631  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j);
632  }
633  for (unsigned int j = I.getWidth() - 3; j < I.getWidth(); j++) {
634  dIx[i][j] = 0;
635  }
636  }
637 }
638 
640 {
641  dIy.resize(I.getHeight(), I.getWidth());
642  // dIy=0;
643  for (unsigned int i = 0; i < 3; i++) {
644  for (unsigned int j = 0; j < I.getWidth(); j++) {
645  dIy[i][j] = 0;
646  }
647  }
648  for (unsigned int i = 3; i < I.getHeight() - 3; i++) {
649  for (unsigned int j = 0; j < I.getWidth(); j++) {
650  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j);
651  }
652  }
653  for (unsigned int i = I.getHeight() - 3; i < I.getHeight(); i++) {
654  for (unsigned int j = 0; j < I.getWidth(); j++) {
655  dIy[i][j] = 0;
656  }
657  }
658 }
659 
660 void vpImageFilter::getGradX(const vpImage<unsigned char> &I, vpImage<double> &dIx, const double *filter,
661  unsigned int size)
662 {
663  dIx.resize(I.getHeight(), I.getWidth());
664  //#pragma omp parallel for
665  for (unsigned int i = 0; i < I.getHeight(); i++) {
666  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
667  dIx[i][j] = 0;
668  }
669  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
670  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j, filter, size);
671  }
672  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
673  dIx[i][j] = 0;
674  }
675  }
676 }
677 void vpImageFilter::getGradX(const vpImage<double> &I, vpImage<double> &dIx, const double *filter, unsigned int size)
678 {
679  dIx.resize(I.getHeight(), I.getWidth());
680  // dIx=0;
681  for (unsigned int i = 0; i < I.getHeight(); i++) {
682  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
683  dIx[i][j] = 0;
684  }
685  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
686  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j, filter, size);
687  }
688  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
689  dIx[i][j] = 0;
690  }
691  }
692 }
693 
694 void vpImageFilter::getGradY(const vpImage<unsigned char> &I, vpImage<double> &dIy, const double *filter,
695  unsigned int size)
696 {
697  dIy.resize(I.getHeight(), I.getWidth());
698  //#pragma omp parallel for
699  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
700  for (unsigned int j = 0; j < I.getWidth(); j++) {
701  dIy[i][j] = 0;
702  }
703  }
704  //#pragma omp parallel for
705  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
706  for (unsigned int j = 0; j < I.getWidth(); j++) {
707  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j, filter, size);
708  }
709  }
710  //#pragma omp parallel for
711  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
712  for (unsigned int j = 0; j < I.getWidth(); j++) {
713  dIy[i][j] = 0;
714  }
715  }
716 }
717 
718 void vpImageFilter::getGradY(const vpImage<double> &I, vpImage<double> &dIy, const double *filter, unsigned int size)
719 {
720  dIy.resize(I.getHeight(), I.getWidth());
721  // dIy=0;
722  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
723  for (unsigned int j = 0; j < I.getWidth(); j++) {
724  dIy[i][j] = 0;
725  }
726  }
727  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
728  for (unsigned int j = 0; j < I.getWidth(); j++) {
729  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j, filter, size);
730  }
731  }
732  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
733  for (unsigned int j = 0; j < I.getWidth(); j++) {
734  dIy[i][j] = 0;
735  }
736  }
737 }
738 
748 void vpImageFilter::getGradXGauss2D(const vpImage<unsigned char> &I, vpImage<double> &dIx, const double *gaussianKernel,
749  const double *gaussianDerivativeKernel, unsigned int size)
750 {
751  vpImage<double> GIy;
752  vpImageFilter::filterY(I, GIy, gaussianKernel, size);
753  vpImageFilter::getGradX(GIy, dIx, gaussianDerivativeKernel, size);
754 }
755 
765 void vpImageFilter::getGradYGauss2D(const vpImage<unsigned char> &I, vpImage<double> &dIy, const double *gaussianKernel,
766  const double *gaussianDerivativeKernel, unsigned int size)
767 {
768  vpImage<double> GIx;
769  vpImageFilter::filterX(I, GIx, gaussianKernel, size);
770  vpImageFilter::getGradY(GIx, dIy, gaussianDerivativeKernel, size);
771 }
772 
773 // operation pour pyramide gaussienne
775 {
777 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000)
778  cv::Mat imgsrc, imgdest;
779  vpImageConvert::convert(I, imgsrc);
780  cv::pyrDown(imgsrc, imgdest, cv::Size((int)I.getWidth() / 2, (int)I.getHeight() / 2));
781  vpImageConvert::convert(imgdest, GI);
782 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408)
783  cv::Mat imgsrc, imgdest;
784  vpImageConvert::convert(I, imgsrc);
785  cv::pyrDown(imgsrc, imgdest, cvSize((int)I.getWidth() / 2, (int)I.getHeight() / 2));
786  vpImageConvert::convert(imgdest, GI);
787 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
788  IplImage *imgsrc = NULL; // cvCreateImage(cvGetSize(imgign), IPL_DEPTH_8U, 1);
789  IplImage *imgdest = NULL; // cvCreateImage(cvGetSize(imgign), IPL_DEPTH_8U, 1);
790  imgsrc = cvCreateImage(cvSize((int)I.getWidth(), (int)I.getHeight()), IPL_DEPTH_8U, 1);
791  imgdest = cvCreateImage(cvSize((int)I.getWidth() / 2, (int)I.getHeight() / 2), IPL_DEPTH_8U, 1);
792  vpImageConvert::convert(I, imgsrc);
793  cvPyrDown(imgsrc, imgdest);
794  vpImageConvert::convert(imgdest, GI);
795 
796  cvReleaseImage(&imgsrc);
797  cvReleaseImage(&imgdest);
798  // vpImage<unsigned char> sGI;sGI=GI;
799 
800 #else
803 #endif
804 }
805 
807 {
808 #if 0
809  GI.resize(I.getHeight(),(int)((I.getWidth()+1.)/2.)) ;
810  for (unsigned int i=0 ; i < I.getHeight() ; i++)
811  {
812  GI[i][0]=I[i][0];
813  for (unsigned int j=1 ; j < ((I.getWidth()+1.)/2.)-1 ; j++)
814  {
815  GI[i][j]=vpImageFilter::filterGaussXPyramidal(I,i,2*j);
816  }
817  GI[i][(int)((I.getWidth()+1.)/2.)-1]=I[i][2*((int)((I.getWidth()+1.)/2.)-1)];
818  }
819 #else
820  unsigned int w = I.getWidth() / 2;
821 
822  GI.resize(I.getHeight(), w);
823  for (unsigned int i = 0; i < I.getHeight(); i++) {
824  GI[i][0] = I[i][0];
825  for (unsigned int j = 1; j < w - 1; j++) {
826  GI[i][j] = vpImageFilter::filterGaussXPyramidal(I, i, 2 * j);
827  }
828  GI[i][w - 1] = I[i][2 * w - 1];
829  }
830 
831 #endif
832 }
834 {
835 
836 #ifdef ORIG
837  GI.resize((int)((I.getHeight() + 1.) / 2.), I.getWidth());
838  for (unsigned int j = 0; j < I.getWidth(); j++) {
839  GI[0][j] = I[0][j];
840  for (unsigned int i = 1; i < ((I.getHeight() + 1.) / 2.) - 1; i++) {
841  GI[i][j] = vpImageFilter::filterGaussYPyramidal(I, 2 * i, j);
842  }
843  GI[(int)((I.getHeight() + 1.) / 2.) - 1][j] = I[2 * ((int)((I.getHeight() + 1.) / 2.) - 1)][j];
844  }
845 
846 #else
847  unsigned int h = I.getHeight() / 2;
848 
849  GI.resize(h, I.getWidth());
850  for (unsigned int j = 0; j < I.getWidth(); j++) {
851  GI[0][j] = I[0][j];
852  for (unsigned int i = 1; i < h - 1; i++) {
853  GI[i][j] = vpImageFilter::filterGaussYPyramidal(I, 2 * i, j);
854  }
855  GI[h - 1][j] = I[2 * h - 1][j];
856  }
857 #endif
858 }
859 
867 double vpImageFilter::getSobelKernelX(double *filter, unsigned int size)
868 {
869  if (size == 0)
870  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
871  if (size > 20)
872  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
873 
874  vpMatrix SobelY(size * 2 + 1, size * 2 + 1);
875  double norm = getSobelKernelY(SobelY.data, size);
876  memcpy(filter, SobelY.t().data, SobelY.getRows() * SobelY.getCols() * sizeof(double));
877  return norm;
878 }
879 
887 double vpImageFilter::getSobelKernelY(double *filter, unsigned int size)
888 {
889  // Sobel kernel pre-computed for the usual size
890  static const double SobelY3x3[9] = {-1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0};
891  static const double SobelY5x5[25] = {-1.0, -4.0, -6.0, -4.0, -1.0, -2.0, -8.0, -12.0, -8.0, -2.0, 0.0, 0.0, 0.0,
892  0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0};
893  static const double SobelY7x7[49] = {-1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
894  -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
895  5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1};
896  const vpMatrix smoothingKernel(3, 3);
897  smoothingKernel[0][0] = 1.0;
898  smoothingKernel[0][1] = 2.0;
899  smoothingKernel[0][2] = 1.0;
900  smoothingKernel[1][0] = 2.0;
901  smoothingKernel[1][1] = 4.0;
902  smoothingKernel[1][2] = 2.0;
903  smoothingKernel[2][0] = 1.0;
904  smoothingKernel[2][1] = 2.0;
905  smoothingKernel[2][2] = 1.0;
906 
907  if (size == 0)
908  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
909  if (size > 20)
910  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
911 
912  const unsigned int kernel_size = size * 2 + 1;
913  if (kernel_size == 3) {
914  memcpy(filter, SobelY3x3, kernel_size * kernel_size * sizeof(double));
915  return 1 / 8.0;
916  }
917  if (kernel_size == 5) {
918  memcpy(filter, SobelY5x5, kernel_size * kernel_size * sizeof(double));
919  return 1 / 16.0;
920  }
921  if (kernel_size == 7) {
922  memcpy(filter, SobelY7x7, kernel_size * kernel_size * sizeof(double));
923  return 1 / 16.0;
924  }
925 
926  vpMatrix sobelY(7, 7);
927  memcpy(sobelY.data, SobelY7x7, sobelY.getRows() * sobelY.getCols() * sizeof(double));
928  for (unsigned int i = 4; i <= size; i++) {
929  sobelY = vpMatrix::conv2(sobelY, smoothingKernel, "full");
930  }
931 
932  memcpy(filter, sobelY.data, sobelY.getRows() * sobelY.getCols() * sizeof(double));
933 
934  return 1 / 16.0;
935 }
unsigned int getCols() const
Definition: vpArray2D.h:282
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:146
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:294
unsigned int getRows() const
Definition: vpArray2D.h:292
Implementation of column vector and the associated operations.
Definition: vpColVector.h:172
error that can be emited by ViSP classes.
Definition: vpException.h:72
@ dimensionError
Bad dimension.
Definition: vpException.h:95
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Error that can be emited by the vpImage class and its derivates.
static unsigned char filterGaussXPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static void filter(const vpImage< double > &I, vpImage< double > &Iu, vpImage< double > &Iv, const vpMatrix &M, bool convolve=false)
static double derivativeFilterY(const vpImage< T > &I, unsigned int r, unsigned int c)
Definition: vpImageFilter.h:96
static double filterYTopBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterXLeftBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterY(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *filter, unsigned int size)
static double filterYBottomBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void getGradXGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
static double filterYTopBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void getGaussianDerivativeKernel(double *filter, unsigned int size, double sigma=0., bool normalize=true)
static void getGradX(const vpImage< unsigned char > &I, vpImage< double > &dIx)
static double filterXRightBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterYBottomBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterYTopBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterXB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void filterX(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *filter, unsigned int size)
static void gaussianBlur(const vpImage< unsigned char > &I, vpImage< double > &GI, unsigned int size=7, double sigma=0., bool normalize=true)
static double filterXLeftBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void sepFilter(const vpImage< unsigned char > &I, vpImage< double > &If, const vpColVector &kernelH, const vpColVector &kernelV)
static double getSobelKernelX(double *filter, unsigned int size)
static double filterXRightBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterYBottomBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double derivativeFilterX(const vpImage< T > &I, unsigned int r, unsigned int c)
Definition: vpImageFilter.h:82
static double filterXLeftBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void getGaussianKernel(double *filter, unsigned int size, double sigma=0., bool normalize=true)
static double getSobelKernelY(double *filter, unsigned int size)
static double filterXLeftBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterXRightBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void getGradYGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIy, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
static void filterXR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void getGaussXPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static void canny(const vpImage< unsigned char > &I, vpImage< unsigned char > &Ic, unsigned int gaussianFilterSize, double thresholdCanny, unsigned int apertureSobel)
static double filterYTopBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void getGaussYPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static double filterXRightBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterXG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void getGradY(const vpImage< unsigned char > &I, vpImage< double > &dIy)
static double filterYBottomBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static unsigned char filterGaussYPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static void getGaussPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:829
unsigned int getWidth() const
Definition: vpImage.h:247
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
unsigned int getHeight() const
Definition: vpImage.h:189
static double sqr(double x)
Definition: vpMath.h:122
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:154
static vpMatrix conv2(const vpMatrix &M, const vpMatrix &kernel, const std::string &mode="full")
Definition: vpMatrix.cpp:6786
vpMatrix t() const
Definition: vpMatrix.cpp:462