in opencv-kinfu-samples/main.cpp [280:356]
static void remap(const k4a_image_t src, const k4a_image_t lut, k4a_image_t dst, interpolation_t type)
{
int src_width = k4a_image_get_width_pixels(src);
int dst_width = k4a_image_get_width_pixels(dst);
int dst_height = k4a_image_get_height_pixels(dst);
uint16_t* src_data = (uint16_t*)(void*)k4a_image_get_buffer(src);
uint16_t* dst_data = (uint16_t*)(void*)k4a_image_get_buffer(dst);
coordinate_t* lut_data = (coordinate_t*)(void*)k4a_image_get_buffer(lut);
memset(dst_data, 0, (size_t)dst_width * (size_t)dst_height * sizeof(uint16_t));
for (int i = 0; i < dst_width * dst_height; i++)
{
if (lut_data[i].x != INVALID && lut_data[i].y != INVALID)
{
if (type == INTERPOLATION_NEARESTNEIGHBOR)
{
dst_data[i] = src_data[lut_data[i].y * src_width + lut_data[i].x];
}
else if (type == INTERPOLATION_BILINEAR || type == INTERPOLATION_BILINEAR_DEPTH)
{
const uint16_t neighbors[4]{ src_data[lut_data[i].y * src_width + lut_data[i].x],
src_data[lut_data[i].y * src_width + lut_data[i].x + 1],
src_data[(lut_data[i].y + 1) * src_width + lut_data[i].x],
src_data[(lut_data[i].y + 1) * src_width + lut_data[i].x + 1] };
// If the image contains invalid data, e.g. depth image contains value 0, ignore the bilinear
// interpolation for current target pixel if one of the neighbors contains invalid data to avoid
// introduce noise on the edge. If the image is color or ir images, user should use
// INTERPOLATION_BILINEAR
if (type == INTERPOLATION_BILINEAR_DEPTH)
{
// If the image contains invalid data, e.g. depth image contains value 0, ignore the bilinear
// interpolation for current target pixel if one of the neighbors contains invalid data to avoid
// introduce noise on the edge. If the image is color or ir images, user should use
// INTERPOLATION_BILINEAR
if (neighbors[0] == 0 || neighbors[1] == 0 || neighbors[2] == 0 || neighbors[3] == 0)
{
continue;
}
// Ignore interpolation at large depth discontinuity without disrupting slanted surface
// Skip interpolation threshold is estimated based on the following logic:
// - angle between two pixels is: theta = 0.234375 degree (120 degree / 512) in binning resolution
// mode
// - distance between two pixels at same depth approximately is: A ~= sin(theta) * depth
// - distance between two pixels at highly slanted surface (e.g. alpha = 85 degree) is: B = A /
// cos(alpha)
// - skip_interpolation_ratio ~= sin(theta) / cos(alpha)
// We use B as the threshold that to skip interpolation if the depth difference in the triangle is
// larger than B. This is a conservative threshold to estimate largest distance on a highly slanted
// surface at given depth, in reality, given distortion, distance, resolution difference, B can be
// smaller
const float skip_interpolation_ratio = 0.04693441759f;
float depth_min = min(min(neighbors[0], neighbors[1]), min(neighbors[2], neighbors[3]));
float depth_max = max(max(neighbors[0], neighbors[1]), max(neighbors[2], neighbors[3]));
float depth_delta = depth_max - depth_min;
float skip_interpolation_threshold = skip_interpolation_ratio * depth_min;
if (depth_delta > skip_interpolation_threshold)
{
continue;
}
}
dst_data[i] = (uint16_t)(neighbors[0] * lut_data[i].weight[0] + neighbors[1] * lut_data[i].weight[1] +
neighbors[2] * lut_data[i].weight[2] + neighbors[3] * lut_data[i].weight[3] +
0.5f);
}
else
{
printf("Unexpected interpolation type!\n");
exit(-1);
}
}
}
}