Visual Servoing Platform version 3.5.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
44namespace
45{
46template<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
57template<> 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
70double 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
77unsigned char randomPixelValue() {
78 const int min = 0, max = 255;
79 return static_cast<unsigned char>((rand() % (max - min + 1) + min));
80}
81
82template <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
109int 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}
error that can be emited by ViSP classes.
Definition: vpException.h:72
Definition of the vpImage class member functions.
Definition: vpImage.h:139
unsigned int getWidth() const
Definition: vpImage.h:246
Type getValue(unsigned int i, unsigned int j) const
Definition: vpImage.h:1346
unsigned int getSize() const
Definition: vpImage.h:227
unsigned int getHeight() const
Definition: vpImage.h:188
double getValue(double i, double j) const
Definition: vpImage.h:1401
static int round(double x)
Definition: vpMath.h:247
Definition: vpRGBa.h:67
VISP_EXPORT double measureTimeMs()