deriche_o3opt.c
/*
* Copyright (c) 2016, Anmol Popli <anmol.ap020@gmail.com>
* All rights reserved.
*
* This program is free software: you can use, modify and/or
* redistribute it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later
* version. You should have received a copy of this license along
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file deriche_o3opt.c
* @brief Fast gaussian filter using deriche IIR approximation of O(3)
*
* @author ANMOL POPLI <anmol.ap020@gmail.com>
* PRAVIN NAIR <sreehari1390@gmail.com>
**/
#include "headersreq.h"
void convolve_deriche2D(int rows, int columns, int sigma, double complex** ip_padded);
double Nc[3],Dc[3],Na[3],Da[3],scale;
int w;
//double filter[w+1];
/**
* \brief Convolve input array with 1D Causal filter
* (Deriche Recursive algorithm)
* \param in Pointer to input array
* \param out Pointer to output array
* \param datasize Input array size
*
* This routine performs constant time convolution of the
* 1D input array of complex doubles with 1D Causal filter
* of Deriche Recursive algorithm. The 1D filter is an
* IIR filter.
*/
void convolve_dericheCausal(double complex* in, double complex* out, int datasize,double *filter) {
int i, j;
/* Compute first 3 output elements non-recursively */
out[w]=0;
for(i=0; i<w+1; i++)
{
out[w] += in[i]*filter[i];
}
out[w+1]=0;
for(i=0; i<w+1; i++)
{
out[w+1] += in[i+1]*filter[i];
}
out[w+2]=0;
for(i=0; i<w+1; i++)
{
out[w+2] += in[i+2]*filter[i];
}
/* Recursive computation of output in forward direction using filter parameters Nc, Dc and scale */
for (i=w+3; i<datasize-w; i++) {
out[i] = 0;
for (j=0; j<3; j++) {
out[i] += Nc[j]*in[i-(2-j)]/scale;
out[i] -= Dc[j]*out[i-(3-j)];
}
}
}
/**
* \brief Convolve input array with 1D AntiCausal filter
* (Deriche Recursive algorithm)
* \param in Pointer to input array
* \param out Pointer to output array
* \param datasize Input array size
*
* This routine performs constant time convolution of the
* 1D input array of complex doubles with 1D AntiCausal filter
* of Deriche Recursive algorithm. The 1D filter is an
* IIR filter.
*/
void convolve_dericheAnticausal(double complex* in, double complex* out, int datasize,double *filter) {
int i, j;
/* Compute last 3 output elements non-recursively */
out[datasize-1-w]=0;
for(i=0; i<w; i++)
{
out[datasize-1-w] += in[datasize-1-i]*filter[i];
}
out[datasize-2-w]=0;
for(i=0; i<w; i++)
{
out[datasize-2-w] += in[datasize-2-i]*filter[i];
}
out[datasize-3-w]=0;
for(i=0; i<w; i++)
{
out[datasize-3-w] += in[datasize-3-i]*filter[i];
}
/* Recursive computation of output in backward direction using filter parameters Na, Da and scale */
for (i=datasize-4-w; i>=w; i--) {
out[i] = 0;
for (j=0; j<3; j++) {
out[i] += Na[j]*in[i+(j+1)]/scale;
out[i] -= Da[j]*out[i+(j+1)];
}
}
}
/**
* \brief Convolve input array with 1D Gaussian filter
* (Deriche Recursive algorithm)
* \param in Pointer to input array
* \param out Pointer to output array
* \param datasize Input array size
*
* This routine performs constant time convolution of the
* 1D input array of complex doubles with 1D Gaussian filter
* using Deriche Recursive algorithm. The input array is separately
* convolved with Causal and AntiCausal filters and the results are
* added to obtain the output array.
*/
void convolve_deriche1D(double complex* in, double complex* out, int datasize,double *filter) {
/** \brief Array to store output of Causal filter convolution */
double complex out_causal[datasize];
convolve_dericheCausal(in, out_causal, datasize,filter);
convolve_dericheAnticausal(in, out, datasize,filter);
int i;
for (i=0; i<datasize; i++) in[i] = out_causal[i] + out[i];
}
/**
* \brief Apply 2D Gaussian filter to input image
* (Deriche Recursive Algorithm)
* \param rows Image height
* \param columns Image width
* \param sigma Gaussian kernel standard deviation
* \param ip_padded Pointer to input image
* \param op_padded Pointer to output image
*
* This routine applies 2D Gaussian filter of s.d.
* sigma to input image ip_padded of dimensions
* rows x columns and computes output image op_padded.
* 1D filter is first convolved along rows and then
* along columns. The 1D convolution is performed using
* Deriche's fast recursive algorithm.
*/
void convolve_deriche2D(int rows, int columns, int sigma, double complex** ip_padded) {
/** \brief Filter radius */
w = 3*sigma;
/** \brief Array to store filter weights */
double *filter=calloc(w+1,sizeof(double));
/** \brief Impulse response parameters */
double a0 = -0.8929, a1 = 1.021, b0 = 1.512, w0 = 1.475, c0 = 1.898, b1 = 1.556;
/** \brief Transfer function coefficients */
double n22c = c0*exp(-2*b0/sigma) + (a0*cos(w0/sigma)-a1*sin(w0/sigma))*exp(-(b0+b1)/sigma);
double n11c = -((a0*cos(w0/sigma)-a1*sin(w0/sigma))*exp(-b0/sigma) + a0*exp(-b1/sigma) + 2*c0*exp(-b0/sigma)*cos(w0/sigma));
double n00c = a0 + c0;
double d33c = -exp(-(2*b0+b1)/sigma);
double d22c = exp(-2*b0/sigma) + 2*exp(-(b0+b1)/sigma)*cos(w0/sigma);
double d11c = -(2*exp(-b0/sigma)*cos(w0/sigma) + exp(-b1/sigma));
double d11a = d11c, d22a = d22c, d33a = d33c;
double n33a = -d33c*n00c;
double n22a = n22c - d22c*n00c;
double n11a = n11c - d11c*n00c;
Nc[0]= n22c; Nc[1]= n11c; Nc[2]=n00c;
Dc[0]= d33c; Dc[1]= d22c; Dc[2]=d11c;
Na[0]= n11a; Na[1]= n22a; Na[2]=n33a;
Da[0]= d11a; Da[1]= d22a; Da[2]=d33a;
/** \brief Scale to normalize filter weights */
scale = (Nc[0]+Nc[1]+Nc[2])/(1+Dc[0]+Dc[1]+Dc[2]) + (Na[0]+Na[1]+Na[2])/(1+Da[0]+Da[1]+Da[2]);
/* Compute normalized filter weights */
int i,j,k;
for (i=0;i<w+1;i++)
{
double gnum = -(i-w)*(i-w);
double gden = 2*sigma*sigma;
filter[i] = exp(gnum/gden)/scale;
}
/* Symmetric padding of input image with padding width equal to the filter radius w */
symmetric_padding(rows,columns,ip_padded,w);
/* Convolve each row with 1D Gaussian filter */
double complex *out_t = calloc(columns+(2*w),sizeof(double complex));
for (i=0; i<rows+2*w; i++) convolve_deriche1D(ip_padded[i], out_t, columns+2*w,filter);
free(out_t);
double complex *intemp=calloc(rows+(2*w),sizeof(double complex)),*outtemp=calloc(rows+(2*w),sizeof(double complex));
for (j=w; j<columns+w; j++)
{
/* Convolve each column with 1D Gaussian filter */
for (i=0;i<rows+(2*w);i++) intemp[i]=ip_padded[i][j];
convolve_deriche1D(intemp, outtemp, rows+2*w,filter);
/* Store the convolved column in row of output matrix*/
for (i=0;i<rows+(2*w);i++) ip_padded[i][j]=intemp[i];
}
free(filter);
free(intemp);
free(outtemp);
}