Bilinear resize of a [H, W, 3] uint8 image to [dst_h, dst_w, 3].
| 3443 | |
| 3444 | // Bilinear resize of a [H, W, 3] uint8 image to [dst_h, dst_w, 3]. |
| 3445 | static void sam3_resize_bilinear(const uint8_t* src, int src_w, int src_h, |
| 3446 | uint8_t* dst, int dst_w, int dst_h) { |
| 3447 | // Bilinear resize matching torch.nn.functional.interpolate(bilinear, align_corners=False). |
| 3448 | // ALL arithmetic is in double to get an exact result for uint8 inputs (0-255), |
| 3449 | // ensuring the bilinear result is independent of FMA/SIMD/compiler behavior. |
| 3450 | // The exact double result is then rounded to uint8, matching torch's round(). |
| 3451 | const double sx = (double)src_w / dst_w; |
| 3452 | const double sy = (double)src_h / dst_h; |
| 3453 | for (int y = 0; y < dst_h; ++y) { |
| 3454 | double fy = (y + 0.5) * sy - 0.5; |
| 3455 | if (fy < 0.0) fy = 0.0; |
| 3456 | const int y0 = (int)fy; |
| 3457 | const int y1 = (y0 < src_h - 1) ? y0 + 1 : y0; |
| 3458 | const double wy = fy - y0; |
| 3459 | const double wy0 = 1.0 - wy; |
| 3460 | for (int x = 0; x < dst_w; ++x) { |
| 3461 | double fx = (x + 0.5) * sx - 0.5; |
| 3462 | if (fx < 0.0) fx = 0.0; |
| 3463 | const int x0 = (int)fx; |
| 3464 | const int x1 = (x0 < src_w - 1) ? x0 + 1 : x0; |
| 3465 | const double wx = fx - x0; |
| 3466 | const double wx0 = 1.0 - wx; |
| 3467 | for (int c = 0; c < 3; ++c) { |
| 3468 | const double p00 = src[(y0 * src_w + x0) * 3 + c]; |
| 3469 | const double p01 = src[(y0 * src_w + x1) * 3 + c]; |
| 3470 | const double p10 = src[(y1 * src_w + x0) * 3 + c]; |
| 3471 | const double p11 = src[(y1 * src_w + x1) * 3 + c]; |
| 3472 | double v = wy0 * (wx0 * p00 + wx * p01) + |
| 3473 | wy * (wx0 * p10 + wx * p11); |
| 3474 | // Round to nearest integer, matching torch's round().to(uint8). |
| 3475 | // For exact half-values (v = N.5), torch uses banker's rounding |
| 3476 | // (round-half-to-even), but bilinear with double precision on |
| 3477 | // uint8 inputs virtually never hits exact halves. |
| 3478 | int iv = (int)(v + 0.5); |
| 3479 | if (iv < 0) iv = 0; |
| 3480 | if (iv > 255) iv = 255; |
| 3481 | dst[(y * dst_w + x) * 3 + c] = (uint8_t)iv; |
| 3482 | } |
| 3483 | } |
| 3484 | } |
| 3485 | } |
| 3486 | |
| 3487 | // Preprocess an image: resize to img_size × img_size, convert to float, normalize. |
| 3488 | // Returns a float tensor in [C, H, W] layout (channel-first), range normalized with |
no outgoing calls
no test coverage detected