Visual Servoing Platform  version 3.4.0
testImageGetValue.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  * Test for vpImagePoint::getValue().
33  *
34  *****************************************************************************/
41 #include <iostream>
42 #include <visp3/core/vpImage.h>
43 
44 namespace
45 {
46 template<typename PixelType> PixelType checkPixelAccess(unsigned int height, unsigned int width, double v, double u) {
47  vpImage<PixelType> I(height, width);
48  for (unsigned int i = 0; i < I.getHeight(); i++) {
49  for (unsigned int j = 0; j < I.getWidth(); j++) {
50  I[i][j] = static_cast<PixelType>(i * I.getWidth() + j);
51  }
52  }
53 
54  return I.getValue(v,u);
55 }
56 
57 template<> vpRGBa checkPixelAccess(unsigned int height, unsigned int width, double v, double u) {
58  vpImage<vpRGBa> I(height, width);
59  for (unsigned int i = 0; i < I.getHeight(); i++) {
60  for (unsigned int j = 0; j < I.getWidth(); j++) {
61  I[i][j] = vpRGBa(static_cast<unsigned char>(i * I.getWidth() + j),
62  static_cast<unsigned char>(i * I.getWidth() + j),
63  static_cast<unsigned char>(i * I.getWidth() + j));
64  }
65  }
66 
67  return I.getValue(v,u);
68 }
69 
70 double randomDouble(double a, double b) {
71  double random = (static_cast<double>(rand())) / static_cast<double>(RAND_MAX);
72  double diff = b - a;
73  double r = random * diff;
74  return a + r;
75 }
76 
77 unsigned char randomPixelValue() {
78  const int min = 0, max = 255;
79  return static_cast<unsigned char>((rand() % (max - min + 1) + min));
80 }
81 
82 template <class PixelType> PixelType getValue(const vpImage<PixelType> &I, double i, double j, bool roundValue) {
83  if (i < 0 || j < 0 || i+1 > I.getHeight() || j+1 > I.getWidth()) {
84  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
85  }
86  if (I.getHeight() * I.getWidth() == 0) {
88  }
89 
90  unsigned int iround = static_cast<unsigned int>(floor(i));
91  unsigned int jround = static_cast<unsigned int>(floor(j));
92 
93  double rratio = i - static_cast<double>(iround);
94  double cratio = j - static_cast<double>(jround);
95 
96  double rfrac = 1.0 - rratio;
97  double cfrac = 1.0 - cratio;
98 
99  unsigned int iround_1 = (std::min)(I.getHeight() - 1, iround + 1);
100  unsigned int jround_1 = (std::min)(I.getWidth() - 1, jround + 1);
101 
102  double value = (static_cast<double>(I[iround][jround]) * rfrac + static_cast<double>(I[iround_1][jround]) * rratio) * cfrac +
103  (static_cast<double>(I[iround][jround_1]) * rfrac + static_cast<double>(I[iround_1][jround_1]) * rratio) * cratio;
104 
105  return static_cast<PixelType>(roundValue ? vpMath::round(value) : value);
106 }
107 } // namespace
108 
109 int main() {
110  //Test out of image memory access
111  //vpImage::getValue(double, double)
112  {
113  //unsigned char
114  std::cout << "checkPixelAccess<unsigned char>(3, 4, 2, 3): "
115  << static_cast<unsigned int>(checkPixelAccess<unsigned char>(3, 4, 2, 3)) << std::endl;
116  try {
117  std::cout << "checkPixelAccess<unsigned char>(3, 4, -2, -3): "
118  << static_cast<unsigned int>(checkPixelAccess<unsigned char>(3, 4, -2, -3)) << std::endl;
119  std::cerr << "Out of image access exception should have been thrown" << std::endl;
120  return EXIT_FAILURE;
121  } catch (...) { std::cout << "\n"; }
122  try {
123  std::cout << "checkPixelAccess<unsigned char>(3, 4, 3, 4): "
124  << static_cast<unsigned int>(checkPixelAccess<unsigned char>(3, 4, 3, 4)) << std::endl;
125  std::cerr << "Out of image access exception should have been thrown" << std::endl;
126  return EXIT_FAILURE;
127  } catch (...) { std::cout << "\n"; }
128 
129  //vpRGBa
130  std::cout << "checkPixelAccess<vpRGBa>(3, 4, 2, 3): " << checkPixelAccess<vpRGBa>(3, 4, 2, 3) << std::endl;
131  try {
132  std::cout << "checkPixelAccess<vpRGBa>(3, 4, -2, -3): " << checkPixelAccess<vpRGBa>(3, 4, -2, -3) << std::endl;
133  std::cerr << "Out of image access exception should have been thrown" << std::endl;
134  return EXIT_FAILURE;
135  } catch (...) { std::cout << "\n"; }
136  try {
137  std::cout << "checkPixelAccess<vpRGBa>(3, 4, 3, 4): " << checkPixelAccess<vpRGBa>(3, 4, 3, 4) << std::endl;
138  std::cerr << "Out of image access exception should have been thrown" << std::endl;
139  return EXIT_FAILURE;
140  } catch (...) { std::cout << "\n"; }
141 
142  //int
143  std::cout << "checkPixelAccess<int>(3, 4, 2, 3): " << checkPixelAccess<int>(3, 4, 2, 3) << std::endl;
144  try {
145  std::cout << "checkPixelAccess<int>(3, 4, -2, -3): " << checkPixelAccess<int>(3, 4, -2, -3) << std::endl;
146  std::cerr << "Out of image access exception should have been thrown" << std::endl;
147  return EXIT_FAILURE;
148  } catch (...) { std::cout << "\n"; }
149  try {
150  std::cout << "checkPixelAccess<int>(3, 4, 3, 4): " << checkPixelAccess<int>(3, 4, 3, 4) << std::endl;
151  std::cerr << "Out of image access exception should have been thrown" << std::endl;
152  return EXIT_FAILURE;
153  } catch (...) { std::cout << "\n"; }
154 
155  //double
156  std::cout << "checkPixelAccess<double>(3, 4, 2, 3): " << checkPixelAccess<double>(3, 4, 2, 3) << std::endl;
157  try {
158  std::cout << "checkPixelAccess<double>(3, 4, -2, -3): " << checkPixelAccess<double>(3, 4, -2, -3) << std::endl;
159  std::cerr << "Out of image access exception should have been thrown" << std::endl;
160  return EXIT_FAILURE;
161  } catch (...) { std::cout << "\n"; }
162  try {
163  std::cout << "checkPixelAccess<double>(3, 4, 3, 4): " << checkPixelAccess<double>(3, 4, 3, 4) << std::endl;
164  std::cerr << "Out of image access exception should have been thrown" << std::endl;
165  return EXIT_FAILURE;
166  } catch (...) { std::cout << "\n"; }
167  }
168 
169  //Test difference between double bilinear interpolation and fixed-point interpolation
170  srand(0);
171 
172  {
173  vpImage<unsigned char> I(480, 640);
174  for (unsigned int i = 0; i < I.getHeight(); i++) {
175  for (unsigned int j = 0; j < I.getWidth(); j++) {
176  I[i][j] = randomPixelValue();
177  }
178  }
179 
180  double diff_round = 0.0, diff = 0.0;
181  vpImage<unsigned char> I1(480, 640);
182  for (unsigned int i = 0; i < I.getHeight(); i++) {
183  for (unsigned int j = 0; j < I.getWidth(); j++) {
184  double idx1 = randomDouble(0, I.getHeight() - 1);
185  double idx2 = randomDouble(0, I.getWidth() - 1);
186  unsigned char val1 = I.getValue(idx1, idx2);
187  unsigned char val2 = getValue<unsigned char>(I, idx1, idx2, true);
188  unsigned char val3 = getValue<unsigned char>(I, idx1, idx2, false);
189 
190  diff_round += std::fabs((double)val1 - (double)val2);
191  diff += std::fabs((double)val1 - (double)val3);
192  }
193  }
194 
195  double meanDiffRound = diff_round / I.getSize();
196  double meanDiff = diff / I.getSize();
197  std::cout << "diff_round: " << diff_round << " ; meanDiffRound: " << meanDiffRound << std::endl;
198  std::cout << "diff: " << diff << " ; meanDiff: " << meanDiff << std::endl;
199  const double maxInterpolationErrorDiff = 1.0;
200  if (std::fabs(meanDiffRound) > maxInterpolationErrorDiff) {
201  std::cerr << "Too much pixel difference between fixed-point vpImage::getValue(double, double) and old method."
202  << std::endl;
203  return EXIT_FAILURE;
204  }
205  }
206 
207  //Test performance double bilinear interpolation + round vs fixed-point interpolation
208  {
209  vpImage<unsigned char> I(1080, 1920);
210  for (unsigned int i = 0; i < I.getHeight(); i++) {
211  for (unsigned int j = 0; j < I.getWidth(); j++) {
212  I[i][j] = randomPixelValue();
213  }
214  }
215 
216  std::vector<std::pair<double, double> > indexes;
217  for (int cpt = 0; cpt < 1000000; cpt++) {
218  double idx1 = randomDouble(0, I.getHeight() - 1);
219  double idx2 = randomDouble(0, I.getWidth() - 1);
220  indexes.push_back(std::pair<double, double>(idx1, idx2));
221  }
222 
223  int sum1 = 0;
224  double t_optim = vpTime::measureTimeMs();
225  for (size_t cpt = 0; cpt < indexes.size(); cpt++) {
226  double idx1 = indexes[cpt].first;
227  double idx2 = indexes[cpt].second;
228  sum1 += I.getValue(idx1, idx2);
229  }
230  t_optim = vpTime::measureTimeMs() - t_optim;
231  std::cout << "\nFixed-point vpImage::getValue(double, double), sum1: " << sum1 << " in " << t_optim << " ms" << std::endl;
232 
233  int sum2 = 0;
234  double t_old = vpTime::measureTimeMs();
235  for (size_t cpt = 0; cpt < indexes.size(); cpt++) {
236  double idx1 = indexes[cpt].first;
237  double idx2 = indexes[cpt].second;
238  sum2 += getValue(I, idx1, idx2, true);
239  }
240  t_old = vpTime::measureTimeMs() - t_old;
241  std::cout << "Old method, sum2: " << sum2 << " in " << t_old << " ms" << std::endl;
242  std::cout << "Speed-up: " << t_old / t_optim << "X" << std::endl;
243  }
244 
245  //Test performance double bilinear interpolation + round vs fixed-point interpolation
246  {
247  vpImage<unsigned char> I(1080, 1920);
248  for (unsigned int i = 0; i < I.getHeight(); i++) {
249  for (unsigned int j = 0; j < I.getWidth(); j++) {
250  I[i][j] = randomPixelValue();
251  }
252  }
253 
254  std::vector<std::pair<double, double> > indexes;
255  for (int cpt = 0; cpt < 1000000; cpt++) {
256  double idx1 = randomDouble(0, I.getHeight() - 1);
257  double idx2 = randomDouble(0, I.getWidth() - 1);
258  indexes.push_back(std::pair<double, double>(idx1, idx2));
259  }
260 
261  int sum1 = 0;
262  double t_optim = vpTime::measureTimeMs();
263  for (size_t cpt = 0; cpt < indexes.size(); cpt++) {
264  double idx1 = indexes[cpt].first;
265  double idx2 = indexes[cpt].second;
266  sum1 += I.getValue(idx1, idx2);
267  }
268  t_optim = vpTime::measureTimeMs() - t_optim;
269  std::cout << "\nFixed-point vpImage::getValue(double, double), sum1: " << sum1 << " in " << t_optim << " ms" << std::endl;
270 
271  int sum2 = 0;
272  double t_old = vpTime::measureTimeMs();
273  for (size_t cpt = 0; cpt < indexes.size(); cpt++) {
274  double idx1 = indexes[cpt].first;
275  double idx2 = indexes[cpt].second;
276  sum2 += getValue(I, idx1, idx2, false);
277  }
278  t_old = vpTime::measureTimeMs() - t_old;
279  std::cout << "Old method (without vpMath::round()), sum2: " << sum2 << " in " << t_old << " ms" << std::endl;
280  std::cout << "Speed-up: " << t_old / t_optim << "X" << std::endl;
281  }
282 
283  //Check that getValue() still returns correct values
284  {
285  vpImage<unsigned char> I(480, 640);
286  for (unsigned int i = 0; i < I.getHeight(); i++) {
287  for (unsigned int j = 0; j < I.getWidth(); j++) {
288  I[i][j] = randomPixelValue();
289  }
290  }
291 
292  vpImage<unsigned char> I_copy(480, 640);
293  for (unsigned int i = 0; i < I_copy.getHeight(); i++) {
294  double y = static_cast<double>(i);
295 
296  for (unsigned int j = 0; j < I_copy.getWidth(); j++) {
297  double x = static_cast<double>(j);
298 
299  I_copy[i][j] = I.getValue(y, x);
300  }
301  }
302 
303  bool same = (I == I_copy);
304  std::cout << "\nCheck that getValue returns correct results for integer coordinates\n(I == I_copy)? " << same << std::endl;
305  if (!same) {
306  std::cerr << "Issue with vpImage::getValue(double, double)!" << std::endl;
307  return EXIT_FAILURE;
308  }
309  }
310 
311  return EXIT_SUCCESS;
312 }
unsigned int getWidth() const
Definition: vpImage.h:246
error that can be emited by ViSP classes.
Definition: vpException.h:71
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:126
Definition: vpRGBa.h:66
Type getValue(unsigned int i, unsigned int j) const
Definition: vpImage.h:1346
static int round(double x)
Definition: vpMath.h:245
unsigned int getHeight() const
Definition: vpImage.h:188
Definition of the vpImage class member functions.
Definition: vpImage.h:126