1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
/* kernel.cc
Mark Jenkinson, FMRIB Image Analysis Group
Copyright (C) 2001 University of Oxford */
/* CCOPYRIGHT */
#include "kernel.h"
#include "miscmaths.h"
namespace MISCMATHS {
set<kernelstorage*, kernelstorage::comparer> kernel::existingkernels;
//////// Support function /////////
float kernelval(float x, int w, const ColumnVector& kernel)
{
// linearly interpolates to get the kernel at the point (x)
// given the half-width w
if (fabs(x)>w) return 0.0;
float halfnk = (kernel.Nrows()-1.0)/2.0;
float dn = x/w*halfnk + halfnk + 1.0;
int n = (int) floor(dn);
dn -= n;
if (n>(kernel.Nrows()-1)) return 0.0;
if (n<1) return 0.0;
return kernel(n)*(1.0-dn) + kernel(n+1)*dn;
}
inline bool in_bounds(const ColumnVector& data, int index)
{ return ( (index>=1) && (index<=data.Nrows())); }
inline bool in_bounds(const ColumnVector& data, float index)
{ return ( ((int)floor(index)>=1) && ((int)ceil(index)<=data.Nrows())); }
float sincfn(float x)
{
if (fabs(x)<1e-7) { return 1.0-fabs(x); }
float y=M_PI*x;
return sin(y)/y;
}
float hanning(float x, int w)
{ // w is half-width
if (fabs(x)>w)
return 0.0;
else
return (0.5 + 0.5 *cos(M_PI*x/w));
}
float blackman(float x, int w)
{ // w is half-width
if (fabs(x)>w)
return 0.0;
else
return (0.42 + 0.5 *cos(M_PI*x/w) + 0.08*cos(2.0*M_PI*x/w));
}
float rectangular(float x, int w)
{ // w is half-width
if (fabs(x)>w)
return 0.0;
else
return 1.0;
}
ColumnVector sinckernel1D(const string& sincwindowtype, int w, int n)
{ // w is full-width
int nstore = n;
if (nstore<1) nstore=1;
ColumnVector ker(nstore);
int hw = (w-1)/2; // convert to half-width
// set x between +/- width
float halfnk = (nstore-1.0)/2.0;
for (int n=1; n<=nstore; n++) {
float x=(n-halfnk-1)/halfnk*hw;
if ( (sincwindowtype=="hanning") || (sincwindowtype=="h") ) {
ker(n) = sincfn(x)*hanning(x,hw);
} else if ( (sincwindowtype=="blackman") || (sincwindowtype=="b") ) {
ker(n) = sincfn(x)*blackman(x,hw);
} else if ( (sincwindowtype=="rectangular") || (sincwindowtype=="r") ) {
ker(n) = sincfn(x)*rectangular(x,hw);
} else {
cerr << "ERROR: Unrecognised sinc window type - using Blackman" << endl;
ker = sinckernel1D("b",w,nstore);
return ker;
}
}
return ker;
}
kernel sinckernel(const string& sincwindowtype, int w, int nstore)
{
kernel sinck;
sinck = sinckernel(sincwindowtype,w,w,w,nstore);
return sinck;
}
kernel sinckernel(const string& sincwindowtype,
int wx, int wy, int wz, int nstore)
{ // widths are full-widths
kernel sinckern;
if (nstore<1) nstore=1;
// convert all widths to half-widths
int hwx = (wx-1)/2;
int hwy = (wy-1)/2;
int hwz = (wz-1)/2;
ColumnVector kx, ky, kz;
// calculate kernels
kx = sinckernel1D(sincwindowtype,wx,nstore);
ky = sinckernel1D(sincwindowtype,wy,nstore);
kz = sinckernel1D(sincwindowtype,wz,nstore);
sinckern.setkernel(kx,ky,kz,hwx,hwy,hwz);
return sinckern;
}
// dummy fn for now
float extrapolate_1d(const ColumnVector& data, const int index)
{
float extrapval;
if (in_bounds(data, index))
extrapval = data(index);
else if (in_bounds(data, index-1))
extrapval = data(data.Nrows());
else if (in_bounds(data, index+1))
extrapval = data(1);
else
extrapval = mean(data).AsScalar();
return extrapval;
}
// basic trilinear call
float interpolate_1d(const ColumnVector& data, const float index)
{
float interpval;
int low_bound = (int)floor(index);
int high_bound = (int)ceil(index);
if (in_bounds(data, index))
interpval = data(low_bound) + (index - low_bound)*(data(high_bound) - data(low_bound));
else
interpval = extrapolate_1d(data, round(index));
return interpval;
}
//////// Spline Support /////////
float hermiteinterpolation_1d(const ColumnVector& data, int p1, int p4, float t)
{
// Q(t) = (2t^3 - 3t^2 + 1)P_1 + (-2t^3 + 3t^2)P_4 + (t^3 - 2t^2 + t)R_1 + (t^3 - t^2)R_4
// inputs: points P_1, P_4; tangents R_1, R_4; interpolation index t;
float retval, r1 = 0.0, r4 = 0.0;
if (!in_bounds(data,p1) || !in_bounds(data,p4)) {
cerr << "Hermite Interpolation - ERROR: One or more indicies lie outside the data range. Returning ZERO" << endl;
retval = 0.0;
} else if ((t < 0) || (t > 1)) {
cerr << "Hermite Interpolation - ERROR: Interpolation index must lie between 0 and 1. Returning ZERO" << endl;
retval = 0.0;
/* } else if (t == 0.0) {
retval = data(p1);
} else if (t == 1.0) {
retval = data(p4);
*/
} else {
r1 = 0.5 * (extrapolate_1d(data, p1) - extrapolate_1d(data, p1 - 1)) + 0.5 * (extrapolate_1d(data, p1 + 1) - extrapolate_1d(data, p1));// tangent @ P_1
r4 = 0.5 * (extrapolate_1d(data, p4) - extrapolate_1d(data, p4 - 1)) + 0.5 * (extrapolate_1d(data, p4 + 1) - extrapolate_1d(data, p4));// tangent @ P_4
float t2 = t*t; float t3 = t2*t;
retval = (2*t3 - 3*t2 + 1)*data(p1) + (-2*t3 + 3*t2)*data(p4) + (t3 - 2*t2 + t)*r1 + (t3 - t2)*r4;
}
// cerr << "p1, p4, t, r1, r4 = " << p1 << ", " << p4 << ", " << t << ", " << r1 << ", " << r4 << endl;
return retval;
}
//////// Kernel Interpolation Call /////////
float kernelinterpolation_1d(const ColumnVector& data, float index, const ColumnVector& userkernel, int width)
{
int widthx = (width - 1)/2;
// kernel half-width (i.e. range is +/- w)
int ix0;
ix0 = (int) floor(index);
int wx(widthx);
vector<float> storex(2*wx+1);
for (int d=-wx; d<=wx; d++)
storex[d+wx] = kernelval((index-ix0+d),wx,userkernel);
float convsum=0.0, interpval=0.0, kersum=0.0;
int xj;
for (int x1=ix0-wx; x1<=ix0+wx; x1++) {
if (in_bounds(data, x1)) {
xj=ix0-x1+wx;
float kerfac = storex[xj];
convsum += data(x1) * kerfac;
kersum += kerfac;
}
}
if ( (fabs(kersum)>1e-9) ) {
interpval = convsum / kersum;
} else {
interpval = (float) extrapolate_1d(data, ix0);
}
return interpval;
}
////// Kernel wrappers //////
float kernelinterpolation_1d(const ColumnVector& data, float index)
{
ColumnVector userkernel = sinckernel1D("hanning", 7, 1201);
return kernelinterpolation_1d(data, index, userkernel, 7);
}
float kernelinterpolation_1d(RowVector data, float index)
{
ColumnVector userkernel = sinckernel1D("hanning", 7, 1201);
return kernelinterpolation_1d(data.t(), index, userkernel, 7);
}
}
|