ThreeB 1.1
storm.h
Go to the documentation of this file.
00001 /*
00002     This file is part of B-cubed.
00003 
00004     Copyright (C) 2009, 2010, 2011, Edward Rosten and Susan Cox
00005 
00006     B-cubed is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Lesser General Public
00008     License as published by the Free Software Foundation; either
00009     version 3.0 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License     
00017     along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 
00020 #ifndef INC_STORM_H
00021 #define INC_STORM_H
00022 
00023 #include <TooN/TooN.h>
00024 #include <cvd/image.h>
00025 #include <utility>
00026 #include <tr1/tuple>
00027 #include "utility.h"
00028 
00029 
00030 /**See spot_shape()
00031 @param x \f$\Vec{x}\f$
00032 @param phi \f$\Vec{\phi}\f$
00033 @return \f$s(\Vec{x}, \Vec{\phi}) \f$
00034 @ingroup gStorm
00035 */
00036 template<class B> double spot_shape_s(const TooN::Vector<2>& x, const TooN::Vector<4, double, B>& phi)
00037 {
00038     return -norm_sq(x - phi.template slice<2,2>()) / (2*phi[1]*phi[1]);
00039 }
00040 
00041 /** Compute the spot shape and its derivative with respect to posision. See also spot_shape()
00042 @param x \f$\Vec{x}\f$
00043 @param phi \f$\Vec{\phi}\f$
00044 @ingroup gStorm
00045 */
00046 template<class B> std::pair<double, TooN::Vector<4> > spot_shape_diff_position(const TooN::Vector<2>& x, const TooN::Vector<4, double, B>& phi)
00047 {
00048     using namespace TooN;
00049 
00050     double s = spot_shape_s(x, phi);
00051     double r_2_pi = sqrt(2*M_PI);
00052 
00053     double prob = exp(s) * phi[0]/(phi[1]*r_2_pi);
00054     
00055     Vector<4> deriv = (exp(s) / (phi[1]*r_2_pi)) * 
00056                            makeVector(1, 
00057                                       -phi[0] * (1 + 2*s)/phi[1], 
00058                                       (x[0] - phi[2])*(phi[0]/sq(phi[1])), 
00059                                       (x[1] - phi[3])*(phi[0]/sq(phi[1])));
00060     return std::make_pair(prob, deriv);
00061 }
00062 
00063 /** Compute the spot shape and its Hessian with respect to posision. See also spot_shape()
00064 @param x \f$\Vec{x}\f$
00065 @param phi \f$\Vec{\phi}\f$
00066 @ingroup gStorm
00067 */
00068 template<class B> std::tr1::tuple<double, TooN::Vector<4>, TooN::Matrix<4> > spot_shape_hess_position(const TooN::Vector<2>& x, const TooN::Vector<4, double, B>& phi)
00069 {
00070     using namespace TooN;
00071     using namespace std::tr1;
00072 
00073     double s = spot_shape_s(x, phi);
00074     double r_2_pi = sqrt(2*M_PI);
00075 
00076     double es = exp(s);
00077 
00078     double prob = es * phi[0]/(phi[1]*r_2_pi);
00079     
00080     Vector<4> deriv = (es / (phi[1]*r_2_pi)) * 
00081                            makeVector(1, 
00082                                       -phi[0] * (1 + 2*s)/phi[1], 
00083                                       (x[0] - phi[2])*(phi[0]/sq(phi[1])), 
00084                                       (x[1] - phi[3])*(phi[0]/sq(phi[1])));
00085 
00086     Matrix<4> hess;
00087     hess[0][0] = 0;
00088 
00089     hess[0][1] = -es*(1+2*s) / (phi[1] * phi[1] * r_2_pi);
00090     hess[1][0] = hess[0][1];
00091 
00092     hess[0][2] = es * (x[0] - phi[2]) / (pow(phi[1], 3)*r_2_pi);
00093     hess[2][0] = es * (x[0] - phi[2]) / (pow(phi[1], 3)*r_2_pi);
00094 
00095     hess[0][3] = es * (x[1] - phi[3]) / (pow(phi[1], 3)*r_2_pi);
00096     hess[3][0] = es * (x[1] - phi[3]) / (pow(phi[1], 3)*r_2_pi);
00097 
00098     hess[1][1] = 2*phi[0]*es*(1 + 5*s + 2*s*s) / ( pow(phi[1], 3) * r_2_pi);
00099 
00100     hess[1][2] = -phi[0] * es * (3 + 2*s) * (x[0] - phi[2]) / (pow(phi[1], 4) * r_2_pi);
00101     hess[1][3] = -phi[0] * es * (3 + 2*s) * (x[1] - phi[3]) / (pow(phi[1], 4) * r_2_pi);
00102 
00103     hess[2][1] = hess[1][2];
00104     hess[3][1] = hess[1][3];
00105 
00106     hess[2][2] = phi[0] * es * (sq(x[0] - phi[2]) - sq(phi[1])) / (r_2_pi * pow(phi[1], 5));
00107     hess[3][3] = phi[0] * es * (sq(x[1] - phi[3]) - sq(phi[1])) / (r_2_pi * pow(phi[1], 5));
00108     
00109     hess[2][3] = phi[0] * es * (x[0] - phi[2])*(x[1] - phi[3]) / (r_2_pi * pow(phi[1], 5));
00110     hess[3][2] = hess[2][3];
00111 
00112 
00113     return make_tuple(prob, deriv, hess);
00114 }
00115 
00116 /**Value of the spot, given the parameters and input location.
00117 The spot is described by the following formula:
00118 \f[
00119     \mu(\Vec{x}, \Vec{\phi}) = \frac{\phi_1}{\phi_2\sqrt(2\pi)} e^s,
00120 \f]
00121 where
00122 \f[
00123     s = -\frac{(x_1 - \phi_3)^2 + (x_2 - \phi_4)^2}{2\phi_2^2}.
00124 \f]
00125 This describes a generic blobby spot function of a variable size. The light output
00126 can be tuned by varying \f$\phi_1\f$, and the level of blur can be changed independently
00127 by varying \f$\phi_2\f$. The derivative is:
00128 \f{eqnarray}{
00129     \frac{\partial \mu}{\partial \phi_1} &=& \frac{1}{\phi_2\sqrt{2\pi}}e^s\\
00130     \frac{\partial \mu}{\partial \phi_2} &=& -\frac{\phi_1}{\phi_2^2\sqrt{2\pi}}e^s(1 + 2s)
00131 \f}
00132 And the hessian is:
00133 \f{eqnarray}{
00134     \frac{\partial^2 \mu}{\partial \phi_1^2} &=& 0\\
00135     \frac{\partial^2 \mu}{\partial\phi_1 \partial \phi_2} &=& -\frac{1}{\phi_2^2\sqrt{2\pi}}e^s(1 + 2s)\\
00136     \frac{\partial^2 \mu}{\partial \phi_2^2} &=& \frac{2\phi_1}{\phi_2^3\sqrt{2\pi}}e^s(1 + 5s + 2s^2)
00137 \f}
00138 @param x \f$\Vec{x}\f$
00139 @param phi \f$\Vec{\phi}\f$
00140 @return \f$\mu(\Vec{x}, \Vec{\phi}) \f$
00141 @ingroup gStorm
00142 */
00143 template<class B> std::tr1::tuple<double, TooN::Vector<2>, TooN::Matrix<2> > spot_shape_hess(const TooN::Vector<2>& x, const TooN::Vector<4, double, B>& phi)
00144 {
00145     double s = spot_shape_s(x, phi);
00146     double r_2_pi = sqrt(2*M_PI);
00147 
00148     double prob = exp(s) * phi[0]/(phi[1]*r_2_pi);
00149     TooN::Vector<2> deriv = (exp(s) / (phi[1]*r_2_pi)) * TooN::makeVector(1, -phi[0] * (1 + 2*s)/phi[1]);
00150     TooN::Matrix<2> hess;
00151 
00152     hess[0][0] = 0;
00153     hess[0][1] = -exp(s)*(1+2*s) / (phi[1] * phi[1] * r_2_pi);
00154     hess[1][0] = hess[0][1];
00155     hess[1][1] = 2*phi[0]*exp(s)*(1 + 5*s + 2*s*s) / ( pow(phi[1], 3) * r_2_pi);
00156 
00157     return std::tr1::make_tuple(prob, deriv, hess);
00158 }
00159 /** see spot_shape_hess()
00160 @param x \f$\Vec{x}\f$
00161 @param phi \f$\Vec{\phi}\f$
00162 @return \f$\mu(\Vec{x}, \Vec{\phi}) \f$
00163 @ingroup gStorm
00164 */
00165 template<class B> std::pair<double, TooN::Vector<2> > spot_shape_diff(const TooN::Vector<2>& x, const TooN::Vector<4, double, B>& phi)
00166 {
00167     double s = spot_shape_s(x, phi);
00168     double r_2_pi = sqrt(2*M_PI);
00169 
00170     double prob = exp(s) * phi[0]/(phi[1]*r_2_pi);
00171     TooN::Vector<2> deriv = (exp(s) / (phi[1]*r_2_pi)) * TooN::makeVector(1, -phi[0] * (1 + 2*s)/phi[1]);
00172     return std::make_pair(prob, deriv);
00173 }
00174 
00175 /** see spot_shape_hess()
00176 @param x \f$\Vec{x}\f$
00177 @param phi \f$\Vec{\phi}\f$
00178 @return \f$\mu(\Vec{x}, \Vec{\phi}) \f$
00179 @ingroup gStorm
00180 */
00181 template<class B> double spot_shape(const TooN::Vector<2>& x, const TooN::Vector<4, double, B>& phi)
00182 {
00183     double s = spot_shape_s(x, phi);
00184     double r_2_pi = sqrt(2*M_PI);
00185     
00186     // FIXME FIXME FIXME and don't forget to fix the HESSIAN AND DERIVATIVE
00187     // Should be:              1/(2 pi s^2)  for two dimensions
00188     //                             vvvvvvvvvvvvv    http://lol.i.trollyou.com/
00189     double prob = exp(s) * phi[0]/(phi[1]*r_2_pi);
00190 
00191 
00192     return prob;
00193 }
00194 
00195 /**Find the log probability of an image patch, 
00196 assuming zero mean and the given variance, and no spot present.
00197 See also log_probability_spot()
00198 @param im Image
00199 @param variance variance
00200 @returns The log probability
00201 */
00202 inline double log_probability_no_spot(const CVD::SubImage<float>& im, double variance)
00203 {
00204     double logprob_part=0;
00205     for(int y=0; y < im.size().y; y++)
00206         for(int x=0; x < im.size().x; x++)
00207             logprob_part -= im[y][x] * im[y][x];
00208     return logprob_part/(2*variance) - im.size().area() * log(2*M_PI*variance)/2;
00209 
00210 }
00211 
00212 /**Find the log probability of an image patch, assuming zero base-line mean and
00213 the given variance. This function makes use of the spot shape. It is assumed that the
00214 centre pixel of the image is at 0,0. Since the noise is Gaussian:
00215 \f{eqnarray}{
00216     P(\text{image})    &=& \prod_{\Vec{x} \in \text{pixels}} \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(I(\Vec{x}) - \mu(\Vec{x}, \Vec{\phi}))^2}{2\sigma^2}} \\
00217     \ln P(\text{image}) &=& \sum_{\Vec{x} \in \text{pixels}}  -\frac{(I(\Vec{x}) - \mu(\Vec{x}, \Vec{\phi}))^2}{2\sigma^2} - \frac{N}{2} \ln {2 \pi \sigma^2},
00218 \f}
00219 where \e I is the image, and \e N is the number of pixels. See also ::log_probability_no_spot and \f$\mu\f$ (::spot_shape).
00220 The derivatives are:
00221 \f{eqnarray}{
00222     \frac{\partial \ln P(I)}{\partial \phi_0} &=& \frac{1}{\sigma^2} \sum_{\Vec{x}}(I_{\Vec{x}} - \mu(\Vec{x},\Vec{\phi}))
00223                                                            \frac{\partial}{\partial \phi_0}\mu(\Vec{x}, \Vec{\phi})\\
00224     \frac{\partial^2 \ln P(I)}{\partial \phi_0 \partial \phi_1} &=&
00225               \frac{1}{\sigma^2} \sum_{\Vec{x}}(I_{\Vec{x}} - \mu(\Vec{x},\Vec{\phi}))
00226                                \frac{\partial^2}{\partial \phi_0 \partial \phi_1}\mu(\Vec{x}, \Vec{\phi}) - 
00227                                \frac{\partial}{\partial \phi_0}\mu(\Vec{x},\Vec{\phi})
00228                                \frac{\partial}{\partial \phi_1}\mu(\Vec{x},\Vec{\phi})
00229 \f}
00230 @ingroup gStorm
00231 @param im Image
00232 @param variance \f$\sigma^2\f$
00233 @param spot_parameters \f$\Vec{\phi}\f$
00234 @returns The log probability
00235 */
00236 template<class Base> std::tr1::tuple<double, TooN::Vector<2>, TooN::Matrix<2> > log_probability_spot_hess(const CVD::SubImage<float>& im, double variance, const TooN::Vector<4, double, Base>& spot_parameters)
00237 {
00238     using namespace TooN;
00239     using namespace std::tr1;
00240 
00241     //-1 because if the image is 3x3, ie 0,1,2 then 1,1 is the centre.
00242     //If it is 2x2, ie 0,1 then .5,.5 is the centre
00243     Vector<2> centre = makeVector((im.size().x-1) / 2.0, (im.size().y-1) / 2.0);
00244 
00245     double logprob_part=0;
00246     Vector<2> diff = Zeros;
00247     Matrix<2> hess = Zeros;
00248     for(int y=0; y < im.size().y; y++)
00249         for(int x=0; x < im.size().x; x++)
00250         {
00251             Vector<2> d = TooN::makeVector(x, y) - centre;
00252 
00253             double mu;
00254             Vector<2> diff_mu;
00255             Matrix<2> hess_mu;
00256             tie(mu, diff_mu, hess_mu) = spot_shape_hess(d, spot_parameters);
00257 
00258             double e = im[y][x] - mu;
00259 
00260             logprob_part += -sq(e);
00261             diff         += diff_mu * e;
00262             hess         += e * hess_mu - diff_mu.as_col() * diff_mu.as_row();
00263         }
00264     return make_tuple(   logprob_part / (2*variance) - im.size().area() * log(2*M_PI*variance)/2,
00265                         diff / variance,
00266                         hess / variance);
00267 }
00268 
00269 /** See log_probability_spot_hess
00270 @ingroup gStorm
00271 @param im Image
00272 @param variance \f$\sigma^2\f$
00273 @param spot_parameters \f$\Vec{\phi}\f$
00274 @returns The log probability
00275 */
00276 template<class Base> std::pair<double, TooN::Vector<2> > log_probability_spot_diff(const CVD::SubImage<float>& im, double variance, const TooN::Vector<4, double, Base>& spot_parameters)
00277 {
00278     using namespace TooN;
00279     using namespace std::tr1;
00280     using namespace std;
00281     //-1 because if the image is 3x3, ie 0,1,2 then 1,1 is the centre.
00282     //If it is 2x2, ie 0,1 then .5,.5 is the centre
00283     Vector<2> centre = makeVector((im.size().x-1) / 2.0, (im.size().y-1) / 2.0);
00284 
00285     double logprob_part=0;
00286     Vector<2> diff = Zeros;
00287     for(int y=0; y < im.size().y; y++)
00288         for(int x=0; x < im.size().x; x++)
00289         {
00290             Vector<2> d = makeVector(x, y) - centre;
00291 
00292             double mu;
00293             Vector<2> diff_mu;
00294             tie(mu, diff_mu) = spot_shape_diff(d, spot_parameters);
00295 
00296             double e = im[y][x] - mu;
00297 
00298             logprob_part += -sq(e);
00299             diff         += diff_mu * e;
00300         }
00301     return make_pair(logprob_part / (2*variance) - im.size().area() * log(2*M_PI*variance)/2, diff / variance);
00302 }
00303 
00304 /** See log_probability_spot_hess
00305 @ingroup gStorm
00306 @param im Image
00307 @param variance \f$\sigma^2\f$
00308 @param spot_parameters \f$\Vec{\phi}\f$
00309 @returns The log probability
00310 */
00311 template<class Base> double log_probability_spot(const CVD::SubImage<float>& im, double variance, const TooN::Vector<4, double, Base>& spot_parameters)
00312 {
00313     //-1 because if the image is 3x3, ie 0,1,2 then 1,1 is the centre.
00314     //If it is 2x2, ie 0,1 then .5,.5 is the centre
00315     TooN::Vector<2> centre = TooN::makeVector((im.size().x-1) / 2.0, (im.size().y-1) / 2.0);
00316 
00317     double logprob_part=0;
00318     for(int y=0; y < im.size().y; y++)
00319         for(int x=0; x < im.size().x; x++)
00320         {
00321             TooN::Vector<2> d = TooN::makeVector(x, y) - centre;
00322 
00323             double mu = spot_shape(d, spot_parameters);
00324 
00325             double e = im[y][x] - mu;
00326 
00327             logprob_part += -sq(e);
00328         }
00329     return logprob_part / (2*variance) - im.size().area() * log(2*M_PI*variance)/2;
00330 }
00331 
00332 /**Compute the standard deviation of a log-normal distribution.
00333 
00334 See log_normal().
00335 \f{equation}
00336     \mathrm{Var}[P(x)] = (e^(\sigma^2)-1)e^(2*\mu+\sigma^2)
00337 \f}
00338 @param sigma \f$ \sigma\f$
00339 @param mu \f$ \mu\f$
00340 @returns The standard deviation
00341 @ingroup gStorm
00342 */
00343 inline double log_normal_std(double mu, double sigma)
00344 {
00345     return sqrt((exp(sq(sigma)) - 1) * exp(2*mu + sq(sigma)));
00346 }
00347 
00348 /**Compute the mode of a log-normal distribution.
00349 
00350 See log_normal().
00351 \f{equation}
00352     \mathrm{Mode}[P(x)] = e^(\mu-\sigma^2)
00353 \f}
00354 @param sigma \f$ \sigma\f$
00355 @param mu \f$ \mu\f$
00356 @returns The mode
00357 @ingroup gStorm
00358 */
00359 inline double log_normal_mode(double mu, double sigma)
00360 {
00361     return exp(mu - sigma * sigma);
00362 }
00363 
00364 /**Log-normal distribution. This is given by:
00365 \f{eqnarray}{
00366     P(x)     &=& \frac{1}{x\sigma\sqrt{2\pi}} e^{-\frac{(\ln x - \mu)^2}{s\sigma^2}}\\
00367     \ln P(x) &=& -\frac{(\ln x - \mu)^2}{s\sigma^2} - \ln x - \ln\sigma\sqrt{2\pi}.
00368 \f}
00369 @param x \e x
00370 @param mu \f$\mu\f$
00371 @param sigma \f$\sigma\f$
00372 @ingroup gStorm
00373 */
00374 inline double log_log_normal(double x, double mu, double sigma)
00375 {
00376     return -sq(ln(x) - mu) / (2*sq(sigma)) - ln(x) - ln(sigma * sqrt(2*M_PI));
00377 }
00378 
00379 /**Derivative of the log of the log-normal distribution:
00380 \f[
00381     \frac{\partial \ln P(x)}{\partial x} = -\frac{1}{x}\left(1 + \frac{\ln x - \mu}{\sigma^2}\right).
00382 \f]
00383 @param x \e x
00384 @param mu \f$\mu\f$
00385 @param sigma \f$\sigma\f$
00386 @ingroup gStorm
00387 */
00388 inline double diff_log_log_normal(double x, double mu, double sigma)
00389 {
00390     return -(1 + (ln(x) - mu)/sq(sigma)) / x;
00391 }
00392 
00393 
00394 /**Second derivative of the log of the log-normal distribution:
00395 \f[
00396     \frac{\partial^2 \ln P(x)}{\partial x^2} = \frac{1}{x^2}\left(1 + \frac{\ln x - \mu}{\sigma^2} - \frac{1}{\sigma^2}\right).
00397 \f]
00398 @param x \e x
00399 @param mu \f$\mu\f$
00400 @param sigma \f$\sigma\f$
00401 @ingroup gStorm
00402 */
00403 inline double hess_log_log_normal(double x, double mu, double sigma)
00404 {
00405     return (1 + (ln(x) - mu - 1)/sq(sigma)) / sq(x);
00406 }
00407 
00408 
00409 #endif