Created
June 6, 2020 17:22
-
-
Save laurelkeys/6bdcdeb0ced6f9d3af519c87c8d980c0 to your computer and use it in GitHub Desktop.
Pixel sampling with bilinear interpolation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Bilinear interpolation. | |
| static Color3f blerp( | |
| const Image& image, | |
| const std::size_t x0, const std::size_t y0, | |
| const std::size_t x1, const std::size_t y1, | |
| const float fx, const float fy | |
| ) { | |
| // Compute weights: | |
| const float wx1 = fx - x0; | |
| const float wy1 = fy - y0; | |
| const float wx0 = 1.0f - wx1; | |
| const float wy0 = 1.0f - wy1; | |
| return pixel_at(image, x0, y0) * wx0 * wy0 | |
| + pixel_at(image, x1, y0) * wx1 * wy0 | |
| + pixel_at(image, x0, y1) * wx0 * wy1 | |
| + pixel_at(image, x1, y1) * wx1 * wy1; | |
| } | |
| // Returns the weighted average of the four pixels closest to the image coordinate (fx, fy). | |
| static Color3f box_sample(const Image& image, const float fx, const float fy) { | |
| const std::size_t x0 = static_cast<std::size_t>(fx); | |
| const std::size_t y0 = static_cast<std::size_t>(fy); | |
| const std::size_t x1 = std::min<std::size_t>(x0 + 1, image.width - 1); | |
| const std::size_t y1 = std::min<std::size_t>(y0 + 1, image.height - 1); | |
| return blerp(image, x0, y0, x1, y1, fx, fy); | |
| } | |
| // Returns the weighted average of the four pixels closest to the image coordinate (fx, fy). | |
| // Samples the edge-most pixels when coordinates are outside the image (i.e. texture clamping). | |
| static Color3f clamped_box_sample(const Image& image, const float fx, const float fy) { | |
| // Compute to which region the coordinate (fx, fy) belongs: | |
| const int x_region = (fx < 0.0f) ? -1 : (fx <= image.width - 1.0f) ? 0 : +1; | |
| const int y_region = (fy < 0.0f) ? -1 : (fy <= image.height - 1.0f) ? 0 : +1; | |
| // There are 9 regions relative to the image, with 3 base cases: | |
| // -+ 0+ ++ inside: 00 | |
| // -0 00 +0 outside lateral: 0+, -0, +0, 0- | |
| // -- 0- +- outside diagonal: -+, ++, --, +- | |
| // Thus, we can easily check (fx, fy)'s region, and clamp it to be inside the image: | |
| const std::size_t cx = static_cast<std::size_t>((x_region == -1) ? 0 : image.width - 1); | |
| const std::size_t cy = static_cast<std::size_t>((y_region == -1) ? 0 : image.height - 1); | |
| if (x_region * y_region != 0) | |
| return pixel_at(image, cx, cy); | |
| const std::size_t x0 = static_cast<std::size_t>(fx); | |
| const std::size_t y0 = static_cast<std::size_t>(fy); | |
| const std::size_t x1 = std::min<std::size_t>(x0 + 1, image.width - 1); | |
| const std::size_t y1 = std::min<std::size_t>(y0 + 1, image.height - 1); | |
| if (x_region != 0) | |
| return lerp(pixel_at(image, cx, y0), pixel_at(image, cx, y1), fy - y0); | |
| else if (y_region != 0) | |
| return lerp(pixel_at(image, x0, cy), pixel_at(image, x1, cy), fy - y0); | |
| else // inside the image | |
| return blerp(image, x0, y0, x1, y1, fx, fy); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment