/**
* @file projection.c
* @brief projective transformation
* @author Patrick Roth - roth@stettbacher.ch
* @copyright Stettbacher Signal Processing AG
*
* @remarks
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
*/
#include
#include
#include
#include "color_pipe_private.h"
/**
* Pixel value interpolation of RGB image (8 bit per color channel).
* If a pixel coordinate with a fraction part is of interest, do interpolate the correct value from their neighbor's pixel.
*
* E. g. the pixel coordinate x/y = 1.8/2.3 gives the following weights:
* +------+------+
* | | |
* | 14% | 56% | 14% = 20%*70%, 56% = 80%*70%
* | | |
* +------+------+
* | | |
* | 6% | 24% | 6% = 20%*30%, 24% = 80%*30%
* | | |
* +------+------+
*
* The weights are applied to the neighors and the resulting pixel value is saved at the given location.
*
* NOTE
* The input and output image must have the same pixel size.
*
* @param img_out On return: image with interpolated values
* @param x saved interpolated pixel value at this x-coordinate
* @param y saved interpolated pixel value at this y-coordinate
* @param height image height of input and output image in number of pixels
* @param width image width of input and output image in number of pixels
* @param img_in input image to interpolate pixel values
* @param coord_x x-coordinate to interpolate
* @param coord_y y-coordinate to interpolate
* @param scale_fact coordinates are scaled by this factor
*/
static void interpolate_rgb8_scalar(uint8_t *img_out, const int x, const int y, const int height, const int width,
const uint8_t *img_in, const int coord_x, const int coord_y, const int scale_fact)
#include "alg_interpolate_rgb_scalar.h"
/**
* Pixel value interpolation of RGB image (16 bit per color channel).
* If a pixel coordinate with a fraction part is of interest, do interpolate the correct value from their neighbor's pixel.
*
* E. g. the pixel coordinate x/y = 1.8/2.3 gives the following weights:
* +------+------+
* | | |
* | 14% | 56% | 14% = 20%*70%, 56% = 80%*70%
* | | |
* +------+------+
* | | |
* | 6% | 24% | 6% = 20%*30%, 24% = 80%*30%
* | | |
* +------+------+
*
* The weights are applied to the neighors and the resulting pixel value is saved at the given location.
*
* NOTE
* The input and output image must have the same pixel size.
*
* @param img_out On return: image with interpolated values
* @param x saved interpolated pixel value at this x-coordinate
* @param y saved interpolated pixel value at this y-coordinate
* @param height image height of input and output image in number of pixels
* @param width image width of input and output image in number of pixels
* @param img_in input image to interpolate pixel values
* @param coord_x x-coordinate to interpolate
* @param coord_y y-coordinate to interpolate
* @param scale_fact coordinates are scaled by this factor
*/
static void interpolate_rgb16_scalar(uint16_t *img_out, const int x, const int y, const int height, const int width,
const uint16_t *img_in, const int coord_x, const int coord_y, const int scale_fact)
#include "alg_interpolate_rgb_scalar.h"
/**
* Pixel value interpolation of monochrome image (8 bit per pixel).
* If a pixel coordinate with a fraction part is of interest, do interpolate the correct value from their neighbor's pixel.
*
* E. g. the pixel coordinate x/y = 1.8/2.3 gives the following weights:
* +------+------+
* | | |
* | 14% | 56% | 14% = 20%*70%, 56% = 80%*70%
* | | |
* +------+------+
* | | |
* | 6% | 24% | 6% = 20%*30%, 24% = 80%*30%
* | | |
* +------+------+
*
* The weights are applied to the neighors and the resulting pixel value is saved at the given location.
*
* NOTE
* The input and output image must have the same pixel size.
*
* @param img_out On return: image with interpolated values
* @param x saved interpolated pixel value at this x-coordinate
* @param y saved interpolated pixel value at this y-coordinate
* @param height image height of input and output image in number of pixels
* @param width image width of input and output image in number of pixels
* @param img_in input image to interpolate pixel values
* @param coord_x x-coordinate to interpolate
* @param coord_y y-coordinate to interpolate
* @param scale_fact coordinates are scaled by this factor
*/
static void interpolate_mono8_scalar(uint8_t *img_out, const int x, const int y, const int height, const int width,
const uint8_t *img_in, const int coord_x, const int coord_y, const int scale_fact)
#include "alg_interpolate_mono_scalar.h"
/**
* Pixel value interpolation of monochrome image (16 bit per pixel).
* If a pixel coordinate with a fraction part is of interest, do interpolate the correct value from their neighbor's pixel.
*
* E. g. the pixel coordinate x/y = 1.8/2.3 gives the following weights:
* +------+------+
* | | |
* | 14% | 56% | 14% = 20%*70%, 56% = 80%*70%
* | | |
* +------+------+
* | | |
* | 6% | 24% | 6% = 20%*30%, 24% = 80%*30%
* | | |
* +------+------+
*
* The weights are applied to the neighors and the resulting pixel value is saved at the given location.
*
* NOTE
* The input and output image must have the same pixel size.
*
* @param img_out On return: image with interpolated values
* @param x saved interpolated pixel value at this x-coordinate
* @param y saved interpolated pixel value at this y-coordinate
* @param height image height of input and output image in number of pixels
* @param width image width of input and output image in number of pixels
* @param img_in input image to interpolate pixel values
* @param coord_x x-coordinate to interpolate
* @param coord_y y-coordinate to interpolate
* @param scale_fact coordinates are scaled by this factor
*/
static void interpolate_mono16_scalar(uint16_t *img_out, const int x, const int y, const int height, const int width,
const uint16_t *img_in, const int coord_x, const int coord_y, const int scale_fact)
#include "alg_interpolate_mono_scalar.h"
/**
* Apply projective transformaion.
*
* @param data projective transformation data
*/
static void apply_projection(struct projection_data_t *data) {
int x, y, x_corr, y_corr;
const int width = data->width;
const int height = data->height;
int bit_channel = data->bit_channel;
struct coord_t *map = data->map;
void *img_calib = data->img_out;
void *img_uncalib = data->img_in;
const int scale_fact = data->map_scale_fact;
const int is_color = data->is_color;
for(y = 0; y < height; y++) {
for(x = 0; x < width; x++) {
x_corr = map->x;
y_corr = map->y;
map++;
if(bit_channel <= 8) {
if(is_color) {
interpolate_rgb8_scalar(img_calib, x, y, height, width, img_uncalib, x_corr, y_corr, scale_fact);
}
else {
interpolate_mono8_scalar(img_calib, x, y, height, width, img_uncalib, x_corr, y_corr, scale_fact);
}
}
else if(bit_channel <= 16) {
if(is_color) {
interpolate_rgb16_scalar(img_calib, x, y, height, width, img_uncalib, x_corr, y_corr, scale_fact);
}
else {
interpolate_mono16_scalar(img_calib, x, y, height, width, img_uncalib, x_corr, y_corr, scale_fact);
}
}
}
}
}
/**
* Initialize perspective transformation map.
*
* @param data projective transformation data
*/
static void init_map(struct projection_data_t *data) {
int x, y;
struct coord_t *map = data->map;
const int scale_fact = (1 << (data->map_scale_fact));
const int width = data->width;
const int height = data->height;
float x_corr, y_corr;
const float c00 = data->c_inv[0][0];
const float c01 = data->c_inv[0][1];
const float c02 = data->c_inv[0][2];
const float c10 = data->c_inv[1][0];
const float c11 = data->c_inv[1][1];
const float c12 = data->c_inv[1][2];
const float c20 = data->c_inv[2][0];
const float c21 = data->c_inv[2][1];
const float c22 = data->c_inv[2][2];
for(y = 0; y < height; y++) {
for(x = 0; x < width; x++) {
x_corr = (c00*x+c01*y+c02)/(c20*x+c21*y+c22);
y_corr = (c10*x+c11*y+c12)/(c20*x+c21*y+c22);
// apply scaling factor
map->x = (int)roundf(x_corr*scale_fact);
map->y = (int)roundf(y_corr*scale_fact);
map++;
}
}
}
/**
* Apply projective transformation.
*
* @param data required data for projective transformation
* @return 0 on success otherwise -1
*/
int projection(struct projection_data_t *data) {
/*
* Create projective transformation map if needed.
*/
if(data->map_init == 0) {
data->map_scale_fact = 6; // scale by 9 means 2^6 = 64
init_map(data);
data->map_init = 1;
}
apply_projection(data);
return 0;
}