Skip to content

Instantly share code, notes, and snippets.

@laurelkeys
Created June 6, 2020 17:22
Show Gist options
  • Select an option

  • Save laurelkeys/6bdcdeb0ced6f9d3af519c87c8d980c0 to your computer and use it in GitHub Desktop.

Select an option

Save laurelkeys/6bdcdeb0ced6f9d3af519c87c8d980c0 to your computer and use it in GitHub Desktop.
Pixel sampling with bilinear interpolation.
// 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