blob: 821e7af473251ff1879437d512ff3aca37515de7 [file] [log] [blame]
#ifndef LAYERED_FILTER_F32_HELPER_RSH
#define LAYERED_FILTER_F32_HELPER_RSH
#include "pixel_format_f32.rsh"
#include "luts_for_speedup_f32.rsh"
// Several supporting functions that are called by kernel functions defined in
// layered_filter_f32.rs for refocus rendering.
// For the following supporting functions, the input arguments have the
// following meaning:
//
// @param x x-coordinate of a pixel in a padded image.
// @param y y-coordinate of a pixel in a padded image.
// A function that visits neighboring pixels around (x,y) and finds the closest
// active pixel to (x,y). Sets the closest distance to sharp->matte and sets the
// depth of the closest pixel to sharp->dilated_depth.
// When this function is called, the initial value of sharp->dilated_depth is
// sharp->actual_depth and must be non-zero. However, sharp->actual_depth may or
// may not be in the depth range of the target layer.
static inline void ComputeLayerMatteHelper(SharpPixelF32_t *sharp, uint32_t x,
uint32_t y,
const ImageSize_t *image_size,
const int dilation_radius) {
const int kernel_center_x = dilation_radius;
const int kernel_center_y = dilation_radius;
const int kernel_dim_x = 2 * kernel_center_x + 1;
// Initializes the minimum distance from this pixel to the active pixels on
// this layer.
int min_dist = dilation_radius + 1;
min_dist *= min_dist; // Prepares for L2 distance.
int depth = sharp->actual_depth;
const SharpPixelF32_t *sharp_nbr =
sharp - kernel_center_y * image_size->width - kernel_center_x;
const int jump_to_next_pixel = 1;
const int jump_to_next_row = image_size->width - kernel_dim_x;
for (int j = -kernel_center_y; j <= kernel_center_y; ++j) {
for (int i = -kernel_center_x; i <= kernel_center_x; ++i) {
// L_2 distance:
int this_dist = i * i + j * j;
// Whether or not this is an active pixel with a smaller distance.
int cond = (sharp_nbr->active && this_dist < min_dist);
// Updates min_dist and corresponding depth.
min_dist = cond ? this_dist : min_dist;
depth = cond ? sharp_nbr->actual_depth : depth;
sharp_nbr += jump_to_next_pixel;
}
sharp_nbr += jump_to_next_row;
}
// Converts min_dist to a matte value.
sharp->matte = (uchar)(dilation_radius + 1 - (int)half_sqrt((float)min_dist));
// If sharp->matte > 0, depth must be within the depth range of this layer.
sharp->dilated_depth = (uchar)depth;
}
// Filters target layer when processing layers in pass one from the back-most to
// the sharp depth.
static inline FuzzyPixelF32_t FilterLayerBehindFocalDepthHelper(
uint32_t x, uint32_t y, const ImageSize_t *image_size,
const LayerInfo_t *layer_info, const KernelInfo_t *kernel_info,
const float *kernel_stack, const SharpPixelF32_t *sharp_image,
const VisibilityProbability_t *visibility_probability) {
FuzzyPixelF32_t result = {0.0f, 0.0f, 0.0f, 0.0f};
// Extracts kernel matrix from kernel stack using kernel_info.
const int kernel_center_x = kernel_info->radius_x;
const int kernel_center_y = kernel_info->radius_y;
const int kernel_dim_x = 2 * kernel_center_x + 1;
const float *kernel = kernel_stack + kernel_info->offset;
// Gets the visibility probability lookup table for the target layer depth.
const float *vis_prob = visibility_probability->lut[layer_info->front_depth];
// Locates the top left corner of the window surrounding this pixel.
const SharpPixelF32_t *sharp_nbr = sharp_image +
(y - kernel_center_y) * image_size->width +
(x - kernel_center_x);
// Filters over the window.
const int jump_to_next_pixel = 1;
const int jump_to_next_row = image_size->width - kernel_dim_x;
for (int j = -kernel_center_y; j <= kernel_center_y; ++j) {
for (int i = -kernel_center_x; i <= kernel_center_x; ++i) {
// Filters only using pixels on or behind this layer to avoid color
// bleeding from layers in front of this layer. Doing visibility test in a
// soft way using a probability set in a heuristic way.
const float v_p = vis_prob[sharp_nbr->actual_depth];
const float weight = v_p * (*kernel);
result.red += weight * sharp_nbr->red;
result.green += weight * sharp_nbr->green;
result.blue += weight * sharp_nbr->blue;
result.alpha += weight;
kernel++;
sharp_nbr += jump_to_next_pixel;
}
sharp_nbr += jump_to_next_row;
}
// Normalizes and returns the result.
float factor = 1.0f / result.alpha;
result.red *= factor;
result.green *= factor;
result.blue *= factor;
result.alpha = 1.0f;
return result;
}
// Filters target layer when processing layers in pass one from the back-most to
// the sharp depth.
static inline FuzzyPixelF32_t FilterLayerUsingRowwiseIntegralImage(
uint32_t x, uint32_t y, const ImageSize_t *image_size,
const KernelInfo_t *kernel_info, const float4 *integral_image,
const SecantOffset_t *secant_offset) {
float4 result = {0.0f, 0.0f, 0.0f, 0.0f};
// Extracts kernel matrix from kernel stack using kernel_info.
const int kernel_radius_y = kernel_info->radius_y;
const int *radius_lut =
secant_offset->lut[kernel_radius_y] + g_kMaxKernelRadius;
// Locates the top left corner of the window surrounding this pixel.
const float4 *integral_pixel =
integral_image + (y - kernel_radius_y) * image_size->width + x;
// Filters over the window.
const int jump_to_next_row = image_size->width;
for (int j = -kernel_radius_y; j <= kernel_radius_y; ++j) {
const int kernel_radius_x_at_y = radius_lut[j];
result += integral_pixel[kernel_radius_x_at_y] -
integral_pixel[-kernel_radius_x_at_y - 1];
integral_pixel += jump_to_next_row;
}
// Normalizes and returns the result.
FuzzyPixelF32_t fuzzy;
float factor = 1.0f / result.a;
fuzzy.red = result.r * factor;
fuzzy.green = result.g * factor;
fuzzy.blue = result.b * factor;
fuzzy.alpha = 1.0f;
return fuzzy;
}
// Filters the target layer when processing layers in pass two from the
// front-most to the focus depth.
static inline FuzzyPixelF32_t FilterLayerInFrontOfFocalDepthHelper(
uint32_t x, uint32_t y, const ImageSize_t *image_size,
const KernelInfo_t *kernel_info, const float *kernel_stack,
const SharpPixelF32_t *sharp_image) {
FuzzyPixelF32_t result = {0.f, 0.f, 0.f, 0.f};
// Extracts kernel matrix from kernel stack using kernel_info.
const int kernel_center_x = kernel_info->radius_x;
const int kernel_center_y = kernel_info->radius_y;
const int kernel_dim_x = 2 * kernel_center_x + 1;
const float *kernel = kernel_stack + kernel_info->offset;
// Locates the top left corner of the window surrounding this pixel.
const int index =
(y - kernel_center_y) * image_size->width + (x - kernel_center_x);
const SharpPixelF32_t *sharp_nbr = sharp_image + index;
// Filters over the window.
const int jump_to_next_pixel = 1;
const int jump_to_next_row = image_size->width - kernel_dim_x;
for (int j = -kernel_center_y; j <= kernel_center_y; ++j) {
for (int i = -kernel_center_x; i <= kernel_center_x; ++i) {
// Filters only using pixels with valid depth values (i.e. excluding
// padded pixels).
const float flag = ValidDepth(sharp_nbr->actual_depth);
const float weight = flag * (*kernel);
result.red += weight * sharp_nbr->red;
result.green += weight * sharp_nbr->green;
result.blue += weight * sharp_nbr->blue;
result.alpha += weight;
kernel++;
sharp_nbr += jump_to_next_pixel;
}
sharp_nbr += jump_to_next_row;
}
// Normalizes and returns the result
float fac = 1.0f / result.alpha;
result.red *= fac;
result.green *= fac;
result.blue *= fac;
result.alpha = 1.0f;
return result;
}
static void ResetSharpImage(SharpPixelF32_t *sharp_image, int num_pixels) {
const SharpPixelF32_t *last_p = sharp_image + num_pixels;
for (SharpPixelF32_t *p = sharp_image; p != last_p; ++p) {
p->red = 0;
p->green = 0;
p->blue = 0;
p->active = 0;
p->dilated_depth = 0;
p->actual_depth = 0;
p->matte = 0;
}
}
static void ResetIntegralImage(float4 *integral_image, int num_pixels) {
const float4 *last_p = integral_image + num_pixels;
for (float4 *p = integral_image; p != last_p; ++p) {
*p = 0;
}
}
static void ResetFuzzyImage(FuzzyPixelF32_t *fuzzy_image, int num_pixels) {
const FuzzyPixelF32_t *last_p = fuzzy_image + num_pixels;
for (FuzzyPixelF32_t *p = fuzzy_image; p != last_p; ++p) {
p->red = 0;
p->green = 0;
p->blue = 0;
p->alpha = 0;
}
}
#endif