diff --git a/ChangeLog b/ChangeLog index 8b630c24115b943538bba56ea8b781ac6af00562..6e0128207a2d2c97c4fca306b3440c42f8ff552d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Version 1.1.0 2021-07-01 PR - horizontal isosceles trapeze perspective correction added + - perspective transformation added Version 1.0.2 2019-10-16 PR diff --git a/color_pipe.c b/color_pipe.c index b0a9ddfe600e3d42f64c31bcfa1a81aa7fa5515d..3c4200f3b2e251d0434bc4e810a5fb649b225018 100644 --- a/color_pipe.c +++ b/color_pipe.c @@ -400,6 +400,20 @@ static void set_default_value(struct color_pipe_t *pipe) { pipe->trapcorr_data.wh = 0.0f; pipe->trapcorr_data.wv_new = pipe->trapcorr_data.wv; pipe->trapcorr_data.wh_new = pipe->trapcorr_data.wh; + + pipe->proj_data.enable = 0; + pipe->proj_data.map_init = 0; + pipe->proj_data.c_inv[0][0] = 1.0f; // use identity matrix + pipe->proj_data.c_inv[0][1] = 0.0f; + pipe->proj_data.c_inv[0][2] = 0.0f; + pipe->proj_data.c_inv[1][0] = 0.0f; + pipe->proj_data.c_inv[1][1] = 1.0f; + pipe->proj_data.c_inv[1][2] = 0.0f; + pipe->proj_data.c_inv[2][0] = 0.0f; + pipe->proj_data.c_inv[2][1] = 0.0f; + pipe->proj_data.c_inv[2][2] = 1.0f; + memcpy(pipe->proj_data.c_inv_new, pipe->proj_data.c_inv, sizeof(pipe->proj_data.c_inv)); + pipe->proj_data.c_upd = 0; } @@ -463,7 +477,7 @@ void __stdcall color_pipe_process(struct color_pipe_t *__restrict__ color_pipe, #ifdef DEBUG_PROC_TIME uint64_t ts_start = get_ts(); - uint64_t ts_debayer, ts_awb, ts_calib, ts_ccm, ts_sharp, ts_gamma, ts_trapcorr; + uint64_t ts_debayer, ts_awb, ts_calib, ts_ccm, ts_sharp, ts_gamma, ts_trapcorr, ts_projection; #endif // DEBUG_PROC_TIME /* @@ -714,6 +728,40 @@ void __stdcall color_pipe_process(struct color_pipe_t *__restrict__ color_pipe, #endif // DEBUG_PROC_TIME + /* + * Pipeline stage: Projective transformation + */ + if(color_pipe->proj_data.enable) { + + // auto-reinit perspective correction map if image format, resolution or weights have changed + if( color_pipe->proj_data.bit_channel != bit_channel || + color_pipe->proj_data.width != width || + color_pipe->proj_data.height != height) { + + color_pipe->proj_data.map_init = 0; + } + + // apply user parameter (double buffered) + if(color_pipe->proj_data.c_upd) { + memcpy(color_pipe->proj_data.c_inv, color_pipe->proj_data.c_inv_new, sizeof(color_pipe->proj_data.c_inv)); + color_pipe->proj_data.c_upd = 0; + color_pipe->proj_data.map_init = 0; + } + + color_pipe->proj_data.img_in = img_out; + color_pipe->proj_data.is_color = is_color; + color_pipe->proj_data.bit_channel = bit_channel; + color_pipe->proj_data.width = width; + color_pipe->proj_data.height = height; + + projection(&(color_pipe->proj_data)); + + img_out = color_pipe->proj_data.img_out; + } +#ifdef DEBUG_PROC_TIME + ts_projection = get_ts(); +#endif // DEBUG_PROC_TIME + /* * Return processed image depending on active pipeline stages. @@ -726,13 +774,14 @@ void __stdcall color_pipe_process(struct color_pipe_t *__restrict__ color_pipe, #ifdef DEBUG_PROC_TIME - printf(" debayer: %lld msec\n", ts_debayer - ts_start); - printf(" awb: %lld msec\n", ts_awb - ts_debayer); - printf(" camera calib: %lld msec\n", ts_calib - ts_awb); - printf(" color correction: %lld msec\n", ts_ccm - ts_calib); - printf(" sharpening: %lld msec\n", ts_sharp - ts_ccm); - printf(" gamma: %lld msec\n", ts_gamma - ts_sharp); - printf(" trapeze correction: %lld msec\n", ts_trapcorr - ts_sharp); + printf(" debayer: %lld msec\n", ts_debayer - ts_start); + printf(" awb: %lld msec\n", ts_awb - ts_debayer); + printf(" camera calib: %lld msec\n", ts_calib - ts_awb); + printf(" color correction: %lld msec\n", ts_ccm - ts_calib); + printf(" sharpening: %lld msec\n", ts_sharp - ts_ccm); + printf(" gamma: %lld msec\n", ts_gamma - ts_sharp); + printf(" trapeze correction: %lld msec\n", ts_trapcorr - ts_gamma); + printf(" projective transformation: %lld msec\n", ts_projection - ts_trapcorr); #endif // DEBUG_PROC_TIME } @@ -916,6 +965,42 @@ void __stdcall color_pipe_stageconf_trapcorr(struct color_pipe_t *color_pipe, in } +/** + * Pipeline stage configuration: projection transformation + * + * Project point p to p' using the the projection matrix C + * with homogeneous coordinates. + * + * t * p' = C * p + * + * where: + * / u \ / x \ + * p' = | v | p = | y | t = scaling factor + * \ 1 / \ 1 / + * + * + * / c00 c01 c02 \ + * C = | c10 c11 c12 | + * \ c20 c21 c22 / + * + * p': projected points + * p: point to be projected + * C: projection matrix + * + * The color-pipe requires the invers of matrix C because + * an inverse mapping is implemented. + * + * @param color_pipe Pointer to pipeline context + * @param enable not 0: enable, 0: disable + * @param c_inv inverse of 3x3 projection matrix C + */ +void __stdcall color_pipe_stageconf_projection(struct color_pipe_t *color_pipe, int enable, float c_inv[3][3]) { + memcpy(color_pipe->proj_data.c_inv_new, c_inv, sizeof(color_pipe->proj_data.c_inv_new)); + color_pipe->proj_data.c_upd = 1; + color_pipe->proj_data.enable = enable; +} + + /** * Open color image processing pipeline. * This function allocates memory for various pipe algorithm. The pipeline is set up for a maximum possible image size defined @@ -1072,6 +1157,18 @@ int __stdcall color_pipe_open(struct color_pipe_t **color_pipe, const int max_im goto _pipe_open_abort; } + // allocate memory for projective transformation + data->proj_data.img_out = do_aligned_alloc(ALIGNMENT_SIZE, max_img_size, __func__, __LINE__-1); + if(data->proj_data.img_out == NULL) { + goto _pipe_open_abort; + } + data->proj_data.map = do_aligned_alloc(ALIGNMENT_SIZE, + sizeof(struct coord_t)*max_img_height*max_img_width, + __func__, __LINE__-1); + if(data->proj_data.map == NULL) { + goto _pipe_open_abort; + } + // set suitable and valid defaults set_default_value(data); *color_pipe = data; @@ -1120,6 +1217,8 @@ int __stdcall color_pipe_close(struct color_pipe_t *data) { do_aligned_free(data->gamma_data.gamma_table); do_aligned_free(data->trapcorr_data.img_out); do_aligned_free(data->trapcorr_data.map); + do_aligned_free(data->proj_data.img_out); + do_aligned_free(data->proj_data.map); // free various image buffers free(data); diff --git a/color_pipe.h b/color_pipe.h index 9b52f2334bc382131a32b1dc0f5ad10d050c3b92..26b229b83ac7083a2419d51765b5affcd5bb9379 100644 --- a/color_pipe.h +++ b/color_pipe.h @@ -317,6 +317,40 @@ struct trapcorr_data_t { }; +/** + * Projective transformation definition + */ +struct projection_data_t { + int enable; ///< flag to enable projective transformation + void *img_out; ///< projected image. This buffer must be allocated externly. + void *img_in; ///< Input image. + int is_color; ///< Not 0 if it's a color image + int bit_channel; ///< Bits per color channel. + int width; ///< image width in number of pixels + int height; ///< image height in number of pixels + float c_inv[3][3]; ///< inverse of 3x3 projection matrix C + float c_inv_new[3][3]; ///< double buffered matrix + int c_upd; ///< projection matrix update flag + + int map_init; ///< flag indicating transformation map is initialized + + /** + * projective transfomration map + * A coordinate pair defines the transformed pixel location. It may be shifted (see @ref map_scale_fact). + * + * This buffer must be allocated externly. + */ + struct coord_t *map; + + /** + * Bit shift applied on correction map @ref map. + * The pixel location may lay between a pixel pair. Therefore the coordinates defined at the map + * @ref map are (scaled) shifted by this factor. + */ + int map_scale_fact; +}; + + /** * Color pipe definition structure holding all memory data from different pipeline * stages. This structure and image buffers are allocated dynamically. @@ -336,6 +370,7 @@ struct color_pipe_t { struct sharp_data_t sharp_data; ///< image sharpening data struct gamma_data_t gamma_data; ///< gamma correction data struct trapcorr_data_t trapcorr_data; ///< isosceles trapezoid correction data + struct projection_data_t proj_data; ///< projective transformation data }; @@ -356,6 +391,7 @@ void __stdcall color_pipe_stageconf_color_calib(struct color_pipe_t *color_pipe, void __stdcall color_pipe_stageconf_sharp(struct color_pipe_t *color_pipe, int enable, float factor, enum sharp_alg_t alg, float sens); void __stdcall color_pipe_stageconf_gamma(struct color_pipe_t *color_pipe, int enable, float gamma); void __stdcall color_pipe_stageconf_trapcorr(struct color_pipe_t *color_pipe, int enable, float wv, float wh); +void __stdcall color_pipe_stageconf_projection(struct color_pipe_t *color_pipe, int enable, float c_inv[3][3]); #if defined(__cplusplus) || defined(c_plusplus) } // extern "C" diff --git a/color_pipe_private.h b/color_pipe_private.h index b2954ac54bce88f703aa6d700a9aa732555915c4..431158b4a6d054440422b8c8582bba23df0c7621 100644 --- a/color_pipe_private.h +++ b/color_pipe_private.h @@ -49,6 +49,8 @@ int gamma_corr(struct gamma_data_t *gamma_data); int trapcorr(struct trapcorr_data_t *trapcorr_data); +int projection(struct projection_data_t *data); + #if defined(__cplusplus) || defined(c_plusplus) } // extern "C" #endif diff --git a/projection.c b/projection.c new file mode 100644 index 0000000000000000000000000000000000000000..c3742af0987bfcb550216c9fb98d9d243746c728 --- /dev/null +++ b/projection.c @@ -0,0 +1,272 @@ +/** +* @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