Visual Servoing Platform  version 3.6.1 under development (2024-09-07)
vpImageTools_warp.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 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  * Image handling.
32  */
33 
34 #ifndef VP_IMAGE_TOOLS_WARP_H
35 #define VP_IMAGE_TOOLS_WARP_H
36 
37 // Warning: this file shouldn't be included by the user. Internal usage only to reduce length of vpImage.h
38 #include <visp3/core/vpImageTools.h>
39 
54 template <class Type>
56  const vpImageInterpolationType &interpolation, bool fixedPointArithmetic, bool pixelCenter)
57 {
58  const unsigned int expectedNbCols = 3, expectedNbRows1stOpt = 2, expectedNbRows2ndOpt = 3;
59  if (((T.getRows() != expectedNbRows1stOpt) && (T.getRows() != expectedNbRows2ndOpt)) || (T.getCols() != expectedNbCols)) {
60  std::cerr << "Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
61  return;
62  }
63 
64  if (src.getSize() == 0) {
65  return;
66  }
67 
68  const bool affine = (T.getRows() == 2);
69  const bool interp_NN = (interpolation == INTERPOLATION_NEAREST) || (interpolation == INTERPOLATION_CUBIC);
70 
71  if (dst.getSize() == 0) {
72  dst.resize(src.getHeight(), src.getWidth(), Type(0));
73  }
74 
75  vpMatrix M = T;
76  if (affine) {
77  const unsigned int index_0 = 0;
78  const unsigned int index_1 = 1;
79  const unsigned int index_2 = 2;
80  double D = (M[index_0][index_0] * M[index_1][index_1]) - (M[index_0][index_1] * M[index_1][index_0]);
81  D = !vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? (1.0 / D) : 0;
82  double A11 = M[index_1][index_1] * D, A22 = M[index_0][index_0] * D;
83  M[index_0][index_0] = A11;
84  M[index_0][index_1] *= -D;
85  M[index_1][index_0] *= -D;
86  M[index_1][index_1] = A22;
87  double b1 = (-M[index_0][index_0] * M[index_0][index_2]) - (M[index_0][index_1] * M[index_1][index_2]);
88  double b2 = (-M[index_1][index_0] * M[index_0][index_2]) - (M[index_1][index_1] * M[index_1][index_2]);
89  M[index_0][index_2] = b1;
90  M[index_1][index_2] = b2;
91  }
92  else {
93  M = T.inverseByLU();
94  }
95 
96  if (fixedPointArithmetic && (!pixelCenter)) {
97  fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) && checkFixedPoint(dst.getWidth() - 1, 0, M, affine) &&
98  checkFixedPoint(0, dst.getHeight() - 1, M, affine) &&
99  checkFixedPoint(dst.getWidth() - 1, dst.getHeight() - 1, M, affine);
100  }
101 
102  if (interp_NN) {
103  // nearest neighbor interpolation
104  warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
105  }
106  else {
107  // bilinear interpolation
108  warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
109  }
110 }
111 
112 template <class Type>
113 void vpImageTools::warpNN(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
114  bool centerCorner, bool fixedPoint)
115 {
116  if (fixedPoint && (!centerCorner)) {
117  const int nbits = 16;
118  const int32_t precision = 1 << nbits;
119  const float precision_1 = 1 / static_cast<float>(precision);
120  const unsigned int index_0 = 0;
121  const unsigned int index_1 = 1;
122  const unsigned int index_2 = 2;
123  int32_t a0_i32 = static_cast<int32_t>(T[index_0][index_0] * precision);
124  int32_t a1_i32 = static_cast<int32_t>(T[index_0][index_1] * precision);
125  int32_t a2_i32 = static_cast<int32_t>(T[index_0][index_2] * precision);
126  int32_t a3_i32 = static_cast<int32_t>(T[index_1][index_0] * precision);
127  int32_t a4_i32 = static_cast<int32_t>(T[index_1][index_1] * precision);
128  int32_t a5_i32 = static_cast<int32_t>(T[index_1][index_2] * precision);
129  int32_t a6_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[index_2][index_0] * precision) : 0;
130  int32_t a7_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[index_2][index_1] * precision) : 0;
131  int32_t a8_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[index_2][index_2] * precision) : 1;
132 
133  int32_t height_1_i32 = static_cast<int32_t>((src.getHeight() - 1) * precision) + 0x8000;
134  int32_t width_1_i32 = static_cast<int32_t>((src.getWidth() - 1) * precision) + 0x8000;
135 
136  if (affine) {
137  unsigned int dst_height = dst.getHeight();
138  unsigned int dst_width = dst.getWidth();
139  for (unsigned int i = 0; i < dst_height; ++i) {
140  int32_t xi = a2_i32;
141  int32_t yi = a5_i32;
142 
143  for (unsigned int j = 0; j < dst_width; ++j) {
144  if ((yi >= 0) && (yi < height_1_i32) && (xi >= 0) && (xi < width_1_i32)) {
145  float x_ = (xi >> nbits) + ((xi & 0xFFFF) * precision_1);
146  float y_ = (yi >> nbits) + ((yi & 0xFFFF) * precision_1);
147 
148  int x = vpMath::round(x_);
149  int y = vpMath::round(y_);
150  dst[i][j] = src[y][x];
151  }
152 
153  xi += a0_i32;
154  yi += a3_i32;
155  }
156 
157  a2_i32 += a1_i32;
158  a5_i32 += a4_i32;
159  }
160  }
161  else {
162  unsigned int dst_height = dst.getHeight();
163  unsigned int dst_width = dst.getWidth();
164  int src_height = static_cast<int>(src.getHeight());
165  int src_width = static_cast<int>(src.getWidth());
166  for (unsigned int i = 0; i < dst_height; ++i) {
167  int64_t xi = a2_i32;
168  int64_t yi = a5_i32;
169  int64_t wi = a8_i32;
170 
171  for (unsigned int j = 0; j < dst_width; ++j) {
172  bool cond_on_y = (yi >= 0) && (yi <= ((src_height - 1) * wi));
173  bool cond_on_x = (xi >= 0) && (xi <= ((src_width - 1) * wi));
174  if ((wi != 0) && cond_on_y && cond_on_x) {
175  float w_ = (wi >> nbits) + ((wi & 0xFFFF) * precision_1);
176  float x_ = ((xi >> nbits) + ((xi & 0xFFFF) * precision_1)) / w_;
177  float y_ = ((yi >> nbits) + ((yi & 0xFFFF) * precision_1)) / w_;
178 
179  int x = vpMath::round(x_);
180  int y = vpMath::round(y_);
181 
182  dst[i][j] = src[y][x];
183  }
184 
185  xi += a0_i32;
186  yi += a3_i32;
187  wi += a6_i32;
188  }
189 
190  a2_i32 += a1_i32;
191  a5_i32 += a4_i32;
192  a8_i32 += a7_i32;
193  }
194  }
195  }
196  else {
197  const unsigned int index_0 = 0;
198  const unsigned int index_1 = 1;
199  const unsigned int index_2 = 2;
200  double a0 = T[index_0][index_0];
201  double a1 = T[index_0][index_1];
202  double a2 = T[index_0][index_2];
203  double a3 = T[index_1][index_0];
204  double a4 = T[index_1][index_1];
205  double a5 = T[index_1][index_2];
206  double a6 = affine ? 0.0 : T[index_2][index_0];
207  double a7 = affine ? 0.0 : T[index_2][index_1];
208  double a8 = affine ? 1.0 : T[index_2][index_2];
209 
210  unsigned int dst_height = dst.getHeight();
211  unsigned int dst_width = dst.getWidth();
212  for (unsigned int i = 0; i < dst_height; ++i) {
213  for (unsigned int j = 0; j < dst_width; ++j) {
214  double x = ((a0 * (centerCorner ? (j + 0.5) : j)) + (a1 * (centerCorner ? (i + 0.5) : i))) + a2;
215  double y = ((a3 * (centerCorner ? (j + 0.5) : j)) + (a4 * (centerCorner ? (i + 0.5) : i))) + a5;
216  double w = ((a6 * (centerCorner ? (j + 0.5) : j)) + (a7 * (centerCorner ? (i + 0.5) : i))) + a8;
217 
218  if (vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
219  w = 1.0;
220  }
221 
222  int x_ = centerCorner ? coordCast(x / w) : vpMath::round(x / w);
223  int y_ = centerCorner ? coordCast(y / w) : vpMath::round(y / w);
224 
225  if ((x_ >= 0) && (x_ < static_cast<int>(src.getWidth())) && (y_ >= 0) && (y_ < static_cast<int>(src.getHeight()))) {
226  dst[i][j] = src[y_][x_];
227  }
228  }
229  }
230  }
231 }
232 
233 template <class Type>
234 void vpImageTools::warpLinear(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
235  bool centerCorner, bool fixedPoint)
236 {
237  if (fixedPoint && (!centerCorner)) {
238  const int nbits = 16;
239  const uint64_t precision = 1 << nbits;
240  const float precision_1 = 1 / static_cast<float>(precision);
241  const uint64_t precision2 = 1ULL << (2 * nbits);
242  const float precision_2 = 1 / static_cast<float>(precision2);
243  const unsigned int index_0 = 0;
244  const unsigned int index_1 = 1;
245  const unsigned int index_2 = 2;
246 
247  int64_t a0_i64 = static_cast<int64_t>(T[index_0][index_0] * precision);
248  int64_t a1_i64 = static_cast<int64_t>(T[index_0][index_1] * precision);
249  int64_t a2_i64 = static_cast<int64_t>(T[index_0][index_2] * precision);
250  int64_t a3_i64 = static_cast<int64_t>(T[index_1][index_0] * precision);
251  int64_t a4_i64 = static_cast<int64_t>(T[index_1][index_1] * precision);
252  int64_t a5_i64 = static_cast<int64_t>(T[index_1][index_2] * precision);
253  int64_t a6_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[index_2][index_0] * precision) : 0;
254  int64_t a7_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[index_2][index_1] * precision) : 0;
255  int64_t a8_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[index_2][index_2] * precision) : 1;
256 
257  int64_t height_i64 = static_cast<int64_t>(src.getHeight() * precision);
258  int64_t width_i64 = static_cast<int64_t>(src.getWidth() * precision);
259 
260  if (affine) {
261  unsigned int dst_height = dst.getHeight();
262  unsigned int dst_width = dst.getWidth();
263  for (unsigned int i = 0; i < dst_height; ++i) {
264  int64_t xi_ = a2_i64;
265  int64_t yi_ = a5_i64;
266 
267  for (unsigned int j = 0; j < dst_width; ++j) {
268  if ((yi_ >= 0) && (yi_ < height_i64) && (xi_ >= 0) && (xi_ < width_i64)) {
269  const int64_t xi_lower = xi_ & (~0xFFFF);
270  const int64_t yi_lower = yi_ & (~0xFFFF);
271 
272  const int64_t t = yi_ - yi_lower;
273  const int64_t t_1 = precision - t;
274  const int64_t s = xi_ - xi_lower;
275  const int64_t s_1 = precision - s;
276 
277  const int x_ = static_cast<int>(xi_ >> nbits);
278  const int y_ = static_cast<int>(yi_ >> nbits);
279 
280  if ((y_ < (static_cast<int>(src.getHeight()) - 1)) && (x_ < (static_cast<int>(src.getWidth()) - 1))) {
281  const Type val00 = src[y_][x_];
282  const Type val01 = src[y_][x_ + 1];
283  const Type val10 = src[y_ + 1][x_];
284  const Type val11 = src[y_ + 1][x_ + 1];
285  const int64_t interp_i64 =
286  static_cast<int64_t>(((s_1 * t_1) * val00) + ((s * t_1) * val01) + ((s_1 * t) * val10) + ((s * t) * val11));
287  const float interp = (interp_i64 >> (nbits * 2)) + ((interp_i64 & 0xFFFFFFFFU) * precision_2);
288  dst[i][j] = vpMath::saturate<Type>(interp);
289  }
290  else if (y_ < (static_cast<int>(src.getHeight()) - 1)) {
291  const Type val00 = src[y_][x_];
292  const Type val10 = src[y_ + 1][x_];
293  const int64_t interp_i64 = static_cast<int64_t>((t_1 * val00) + (t * val10));
294  const float interp = (interp_i64 >> nbits) + ((interp_i64 & 0xFFFF) * precision_1);
295  dst[i][j] = vpMath::saturate<Type>(interp);
296  }
297  else if (x_ < (static_cast<int>(src.getWidth()) - 1)) {
298  const Type val00 = src[y_][x_];
299  const Type val01 = src[y_][x_ + 1];
300  const int64_t interp_i64 = static_cast<int64_t>((s_1 * val00) + (s * val01));
301  const float interp = (interp_i64 >> nbits) + ((interp_i64 & 0xFFFF) * precision_1);
302  dst[i][j] = vpMath::saturate<Type>(interp);
303  }
304  else {
305  dst[i][j] = src[y_][x_];
306  }
307  }
308 
309  xi_ += a0_i64;
310  yi_ += a3_i64;
311  }
312 
313  a2_i64 += a1_i64;
314  a5_i64 += a4_i64;
315  }
316  }
317  else {
318  unsigned int dst_height = dst.getHeight();
319  unsigned int dst_width = dst.getWidth();
320  int src_height = static_cast<int>(src.getHeight());
321  int src_width = static_cast<int>(src.getWidth());
322  for (unsigned int i = 0; i < dst_height; ++i) {
323  int64_t xi = a2_i64;
324  int64_t yi = a5_i64;
325  int64_t wi = a8_i64;
326 
327  for (unsigned int j = 0; j < dst_width; ++j) {
328  bool cond_on_y = (yi >= 0) && (yi <= ((src_height - 1) * wi));
329  bool cond_on_x = (xi >= 0) && (xi <= ((src_width - 1) * wi));
330  if ((wi != 0) && cond_on_y && cond_on_x) {
331  const float wi_ = (wi >> nbits) + ((wi & 0xFFFF) * precision_1);
332  const float xi_ = ((xi >> nbits) + ((xi & 0xFFFF) * precision_1)) / wi_;
333  const float yi_ = ((yi >> nbits) + ((yi & 0xFFFF) * precision_1)) / wi_;
334 
335  const int x_ = static_cast<int>(xi_);
336  const int y_ = static_cast<int>(yi_);
337 
338  const float t = yi_ - y_;
339  const float s = xi_ - x_;
340 
341  if ((y_ < (src_height - 1)) && (x_ < (src_width - 1))) {
342  const float val00 = static_cast<float>(src[y_][x_]);
343  const float val01 = static_cast<float>(src[y_][x_ + 1]);
344  const float val10 = static_cast<float>(src[y_ + 1][x_]);
345  const float val11 = static_cast<float>(src[y_ + 1][x_ + 1]);
346  const float col0 = lerp(val00, val01, s);
347  const float col1 = lerp(val10, val11, s);
348  const float interp = lerp(col0, col1, t);
349  dst[i][j] = vpMath::saturate<Type>(interp);
350  }
351  else if (y_ < (src_height - 1)) {
352  const float val00 = static_cast<float>(src[y_][x_]);
353  const float val10 = static_cast<float>(src[y_ + 1][x_]);
354  const float interp = lerp(val00, val10, t);
355  dst[i][j] = vpMath::saturate<Type>(interp);
356  }
357  else if (x_ < (src_width - 1)) {
358  const float val00 = static_cast<float>(src[y_][x_]);
359  const float val01 = static_cast<float>(src[y_][x_ + 1]);
360  const float interp = lerp(val00, val01, s);
361  dst[i][j] = vpMath::saturate<Type>(interp);
362  }
363  else {
364  dst[i][j] = src[y_][x_];
365  }
366  }
367 
368  xi += a0_i64;
369  yi += a3_i64;
370  wi += a6_i64;
371  }
372 
373  a2_i64 += a1_i64;
374  a5_i64 += a4_i64;
375  a8_i64 += a7_i64;
376  }
377  }
378  }
379  else {
380  const unsigned int index_0 = 0;
381  const unsigned int index_1 = 1;
382  const unsigned int index_2 = 2;
383  double a0 = T[index_0][index_0];
384  double a1 = T[index_0][index_1];
385  double a2 = T[index_0][index_2];
386  double a3 = T[index_1][index_0];
387  double a4 = T[index_1][index_1];
388  double a5 = T[index_1][index_2];
389  double a6 = affine ? 0.0 : T[index_2][index_0];
390  double a7 = affine ? 0.0 : T[index_2][index_1];
391  double a8 = affine ? 1.0 : T[index_2][index_2];
392 
393  unsigned int dst_height = dst.getHeight();
394  unsigned int dst_width = dst.getWidth();
395  int src_height = static_cast<int>(src.getHeight());
396  int src_width = static_cast<int>(src.getWidth());
397  for (unsigned int i = 0; i < dst_height; ++i) {
398  for (unsigned int j = 0; j < dst_width; ++j) {
399  double x = (a0 * (centerCorner ? (j + 0.5) : j)) + (a1 * (centerCorner ? (i + 0.5) : i)) + a2;
400  double y = (a3 * (centerCorner ? (j + 0.5) : j)) + (a4 * (centerCorner ? (i + 0.5) : i)) + a5;
401  double w = (a6 * (centerCorner ? (j + 0.5) : j)) + (a7 * (centerCorner ? (i + 0.5) : i)) + a8;
402  if (vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
403  w = 1;
404  }
405 
406  x = (x / w) - (centerCorner ? 0.5 : 0);
407  y = (y / w) - (centerCorner ? 0.5 : 0);
408 
409  int x_lower = static_cast<int>(x);
410  int y_lower = static_cast<int>(y);
411  bool stop_for_loop = false;
412  if ((y_lower >= src_height) || (x_lower >= src_width) || (y < 0) || (x < 0)) {
413  stop_for_loop = true;
414  }
415  if (!stop_for_loop) {
416  double s = x - x_lower;
417  double t = y - y_lower;
418 
419  if ((y_lower < (src_height - 1)) && (x_lower < (src_width - 1))) {
420  const double val00 = static_cast<double>(src[y_lower][x_lower]);
421  const double val01 = static_cast<double>(src[y_lower][x_lower + 1]);
422  const double val10 = static_cast<double>(src[y_lower + 1][x_lower]);
423  const double val11 = static_cast<double>(src[y_lower + 1][x_lower + 1]);
424  const double col0 = lerp(val00, val01, s);
425  const double col1 = lerp(val10, val11, s);
426  const double interp = lerp(col0, col1, t);
427  dst[i][j] = vpMath::saturate<Type>(interp);
428  }
429  else if (y_lower < (src_height - 1)) {
430  const double val00 = static_cast<double>(src[y_lower][x_lower]);
431  const double val10 = static_cast<double>(src[y_lower + 1][x_lower]);
432  const double interp = lerp(val00, val10, t);
433  dst[i][j] = vpMath::saturate<Type>(interp);
434  }
435  else if (x_lower < (src_width - 1)) {
436  const double val00 = static_cast<double>(src[y_lower][x_lower]);
437  const double val01 = static_cast<double>(src[y_lower][x_lower + 1]);
438  const double interp = lerp(val00, val01, s);
439  dst[i][j] = vpMath::saturate<Type>(interp);
440  }
441  else {
442  dst[i][j] = src[y_lower][x_lower];
443  }
444  }
445  }
446  }
447  }
448 }
449 
450 inline void vpImageTools::warpLinearFixedPointNotCenter(const vpImage<vpRGBa> &src, const vpMatrix &T,
451  vpImage<vpRGBa> &dst, bool affine)
452 {
453  const unsigned int index_0 = 0, index_1 = 1, index_2 = 2;
454  const int nbits = 16;
455  const int64_t precision = 1 << nbits;
456  const float precision_1 = 1.f / static_cast<float>(precision);
457  const int64_t precision2 = 1ULL << (2 * nbits);
458  const float precision_2 = 1.f / static_cast<float>(precision2);
459 
460  int64_t a0_i64 = static_cast<int64_t>(T[index_0][index_0] * precision);
461  int64_t a1_i64 = static_cast<int64_t>(T[index_0][index_1] * precision);
462  int64_t a2_i64 = static_cast<int64_t>(T[index_0][index_2] * precision);
463  int64_t a3_i64 = static_cast<int64_t>(T[index_1][index_0] * precision);
464  int64_t a4_i64 = static_cast<int64_t>(T[index_1][index_1] * precision);
465  int64_t a5_i64 = static_cast<int64_t>(T[index_1][index_2] * precision);
466  int64_t a6_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[index_2][index_0] * precision) : 0;
467  int64_t a7_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[index_2][index_1] * precision) : 0;
468  int64_t a8_i64 = precision;
469 
470  int64_t height_i64 = static_cast<int64_t>(src.getHeight() * precision);
471  int64_t width_i64 = static_cast<int64_t>(src.getWidth() * precision);
472 
473  if (affine) {
474  unsigned int dst_height = dst.getHeight();
475  unsigned int dst_width = dst.getWidth();
476  int src_height = static_cast<int>(src.getHeight());
477  int src_width = static_cast<int>(src.getWidth());
478  const unsigned char aChannelVal = 255;
479  for (unsigned int i = 0; i < dst_height; ++i) {
480  int64_t xi = a2_i64;
481  int64_t yi = a5_i64;
482 
483  for (unsigned int j = 0; j < dst_width; ++j) {
484  if ((yi >= 0) && (yi < height_i64) && (xi >= 0) && (xi < width_i64)) {
485  const int64_t xi_lower = xi & (~0xFFFF);
486  const int64_t yi_lower = yi & (~0xFFFF);
487 
488  const int64_t t = yi - yi_lower;
489  const int64_t t_1 = precision - t;
490  const int64_t s = xi - xi_lower;
491  const int64_t s_1 = precision - s;
492 
493  const int x_ = static_cast<int>(xi >> nbits);
494  const int y_ = static_cast<int>(yi >> nbits);
495 
496  if ((y_ < (src_height - 1)) && (x_ < (src_width - 1))) {
497  const vpRGBa val00 = src[y_][x_];
498  const vpRGBa val01 = src[y_][x_ + 1];
499  const vpRGBa val10 = src[y_ + 1][x_];
500  const vpRGBa val11 = src[y_ + 1][x_ + 1];
501  const int64_t interpR_i64 =
502  static_cast<int64_t>((s_1 * t_1 * val00.R) + (s * t_1 * val01.R) + (s_1 * t * val10.R) + (s * t * val11.R));
503  const float interpR = (interpR_i64 >> (nbits * 2)) + ((interpR_i64 & 0xFFFFFFFFU) * precision_2);
504 
505  const int64_t interpG_i64 =
506  static_cast<int64_t>((s_1 * t_1 * val00.G) + (s * t_1 * val01.G) + (s_1 * t * val10.G) + (s * t * val11.G));
507  const float interpG = (interpG_i64 >> (nbits * 2)) + ((interpG_i64 & 0xFFFFFFFFU) * precision_2);
508 
509  const int64_t interpB_i64 =
510  static_cast<int64_t>((s_1 * t_1 * val00.B) + (s * t_1 * val01.B) + (s_1 * t * val10.B) + (s * t * val11.B));
511  const float interpB = (interpB_i64 >> (nbits * 2)) + ((interpB_i64 & 0xFFFFFFFFU) * precision_2);
512 
513  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
514  vpMath::saturate<unsigned char>(interpB), aChannelVal);
515  }
516  else if (y_ < (src_height - 1)) {
517  const vpRGBa val00 = src[y_][x_];
518  const vpRGBa val10 = src[y_ + 1][x_];
519  const int64_t interpR_i64 = static_cast<int64_t>((t_1 * val00.R) + (t * val10.R));
520  const float interpR = (interpR_i64 >> nbits) + ((interpR_i64 & 0xFFFF) * precision_1);
521 
522  const int64_t interpG_i64 = static_cast<int64_t>((t_1 * val00.G) + (t * val10.G));
523  const float interpG = (interpG_i64 >> nbits) + ((interpG_i64 & 0xFFFF) * precision_1);
524 
525  const int64_t interpB_i64 = static_cast<int64_t>((t_1 * val00.B) + (t * val10.B));
526  const float interpB = (interpB_i64 >> nbits) + ((interpB_i64 & 0xFFFF) * precision_1);
527 
528  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
529  vpMath::saturate<unsigned char>(interpB), aChannelVal);
530  }
531  else if (x_ < (src_width - 1)) {
532  const vpRGBa val00 = src[y_][x_];
533  const vpRGBa val01 = src[y_][x_ + 1];
534  const int64_t interpR_i64 = static_cast<int64_t>((s_1 * val00.R) + (s * val01.R));
535  const float interpR = (interpR_i64 >> nbits) + ((interpR_i64 & 0xFFFF) * precision_1);
536 
537  const int64_t interpG_i64 = static_cast<int64_t>((s_1 * val00.G) + (s * val01.G));
538  const float interpG = (interpG_i64 >> nbits) + ((interpG_i64 & 0xFFFF) * precision_1);
539 
540  const int64_t interpB_i64 = static_cast<int64_t>((s_1 * val00.B) + (s * val01.B));
541  const float interpB = (interpB_i64 >> nbits) + ((interpB_i64 & 0xFFFF) * precision_1);
542 
543  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
544  vpMath::saturate<unsigned char>(interpB), aChannelVal);
545  }
546  else {
547  dst[i][j] = src[y_][x_];
548  }
549  }
550 
551  xi += a0_i64;
552  yi += a3_i64;
553  }
554 
555  a2_i64 += a1_i64;
556  a5_i64 += a4_i64;
557  }
558  }
559  else {
560  unsigned int dst_height = dst.getHeight();
561  unsigned int dst_width = dst.getWidth();
562  int src_height = static_cast<int>(src.getHeight());
563  int src_width = static_cast<int>(src.getWidth());
564  const unsigned char aChannelVal = 255;
565  for (unsigned int i = 0; i < dst_height; ++i) {
566  int64_t xi = a2_i64;
567  int64_t yi = a5_i64;
568  int64_t wi = a8_i64;
569 
570  for (unsigned int j = 0; j < dst_width; ++j) {
571  if ((yi >= 0) && (yi <= ((src_height - 1) * wi)) && (xi >= 0) &&
572  (xi <= ((src_width - 1) * wi))) {
573  const float wi_ = (wi >> nbits) + ((wi & 0xFFFF) * precision_1);
574  const float xi_ = ((xi >> nbits) + ((xi & 0xFFFF) * precision_1)) / wi_;
575  const float yi_ = ((yi >> nbits) + ((yi & 0xFFFF) * precision_1)) / wi_;
576 
577  const int x_ = static_cast<int>(xi_);
578  const int y_ = static_cast<int>(yi_);
579 
580  const float t = yi_ - y_;
581  const float s = xi_ - x_;
582 
583  if ((y_ < (src_height - 1)) && (x_ < (src_width - 1))) {
584  const vpRGBa val00 = src[y_][x_];
585  const vpRGBa val01 = src[y_][x_ + 1];
586  const vpRGBa val10 = src[y_ + 1][x_];
587  const vpRGBa val11 = src[y_ + 1][x_ + 1];
588  const float colR0 = lerp(val00.R, val01.R, s);
589  const float colR1 = lerp(val10.R, val11.R, s);
590  const float interpR = lerp(colR0, colR1, t);
591 
592  const float colG0 = lerp(val00.G, val01.G, s);
593  const float colG1 = lerp(val10.G, val11.G, s);
594  const float interpG = lerp(colG0, colG1, t);
595 
596  const float colB0 = lerp(val00.B, val01.B, s);
597  const float colB1 = lerp(val10.B, val11.B, s);
598  const float interpB = lerp(colB0, colB1, t);
599 
600  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
601  vpMath::saturate<unsigned char>(interpB), aChannelVal);
602  }
603  else if (y_ < (src_height - 1)) {
604  const vpRGBa val00 = src[y_][x_];
605  const vpRGBa val10 = src[y_ + 1][x_];
606  const float interpR = lerp(val00.R, val10.R, t);
607  const float interpG = lerp(val00.G, val10.G, t);
608  const float interpB = lerp(val00.B, val10.B, t);
609 
610  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
611  vpMath::saturate<unsigned char>(interpB), aChannelVal);
612  }
613  else if (x_ < (src_width - 1)) {
614  const vpRGBa val00 = src[y_][x_];
615  const vpRGBa val01 = src[y_][x_ + 1];
616  const float interpR = lerp(val00.R, val01.R, s);
617  const float interpG = lerp(val00.G, val01.G, s);
618  const float interpB = lerp(val00.B, val01.B, s);
619 
620  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
621  vpMath::saturate<unsigned char>(interpB), aChannelVal);
622  }
623  else {
624  dst[i][j] = src[y_][x_];
625  }
626  }
627 
628  xi += a0_i64;
629  yi += a3_i64;
630  wi += a6_i64;
631  }
632 
633  a2_i64 += a1_i64;
634  a5_i64 += a4_i64;
635  a8_i64 += a7_i64;
636  }
637  }
638 
639 }
640 
641 template <>
642 inline void vpImageTools::warpLinear(const vpImage<vpRGBa> &src, const vpMatrix &T, vpImage<vpRGBa> &dst, bool affine,
643  bool centerCorner, bool fixedPoint)
644 {
645  const unsigned int index_0 = 0, index_1 = 1, index_2 = 2;
646  if (fixedPoint && (!centerCorner)) {
647  warpLinearFixedPointNotCenter(src, T, dst, affine);
648  }
649  else {
650  double a0 = T[index_0][index_0];
651  double a1 = T[index_0][index_1];
652  double a2 = T[index_0][index_2];
653  double a3 = T[index_1][index_0];
654  double a4 = T[index_1][index_1];
655  double a5 = T[index_1][index_2];
656  double a6 = affine ? 0.0 : T[index_2][index_0];
657  double a7 = affine ? 0.0 : T[index_2][index_1];
658  double a8 = affine ? 1.0 : T[index_2][index_2];
659 
660  unsigned int dst_height = dst.getHeight();
661  unsigned int dst_width = dst.getWidth();
662  int src_height = static_cast<int>(src.getHeight());
663  int src_width = static_cast<int>(src.getWidth());
664  const unsigned char aChannelVal = 255;
665  for (unsigned int i = 0; i < dst_height; ++i) {
666  for (unsigned int j = 0; j < dst_width; ++j) {
667  double x = (a0 * (centerCorner ? (j + 0.5) : j)) + (a1 * (centerCorner ? (i + 0.5) : i)) + a2;
668  double y = (a3 * (centerCorner ? (j + 0.5) : j)) + (a4 * (centerCorner ? (i + 0.5) : i)) + a5;
669  double w = (a6 * (centerCorner ? (j + 0.5) : j)) + (a7 * (centerCorner ? (i + 0.5) : i)) + a8;
670 
671  x = (x / w) - (centerCorner ? 0.5 : 0);
672  y = (y / w) - (centerCorner ? 0.5 : 0);
673 
674  int x_lower = static_cast<int>(x);
675  int y_lower = static_cast<int>(y);
676 
677  bool stop_for_loop = false;
678  if ((y_lower >= src_height) || (x_lower >= src_width) || (y < 0) || (x < 0)) {
679  stop_for_loop = true;
680  }
681  if (!stop_for_loop) {
682  double s = x - x_lower;
683  double t = y - y_lower;
684 
685  if ((y_lower < (src_height - 1)) && (x_lower < (src_width - 1))) {
686  const vpRGBa val00 = src[y_lower][x_lower];
687  const vpRGBa val01 = src[y_lower][x_lower + 1];
688  const vpRGBa val10 = src[y_lower + 1][x_lower];
689  const vpRGBa val11 = src[y_lower + 1][x_lower + 1];
690  const double colR0 = lerp(val00.R, val01.R, s);
691  const double colR1 = lerp(val10.R, val11.R, s);
692  const double interpR = lerp(colR0, colR1, t);
693 
694  const double colG0 = lerp(val00.G, val01.G, s);
695  const double colG1 = lerp(val10.G, val11.G, s);
696  const double interpG = lerp(colG0, colG1, t);
697 
698  const double colB0 = lerp(val00.B, val01.B, s);
699  const double colB1 = lerp(val10.B, val11.B, s);
700  const double interpB = lerp(colB0, colB1, t);
701 
702  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
703  vpMath::saturate<unsigned char>(interpB), aChannelVal);
704  }
705  else if (y_lower < (src_height - 1)) {
706  const vpRGBa val00 = src[y_lower][x_lower];
707  const vpRGBa val10 = src[y_lower + 1][x_lower];
708  const double interpR = lerp(val00.R, val10.R, t);
709  const double interpG = lerp(val00.G, val10.G, t);
710  const double interpB = lerp(val00.B, val10.B, t);
711 
712  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
713  vpMath::saturate<unsigned char>(interpB), aChannelVal);
714  }
715  else if (x_lower < (src_width - 1)) {
716  const vpRGBa val00 = src[y_lower][x_lower];
717  const vpRGBa val01 = src[y_lower][x_lower + 1];
718  const double interpR = lerp(val00.R, val01.R, s);
719  const double interpG = lerp(val00.G, val01.G, s);
720  const double interpB = lerp(val00.B, val01.B, s);
721 
722  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
723  vpMath::saturate<unsigned char>(interpB), aChannelVal);
724  }
725  else {
726  dst[i][j] = src[y_lower][x_lower];
727  }
728  }
729  }
730  }
731  }
732 }
733 
734 #endif
unsigned int getCols() const
Definition: vpArray2D.h:337
unsigned int getRows() const
Definition: vpArray2D.h:347
static void warpImage(const vpImage< Type > &src, const vpMatrix &T, vpImage< Type > &dst, const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST, bool fixedPointArithmetic=true, bool pixelCenter=false)
@ INTERPOLATION_NEAREST
Definition: vpImageTools.h:80
Definition of the vpImage class member functions.
Definition: vpImage.h:131
unsigned int getWidth() const
Definition: vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:542
unsigned int getSize() const
Definition: vpImage.h:221
unsigned int getHeight() const
Definition: vpImage.h:181
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
Definition: vpMath.h:111
static bool nul(double x, double threshold=0.001)
Definition: vpMath.h:449
static int round(double x)
Definition: vpMath.h:409
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix inverseByLU() const
Definition: vpRGBa.h:65
unsigned char B
Blue component.
Definition: vpRGBa.h:169
unsigned char R
Red component.
Definition: vpRGBa.h:167
unsigned char G
Green component.
Definition: vpRGBa.h:168