/**
* @file trapcorr.c
* @brief isosceles trapeze correction algorithm
* @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 iosceles trapez correction.
*
* @param data correction data
*/
static void correct(struct trapcorr_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);
}
}
}
}
}
/**
* Initialze perspective correction map.
*
* @param data required correction data
*/
static void init_map(struct trapcorr_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 p, p_i, row_scale, x_corr, y_corr;
int x_start, x_end;
int shrink_upper;
// convert -100.0...+100.0 ---> 0.0...2.0
const float fact = data->wh/100.0f+1.0f;
/*
* Checking whether we shrink upper or lower horizontal
* trapeze line.
*/
if(data->wh <= 1.0f) {
// upper line shrinks
shrink_upper = 1;
p = fact * (width/2.0f);
}
else {
// lower line shrinks
shrink_upper = 0;
p = (2.0f - fact) * (width/2.0f);
}
/*
* We'll loop through image with y-axis symmetrically centered.
* So the image is horizontally shifted to left. Do calculate
* the start and end values on x-axis.
*/
if((width%2) == 0) {
// even width
x_start = (-1)*width/2;
x_end = width/2-1;
}
else {
// odd width
x_start = (-1)*(width-1)/2;
x_end = (width-1)/2;
}
// loop through image
for(y = 0; y < height; y++) {
if(shrink_upper) {
p_i = ((width/2.0f - p) / height) * y + p;
}
else {
p_i = (-1.0f*((width/2.0f - p) / height)) * y + width/2.0f;
}
row_scale = 2.0f * p_i / width;
// we don't correct vertically
y_corr = y;
for(x = x_start; x <= x_end; x++) {
x_corr = x/row_scale;
// trapeze is horizontally symmetrically centered --> shift right
x_corr -= x_start;
// apply scaling factor
map->x = (int)roundf(x_corr*scale_fact);
map->y = (int)roundf(y_corr*scale_fact);
map++;
}
}
}
/**
* Apply iosceles trapez correction to given image type.
*
* @param trapcorr_data required data for trapez correction
* @return 0 on success otherwise -1
*/
int trapcorr(struct trapcorr_data_t *trapcorr_data) {
/*
* Create perspective correction map if needed.
*/
if(trapcorr_data->map_init == 0) {
trapcorr_data->map_scale_fact = 9; // scale by 9 means 2^9 = 512
init_map(trapcorr_data);
trapcorr_data->map_init = 1;
}
// apply perspective correction
correct(trapcorr_data);
return 0;
}