subpixelInterpolate.h

00001 
00017 #ifndef DLR_NUMERIC_SUBPIXELINTERPOLATE_H
00018 #define DLR_NUMERIC_SUBPIXELINTERPOLATE_H
00019 
00020 
00021 namespace dlr {
00022 
00023   namespace numeric {
00024 
00090     template <class Type0>
00091     inline void
00092     getQuadraticCoefficients3x3(
00093       Type0 value00, Type0 value01, Type0 value02,
00094       Type0 value10, Type0 value11, Type0 value12,
00095       Type0 value20, Type0 value21, Type0 value22,
00096       double& k0, double& k1, double& k2, double& k3, double& k4, double& k5);
00097 
00098 
00164     template <class Type0, class Type1>
00165     bool
00166     subpixelInterpolate(double centerRowCoord, double centerColumnCoord,
00167                         Type0 value00, Type0 value01, Type0 value02,
00168                         Type0 value10, Type0 value11, Type0 value12,
00169                         Type0 value20, Type0 value21, Type0 value22,
00170                         double& extremumRowCoord, double& extremumColumnCoord,
00171                         Type1& extremeValue);
00172 
00173 
00211     template <class Type0, class Type1>
00212     bool
00213     subpixelInterpolate(double centerPosition,
00214                         Type0 value0, Type0 value1, Type0 value2,
00215                         double& extremumPosition,
00216                         Type1& extremeValue);
00217     
00218   } // namespace numeric
00219   
00220 } // namespace dlr
00221 
00222 
00223 /* ============ Definitions of inline & template functions ============ */
00224 
00225 
00226 #include <cmath>
00227 
00228 namespace dlr {
00229 
00230   namespace numeric {
00231 
00232     // This function solves for the coefficients of a 2D quadratic,
00233     // given the function values on a 3x3 grid around the origin.
00234     template <class Type0>
00235     void
00236     getQuadraticCoefficients3x3(
00237       Type0 value00, Type0 value01, Type0 value02,
00238       Type0 value10, Type0 value11, Type0 value12,
00239       Type0 value20, Type0 value21, Type0 value22,
00240       double& k0, double& k1, double& k2, double& k3, double& k4, double& k5)
00241     {
00242       // Given f(x0, y0) = value00, we can rearrange the quadratic
00243       // equation like this:
00244       //
00245       // @code
00246       //   [x0*x0, 2*x0*y0, y0*y0, x0, y0, 1] [k0, k1, k2, k3, k5, k5]^T = value00
00247       // @endcode
00248       // 
00249       // We're always going to look at a 3x3 neighborhood around (0,
00250       // 0), so this gives us 9 simultaneous equations that are
00251       // quadratic in x, y, but linear in the parameters for which
00252       // we're solving.
00253       //
00254       // @code
00255       //   [     ][k0]   [value00]
00256       //   [  A  ][k1] = [value01]
00257       //   [     ][k2]   [value02]
00258       //          [k3]   [value10]
00259       //          [k4]   [value11]
00260       //          [k5]   [value12]
00261       //                 [value20]
00262       //                 [value21]
00263       //                 [value22]
00264       // @endcode
00265       // 
00266       // Where A is a 9x6 matrix:
00267       //
00268       // @code
00269       //       [1,  2,  1, -1, -1,  1]
00270       //       [0,  0,  1,  0, -1,  1]
00271       //       [1, -2,  1,  1, -1,  1]
00272       //       [1,  0,  0, -1,  0,  1]
00273       //   A = [0,  0,  0,  0,  0,  1]
00274       //       [1,  0,  0,  1,  0,  1]
00275       //       [1, -2,  1, -1,  1,  1]
00276       //       [0,  0,  1,  0,  1,  1]
00277       //       [1,  2,  1,  1,  1,  1]
00278       // @endcode
00279       //
00280       // We simply hardcode the pseudoInverse here.
00281       k0 = (0.16666666666666663 * value00
00282             + -0.33333333333333331 * value01
00283             + 0.16666666666666663 * value02
00284             + 0.16666666666666663 * value10
00285             + -0.33333333333333337 * value11
00286             + 0.16666666666666663 * value12
00287             + 0.16666666666666663 * value20
00288             + -0.33333333333333331 * value21
00289             + 0.16666666666666663 * value22);
00290       k1 = (0.125 * value00
00291             + -0.125 * value02
00292             + -0.125 * value20
00293             + 0.125 * value22);
00294       k2 = (0.16666666666666663 * value00
00295             + 0.16666666666666663 * value01
00296             + 0.16666666666666663 * value02
00297             + -0.33333333333333331 * value10
00298             + -0.33333333333333331 * value11
00299             + -0.33333333333333331 * value12
00300             + 0.16666666666666663 * value20
00301             + 0.16666666666666663 * value21
00302             + 0.16666666666666663 * value22);
00303       k3 = (-0.16666666666666666 * value00
00304             + 0.16666666666666666 * value02
00305             + -0.16666666666666666 * value10
00306             + 0.16666666666666666 * value12
00307             + -0.16666666666666666 * value20
00308             + 0.16666666666666666 * value22);
00309       k4 = (-0.16666666666666666 * value00
00310             + -0.16666666666666666 * value01
00311             + -0.16666666666666666 * value02
00312             + 0.16666666666666666 * value20
00313             + 0.16666666666666666 * value21
00314             + 0.16666666666666666 * value22);
00315       k5 = (-0.11111111111111116 * value00
00316             + 0.22222222222222227 * value01
00317             + -0.11111111111111116 * value02
00318             + 0.22222222222222221 * value10
00319             + 0.55555555555555558 * value11
00320             + 0.22222222222222221 * value12
00321             + -0.11111111111111116 * value20
00322             + 0.22222222222222227 * value21
00323             + -0.11111111111111116 * value22);
00324     }
00325 
00326     
00327     template <class Type0, class Type1>
00328     bool
00329     subpixelInterpolate(double centerRowCoord, double centerColumnCoord,
00330                         Type0 value00, Type0 value01, Type0 value02,
00331                         Type0 value10, Type0 value11, Type0 value12,
00332                         Type0 value20, Type0 value21, Type0 value22,
00333                         double& extremumRowCoord, double& extremumColumnCoord,
00334                         Type1& extremeValue)
00335     {
00336       // First, we solve for the coefficients of a quadratic in the
00337       // neighborhood of (centerRowCoord, centerColumnCoord), with the
00338       // parameters of the quadratic being location (rowCoord,
00339       // columnCoord), and the scalar quadratic values being provided
00340       // in the argument list (value00, value01, etc.) above.
00341       //
00342       // @code
00343       //   valueRC = [R, C] [k0, k1] [R] + [R, C] [k3] + k5
00344       //                    [k1, k2] [C]          [k4]
00345       // @endcode
00346       //
00347       // This function call solves for k0 through k5 in the above
00348       // equation.
00349       double k0, k1, k2, k3, k4, k5;
00350       getQuadraticCoefficients3x3(
00351         value00, value01, value02,
00352         value10, value11, value12,
00353         value20, value21, value22,
00354         k0, k1, k2, k3, k4, k5);
00355 
00356       // Now we have the parameters of the quadratic, we need to find
00357       // its extremum.  That is, the place where it's derivitive goes
00358       // to zero.  We need to solve this equation for x and y:
00359       //
00360       // @code
00361       //   2[k0, k1][x] + [k3] = [0]
00362       //    [k1, k2][y]   [k4]   [0]
00363       // @endcode
00364       //
00365       // We simply hardcode a cofactor method inverse below, starting
00366       // with finding the determinant.
00367       double determinant = k0 * k2 - k1 * k1;
00368 
00369       // Before we continue with the matrix inversion, consider
00370       // whether we're going to find a min, a max, or a saddle point.
00371       // Essentially, we need to know if matrix [k0,k1; k1, k2] has
00372       // one positive eigenvalue and one negative eigenvalue (in which
00373       // case we'll find a saddle point).  If we were to solve for
00374       // those eigenvalues, we'd be trying to find values of lambda
00375       // such that
00376       //
00377       // @code
00378       //   determinant([k0 - lambda, k1         ]) == 0
00379       //               [         k1, k2 - lambda]
00380       // @endcode
00381       //
00382       // If you write this out, you get a quadratic equation:
00383       //
00384       //   lambda^2 + (k0 + k2) * lambda + (k0 * k2 - k1^2) = 0
00385       //
00386       // the signs of the two solutions to this equation are different
00387       // if and only if (k0 * k2 - k1^2) is negative (check out the
00388       // documentation of solveQuadratic() in utilities.h to see why
00389       // this is true), but this is just the determinant we just computed.
00390       //
00391       // So, if determinant is zero, we can't do the matrix inverse.
00392       // If determinant < 0, we'll only find a saddle point.  In both
00393       // cases, we simply return false.
00394       if(determinant <= 0) {
00395         return false;
00396       }
00397 
00398       // Now continue with the matrix inversion, and compute the
00399       // position of the extremum.
00400       double detTimes2 = determinant * 2.0;
00401       double inverseMx00 = k2 / detTimes2;
00402       double inverseMx01 = -k1 / detTimes2;
00403       double inverseMx11 = k0 / detTimes2;
00404 
00405       double maxX = -k3 * inverseMx00 - k4 * inverseMx01;
00406       double maxY = -k3 * inverseMx01 - k4 * inverseMx11;
00407 
00408       extremumRowCoord = centerRowCoord + maxY;
00409       extremumColumnCoord = centerColumnCoord + maxX;
00410 
00411       // Now that we have the location of the extremum, use the
00412       // quadratic equation to estimate its "real" value.
00413       extremeValue =
00414         (k0 * maxX * maxX + 2 * k1 * maxX * maxY + k2 * maxY * maxY
00415          + k3 * maxX + k4 * maxY + k5);
00416 
00417       return true;
00418     }
00419 
00420 
00421     
00422     // Given pixel values in a 3x1 arrangement centerPosition, this
00423     // function fits a quadratic to the values and returns the
00424     // location and interpolated value of the extremum (max or min
00425     // value) of the quadratic.
00426     template <class Type0, class Type1>
00427     bool
00428     subpixelInterpolate(double centerPosition,
00429                         Type0 value0, Type0 value1, Type0 value2,
00430                         double& extremumPosition,
00431                         Type1& extremeValue)
00432     {
00433       // First, we solve for the coefficients of a quadratic in the
00434       // neighborhood of centerPosition, with the parameters of the
00435       // quadratic being position, and the scalar quadratic values
00436       // being provided in the argument list (value0, value1, value2)
00437       // above.
00438       //
00439       // @code
00440       //   valueP = k0*p*p + k1*p + k2
00441       // @endcode
00442       //
00443       // To make this easier, we solve as if centerPosition were 0.
00444       // We'll correct this later.  Assuming centerPosition is zero,
00445       // we can write the above equation three times, one for each of
00446       // the input values, assuming coodinates of -1, 0, 1.  Writing
00447       // this in matrix form gives:
00448       // 
00449       // @code
00450       //   [1, -1, 1][k0]   [value0]
00451       //   [0,  0, 1][k1] = [value1]
00452       //   [1,  1, 1][k2]   [value2]
00453       // @endcode
00454       //
00455       // Solving this using the Moore-Penrose pseudoinverse gives:
00456       //
00457       // @code
00458       //   [k0]   [ 0.5, -1.0, 0.5][value0]
00459       //   [k1] = [-0.5,  0.0, 0.5][value1]
00460       //   [k2]   [ 0.0,  1.0, 0.0][value2]
00461       // @endcode
00462       double k0 =  0.5 * value0 - value1 + 0.5 * value2;
00463       double k1 = -0.5 * value0 + 0.5 * value2;
00464       double k2 = value1;
00465 
00466       // Now we have the parameters of the quadratic, we need to find
00467       // its extremum.  That is, the place where it's derivitive goes
00468       // to zero.  We need to solve this equation for p:
00469       //
00470       // @code
00471       //   2*k0*p + k1 = 0
00472       // @code
00473       //
00474       // If k0 is zero, we can't solve this.  Instead we return false.
00475       if(k0 == 0) {
00476         return false;
00477       }
00478       double maxP = -k1 / (2 * k0);
00479 
00480       // Now correct the "assume centerPosition is zero" dodge we
00481       // introduced above.
00482       extremumPosition = centerPosition + maxP;
00483 
00484       // Now that we have the location of the extremum, use the
00485       // quadratic equation to estimate its "real" value.
00486       extremeValue = k0 * maxP * maxP + k1 * maxP + k2;
00487 
00488       return true;
00489     }
00490     
00491   } // namespace numeric
00492 
00493 } // namespace dlr
00494 
00495 #endif /* #ifndef DLR_NUMERIC_SUBPIXELINTERPOLATE_H */

Generated on Wed Nov 25 00:42:43 2009 for dlrUtilities Utility Library by  doxygen 1.5.8