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