Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
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
54template <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
112template <class Type>
113void 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
233template <class Type>
234void 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
450inline 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 = static_cast<float>(interpR_i64 >> (nbits * 2)) + (static_cast<float>(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 = static_cast<float>(interpG_i64 >> (nbits * 2)) + (static_cast<float>(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 = static_cast<float>(interpB_i64 >> (nbits * 2)) + (static_cast<float>(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 = static_cast<float>(interpR_i64 >> nbits) + (static_cast<float>(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 = static_cast<float>(interpG_i64 >> nbits) + (static_cast<float>(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 = static_cast<float>(interpB_i64 >> nbits) + (static_cast<float>(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 = static_cast<float>(interpR_i64 >> nbits) + (static_cast<float>(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 = static_cast<float>(interpG_i64 >> nbits) + (static_cast<float>(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 = static_cast<float>(interpB_i64 >> nbits) + (static_cast<float>(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_ = static_cast<float>(wi >> nbits) + (static_cast<float>(wi & 0xFFFF) * precision_1);
574 const float xi_ = (static_cast<float>(xi >> nbits) + (static_cast<float>(xi & 0xFFFF) * precision_1)) / wi_;
575 const float yi_ = (static_cast<float>(yi >> nbits) + (static_cast<float>(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_ - static_cast<float>(y_);
581 const float s = xi_ - static_cast<float>(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
641template <>
642inline 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
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
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
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:423
unsigned int getRows() const
Definition vpArray2D.h:433
static void warpImage(const vpImage< Type > &src, const vpMatrix &T, vpImage< Type > &dst, const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST, bool fixedPointArithmetic=true, bool pixelCenter=false)
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:544
unsigned int getSize() const
Definition vpImage.h:221
unsigned int getHeight() const
Definition vpImage.h:181
static Tp saturate(unsigned char v)
Definition vpMath.h:306
static bool nul(double x, double threshold=0.001)
Definition vpMath.h:453
static int round(double x)
Definition vpMath.h:413
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
vpMatrix inverseByLU() const
unsigned char B
Blue component.
Definition vpRGBa.h:327
unsigned char R
Red component.
Definition vpRGBa.h:325
unsigned char G
Green component.
Definition vpRGBa.h:326