Issue 2134: removed obsolete raw highlight preservation setting from GUI (still left in procparams for backwards compatilibility)
This commit is contained in:
319
rtengine/klt/convolve.cc
Normal file
319
rtengine/klt/convolve.cc
Normal file
@@ -0,0 +1,319 @@
|
||||
/*********************************************************************
|
||||
* convolve.c
|
||||
*********************************************************************/
|
||||
|
||||
/* Standard includes */
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib> /* malloc(), realloc() */
|
||||
|
||||
/* Our includes */
|
||||
#include "base.h"
|
||||
#include "error.h"
|
||||
#include "convolve.h"
|
||||
#include "klt_util.h" /* printing */
|
||||
|
||||
#define MAX_KERNEL_WIDTH 71
|
||||
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
float data[MAX_KERNEL_WIDTH];
|
||||
} ConvolutionKernel;
|
||||
|
||||
/* Kernels */
|
||||
static ConvolutionKernel gauss_kernel;
|
||||
static ConvolutionKernel gaussderiv_kernel;
|
||||
static float sigma_last = -10.0;
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _KLTToFloatImage
|
||||
*
|
||||
* Given a pointer to image data (probably unsigned chars), copy
|
||||
* data to a float image.
|
||||
*/
|
||||
|
||||
void _KLTToFloatImage(
|
||||
KLT_PixelType *img,
|
||||
int ncols, int nrows,
|
||||
_KLT_FloatImage floatimg)
|
||||
{
|
||||
KLT_PixelType *ptrend = img + ncols*nrows;
|
||||
float *ptrout = floatimg->data;
|
||||
|
||||
/* Output image must be large enough to hold result */
|
||||
assert(floatimg->ncols >= ncols);
|
||||
assert(floatimg->nrows >= nrows);
|
||||
|
||||
floatimg->ncols = ncols;
|
||||
floatimg->nrows = nrows;
|
||||
|
||||
while (img < ptrend) *ptrout++ = (float) *img++;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _computeKernels
|
||||
*/
|
||||
|
||||
static void _computeKernels(
|
||||
float sigma,
|
||||
ConvolutionKernel *gauss,
|
||||
ConvolutionKernel *gaussderiv)
|
||||
{
|
||||
const float factor = 0.01f; /* for truncating tail */
|
||||
int i;
|
||||
|
||||
assert(MAX_KERNEL_WIDTH % 2 == 1);
|
||||
assert(sigma >= 0.0);
|
||||
|
||||
/* Compute kernels, and automatically determine widths */
|
||||
{
|
||||
const int hw = MAX_KERNEL_WIDTH / 2;
|
||||
float max_gauss = 1.0f, max_gaussderiv = (float) (sigma*exp(-0.5f));
|
||||
|
||||
/* Compute gauss and deriv */
|
||||
for (i = -hw ; i <= hw ; i++) {
|
||||
gauss->data[i+hw] = (float) exp(-i*i / (2*sigma*sigma));
|
||||
gaussderiv->data[i+hw] = -i * gauss->data[i+hw];
|
||||
}
|
||||
|
||||
/* Compute widths */
|
||||
gauss->width = MAX_KERNEL_WIDTH;
|
||||
for (i = -hw ; fabs(gauss->data[i+hw] / max_gauss) < factor ;
|
||||
i++, gauss->width -= 2);
|
||||
gaussderiv->width = MAX_KERNEL_WIDTH;
|
||||
for (i = -hw ; fabs(gaussderiv->data[i+hw] / max_gaussderiv) < factor ;
|
||||
i++, gaussderiv->width -= 2);
|
||||
if (gauss->width == MAX_KERNEL_WIDTH ||
|
||||
gaussderiv->width == MAX_KERNEL_WIDTH) {
|
||||
KLTError("(_computeKernels) MAX_KERNEL_WIDTH %d is too small for "
|
||||
"a sigma of %f", MAX_KERNEL_WIDTH, sigma);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shift if width less than MAX_KERNEL_WIDTH */
|
||||
for (i = 0 ; i < gauss->width ; i++)
|
||||
gauss->data[i] = gauss->data[i+(MAX_KERNEL_WIDTH-gauss->width)/2];
|
||||
for (i = 0 ; i < gaussderiv->width ; i++)
|
||||
gaussderiv->data[i] = gaussderiv->data[i+(MAX_KERNEL_WIDTH-gaussderiv->width)/2];
|
||||
/* Normalize gauss and deriv */
|
||||
{
|
||||
const int hw = gaussderiv->width / 2;
|
||||
float den;
|
||||
|
||||
den = 0.0;
|
||||
for (i = 0 ; i < gauss->width ; i++) den += gauss->data[i];
|
||||
for (i = 0 ; i < gauss->width ; i++) gauss->data[i] /= den;
|
||||
den = 0.0;
|
||||
for (i = -hw ; i <= hw ; i++) den -= i*gaussderiv->data[i+hw];
|
||||
for (i = -hw ; i <= hw ; i++) gaussderiv->data[i+hw] /= den;
|
||||
}
|
||||
|
||||
sigma_last = sigma;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _KLTGetKernelWidths
|
||||
*
|
||||
*/
|
||||
|
||||
void _KLTGetKernelWidths(
|
||||
float sigma,
|
||||
int *gauss_width,
|
||||
int *gaussderiv_width)
|
||||
{
|
||||
_computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel);
|
||||
*gauss_width = gauss_kernel.width;
|
||||
*gaussderiv_width = gaussderiv_kernel.width;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _convolveImageHoriz
|
||||
*/
|
||||
|
||||
static void _convolveImageHoriz(
|
||||
_KLT_FloatImage imgin,
|
||||
ConvolutionKernel kernel,
|
||||
_KLT_FloatImage imgout)
|
||||
{
|
||||
float *ptrrow = imgin->data; /* Points to row's first pixel */
|
||||
float *ptrout = imgout->data, /* Points to next output pixel */
|
||||
*ppp;
|
||||
float sum;
|
||||
int radius = kernel.width / 2;
|
||||
int ncols = imgin->ncols, nrows = imgin->nrows;
|
||||
int i, j, k;
|
||||
|
||||
/* Kernel width must be odd */
|
||||
assert(kernel.width % 2 == 1);
|
||||
|
||||
/* Must read from and write to different images */
|
||||
assert(imgin != imgout);
|
||||
|
||||
/* Output image must be large enough to hold result */
|
||||
assert(imgout->ncols >= imgin->ncols);
|
||||
assert(imgout->nrows >= imgin->nrows);
|
||||
|
||||
/* For each row, do ... */
|
||||
for (j = 0 ; j < nrows ; j++) {
|
||||
|
||||
/* Zero leftmost columns */
|
||||
for (i = 0 ; i < radius ; i++)
|
||||
*ptrout++ = 0.0;
|
||||
|
||||
/* Convolve middle columns with kernel */
|
||||
for ( ; i < ncols - radius ; i++) {
|
||||
ppp = ptrrow + i - radius;
|
||||
sum = 0.0;
|
||||
for (k = kernel.width-1 ; k >= 0 ; k--)
|
||||
sum += *ppp++ * kernel.data[k];
|
||||
*ptrout++ = sum;
|
||||
}
|
||||
|
||||
/* Zero rightmost columns */
|
||||
for ( ; i < ncols ; i++)
|
||||
*ptrout++ = 0.0;
|
||||
|
||||
ptrrow += ncols;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _convolveImageVert
|
||||
*/
|
||||
|
||||
static void _convolveImageVert(
|
||||
_KLT_FloatImage imgin,
|
||||
ConvolutionKernel kernel,
|
||||
_KLT_FloatImage imgout)
|
||||
{
|
||||
float *ptrcol = imgin->data; /* Points to row's first pixel */
|
||||
float *ptrout = imgout->data, /* Points to next output pixel */
|
||||
*ppp;
|
||||
float sum;
|
||||
int radius = kernel.width / 2;
|
||||
int ncols = imgin->ncols, nrows = imgin->nrows;
|
||||
int i, j, k;
|
||||
|
||||
/* Kernel width must be odd */
|
||||
assert(kernel.width % 2 == 1);
|
||||
|
||||
/* Must read from and write to different images */
|
||||
assert(imgin != imgout);
|
||||
|
||||
/* Output image must be large enough to hold result */
|
||||
assert(imgout->ncols >= imgin->ncols);
|
||||
assert(imgout->nrows >= imgin->nrows);
|
||||
|
||||
/* For each column, do ... */
|
||||
for (i = 0 ; i < ncols ; i++) {
|
||||
|
||||
/* Zero topmost rows */
|
||||
for (j = 0 ; j < radius ; j++) {
|
||||
*ptrout = 0.0;
|
||||
ptrout += ncols;
|
||||
}
|
||||
|
||||
/* Convolve middle rows with kernel */
|
||||
for ( ; j < nrows - radius ; j++) {
|
||||
ppp = ptrcol + ncols * (j - radius);
|
||||
sum = 0.0;
|
||||
for (k = kernel.width-1 ; k >= 0 ; k--) {
|
||||
sum += *ppp * kernel.data[k];
|
||||
ppp += ncols;
|
||||
}
|
||||
*ptrout = sum;
|
||||
ptrout += ncols;
|
||||
}
|
||||
|
||||
/* Zero bottommost rows */
|
||||
for ( ; j < nrows ; j++) {
|
||||
*ptrout = 0.0;
|
||||
ptrout += ncols;
|
||||
}
|
||||
|
||||
ptrcol++;
|
||||
ptrout -= nrows * ncols - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _convolveSeparate
|
||||
*/
|
||||
|
||||
static void _convolveSeparate(
|
||||
_KLT_FloatImage imgin,
|
||||
ConvolutionKernel horiz_kernel,
|
||||
ConvolutionKernel vert_kernel,
|
||||
_KLT_FloatImage imgout)
|
||||
{
|
||||
/* Create temporary image */
|
||||
_KLT_FloatImage tmpimg;
|
||||
tmpimg = _KLTCreateFloatImage(imgin->ncols, imgin->nrows);
|
||||
|
||||
/* Do convolution */
|
||||
_convolveImageHoriz(imgin, horiz_kernel, tmpimg);
|
||||
|
||||
_convolveImageVert(tmpimg, vert_kernel, imgout);
|
||||
|
||||
/* Free memory */
|
||||
_KLTFreeFloatImage(tmpimg);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _KLTComputeGradients
|
||||
*/
|
||||
|
||||
void _KLTComputeGradients(
|
||||
_KLT_FloatImage img,
|
||||
float sigma,
|
||||
_KLT_FloatImage gradx,
|
||||
_KLT_FloatImage grady)
|
||||
{
|
||||
|
||||
/* Output images must be large enough to hold result */
|
||||
assert(gradx->ncols >= img->ncols);
|
||||
assert(gradx->nrows >= img->nrows);
|
||||
assert(grady->ncols >= img->ncols);
|
||||
assert(grady->nrows >= img->nrows);
|
||||
|
||||
/* Compute kernels, if necessary */
|
||||
if (fabs(sigma - sigma_last) > 0.05)
|
||||
_computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel);
|
||||
|
||||
_convolveSeparate(img, gaussderiv_kernel, gauss_kernel, gradx);
|
||||
_convolveSeparate(img, gauss_kernel, gaussderiv_kernel, grady);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _KLTComputeSmoothedImage
|
||||
*/
|
||||
|
||||
void _KLTComputeSmoothedImage(
|
||||
_KLT_FloatImage img,
|
||||
float sigma,
|
||||
_KLT_FloatImage smooth)
|
||||
{
|
||||
/* Output image must be large enough to hold result */
|
||||
assert(smooth->ncols >= img->ncols);
|
||||
assert(smooth->nrows >= img->nrows);
|
||||
|
||||
/* Compute kernel, if necessary; gauss_deriv is not used */
|
||||
if (fabs(sigma - sigma_last) > 0.05)
|
||||
_computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel);
|
||||
|
||||
_convolveSeparate(img, gauss_kernel, gauss_kernel, smooth);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user