ThreeB 1.1
|
00001 #include <cstdlib> 00002 #include <cerrno> 00003 #include <cstring> 00004 #include <stack> 00005 #include <algorithm> 00006 #include <climits> 00007 #include <iomanip> 00008 #include <map> 00009 #include <tr1/memory> 00010 #include <cvd/image_io.h> 00011 #include <cvd/image_convert.h> 00012 #include <cvd/morphology.h> 00013 #include <cvd/connected_components.h> 00014 #include <cvd/draw.h> 00015 #include <cvd/vector_image_ref.h> 00016 00017 #include <cvd/random.h> 00018 #include <cvd/timer.h> 00019 #include <gvars3/instances.h> 00020 00021 #include <TooN/functions/derivatives.h> 00022 #include <TooN/determinant.h> 00023 #include <TooN/SymEigen.h> 00024 #include <TooN/optimization/conjugate_gradient.h> 00025 00026 #include "conjugate_gradient_only.h" 00027 #include "forward_algorithm.h" 00028 #include "numerical_derivatives.h" 00029 #include "storm.h" 00030 #include "storm_imagery.h" 00031 #include "debug.h" 00032 #include "sampled_multispot.h" 00033 #include "mt19937.h" 00034 #include "utility.h" 00035 #include "multispot5.h" 00036 00037 00038 //For benchmarking... 00039 #define TIME(X) 00040 //#define TIME(X) X 00041 00042 using namespace std; 00043 using namespace CVD; 00044 using namespace GVars3; 00045 using namespace TooN; 00046 using namespace std::tr1; 00047 00048 ///Empty destructor 00049 UserInterfaceCallback::~UserInterfaceCallback(){} 00050 00051 ///User interface callback class which does nothing. 00052 class NullUICallback: public UserInterfaceCallback 00053 { 00054 void per_spot(int, int, int, int){}; 00055 void per_modification(int, int, int){}; 00056 void per_pass(int, int, const std::vector<TooN::Vector<4> >&){}; 00057 void perhaps_stop(){}; 00058 }; 00059 00060 ///Factory function to generate an instance of NullGraphics 00061 ///@ingroup gStorm 00062 auto_ptr<UserInterfaceCallback> null_ui() 00063 { 00064 return auto_ptr<UserInterfaceCallback>(new NullUICallback); 00065 } 00066 00067 00068 //Declare the graphics classes. 00069 //These provide all the debug drawing operations so that the code can run in GUI and 00070 //headless mode easily and without macros. 00071 FitSpotsGraphics::~FitSpotsGraphics(){} 00072 00073 ///Graphics class which does absoloutely nothing 00074 ///@ingroup gStorm 00075 class NullGraphics: public FitSpotsGraphics 00076 { 00077 public: 00078 virtual void init(CVD::ImageRef){} 00079 virtual void draw_krap(const std::vector<TooN::Vector<4> >&, const CVD::Image<CVD::byte>&, const BBox&, int, TooN::Vector<4>){} 00080 virtual void swap(){} 00081 virtual void draw_pixels(const std::vector<CVD::ImageRef>&, float, float, float, float){} 00082 virtual void draw_bbox(const BBox&){} 00083 virtual void glDrawCross(const TooN::Vector<2>&, int){} 00084 virtual ~NullGraphics(){} 00085 }; 00086 00087 ///Factory function to generate an instance of NullGraphics 00088 ///@ingroup gStorm 00089 auto_ptr<FitSpotsGraphics> null_graphics() 00090 { 00091 return auto_ptr<FitSpotsGraphics>(new NullGraphics); 00092 } 00093 00094 00095 ///There are two sensible ways of storing the state vector of spot positions. 00096 ///This function converts between them. See also spots_to_vector. 00097 ///@param s list of spots to convert 00098 ///@ingroup gUtility 00099 Vector<> spots_to_Vector(const vector<Vector<4> >& s) 00100 { 00101 Vector<> r(s.size()*4); 00102 for(unsigned int i=0; i < s.size(); i++) 00103 { 00104 r[i*4+0] = s[i][0]; 00105 r[i*4+1] = s[i][1]; 00106 r[i*4+2] = s[i][2]; 00107 r[i*4+3] = s[i][3]; 00108 } 00109 return r; 00110 } 00111 00112 ///There are two sensible ways of storing the state vector of spot positions. 00113 ///This function converts between them. See also spots_to_Vector. 00114 ///@param s list of spots to convert 00115 ///@ingroup gUtility 00116 vector<Vector<4> > spots_to_vector(const Vector<>& s) 00117 { 00118 vector<Vector<4> > r(s.size()/4); 00119 for(unsigned int i=0; i < r.size(); i++) 00120 r[i] = s.slice<Dynamic, 4>(i*4, 4); 00121 return r; 00122 } 00123 00124 ///Normalize an image for display purposes. 00125 ///@ingroup gUtility 00126 Image<byte> scale_to_bytes(const Image<float>& im, float lo, float hi) 00127 { 00128 Image<byte> out(im.size()); 00129 for(int r=0; r < out.size().y-0; r++) 00130 for(int c=0; c < out.size().x-0; c++) 00131 out[r][c] = (int)floor((im[r][c]-lo)*255/(hi-lo)); 00132 return out; 00133 } 00134 00135 ///Normalize an image for display purposes. 00136 ///@ingroup gUtility 00137 Image<byte> scale_to_bytes(const Image<float>& im) 00138 { 00139 float lo = *min_element(im.begin(), im.end()); 00140 float hi = *max_element(im.begin(), im.end()); 00141 Image<byte> out(im.size()); 00142 for(int r=0; r < out.size().y-0; r++) 00143 for(int c=0; c < out.size().x-0; c++) 00144 out[r][c] = (int)floor((im[r][c]-lo)*255/(hi-lo)); 00145 00146 return out; 00147 } 00148 00149 ///Average the input image stack for display purposes 00150 ///@ingroup gUtility 00151 Image<float> average_image(const vector<Image<float> >& ims) 00152 { 00153 assert_same_size(ims); 00154 Image<float> r(ims[0].size(), 0); 00155 00156 for(unsigned int i=0; i < ims.size(); i++) 00157 transform(r.begin(), r.end(), ims[i].begin(), r.begin(), plus<float>()); 00158 00159 transform(r.begin(), r.end(), r.begin(), bind2nd(multiplies<float>(), 1./ims.size())); 00160 return r; 00161 } 00162 00163 00164 //////////////////////////////////////////////////////////////////////////////// 00165 //////////////////////////////////////////////////////////////////////////////// 00166 //////////////////////////////////////////////////////////////////////////////// 00167 //////////////////////////////////////////////////////////////////////////////// 00168 //////////////////////////////////////////////////////////////////////////////// 00169 //////////////////////////////////////////////////////////////////////////////// 00170 //////////////////////////////////////////////////////////////////////////////// 00171 //////////////////////////////////////////////////////////////////////////////// 00172 00173 ///Closure hoding the data required do use GibbsSampler2 00174 ///See FitSpots for naming of variables. 00175 ///@ingroup gStorm 00176 class DataForMCMC 00177 { 00178 protected: 00179 const vector<ImageRef>& pixels; 00180 const vector<vector<double> >& pixel_intensities;//[frame][pixel] 00181 const double mu_brightness, sigma_brightness, mu_blur, sigma_blur; 00182 const double variance; 00183 const int samples, sample_iterations; 00184 const Matrix<3> A; 00185 const Vector<3> pi; 00186 MT19937& rng; 00187 public: 00188 00189 MT19937& get_rng()const 00190 { 00191 return rng; 00192 } 00193 00194 public: 00195 DataForMCMC(const vector<ImageRef>& pixels_, 00196 const vector<vector<double> >& pixel_intensities_, 00197 double mu_brightness_, 00198 double sigma_brightness_, 00199 double mu_blur_, 00200 double sigma_blur_, 00201 double variance_, 00202 int samples_, 00203 int sample_iterations_, 00204 Matrix<3> A_, 00205 Vector<3> pi_, 00206 MT19937& rng_) 00207 :pixels(pixels_), 00208 pixel_intensities(pixel_intensities_), 00209 mu_brightness(mu_brightness_), 00210 sigma_brightness(sigma_brightness_), 00211 mu_blur(mu_blur_), 00212 sigma_blur(sigma_blur_), 00213 variance(variance_), 00214 samples(samples_), 00215 sample_iterations(sample_iterations_), 00216 A(A_), 00217 pi(pi_), 00218 rng(rng_) 00219 {} 00220 }; 00221 00222 ///Class implementing the Kahan summation algorithm 00223 ///to allow accurate summation of very large numbers of 00224 ///doubles. 00225 ///@ingroup gUtility 00226 class Kahan{ 00227 private: 00228 double y; ///< Input with the compensation removed. Temporary working space. 00229 double c; ///< Running compenstation for low-order bits. 00230 double t; ///< y + sum, which loses low order bits of y. Temporary working space. 00231 public: 00232 double sum; ///< running sum 00233 00234 Kahan() 00235 :c(0),sum(0) 00236 {} 00237 00238 /// Add a number to the running sum 00239 /// @param i Number to add 00240 void add(double i) 00241 { 00242 //y = input -c 00243 y = i; 00244 y-= c; 00245 00246 //t = sum + y 00247 t = sum; 00248 t += y; 00249 00250 //c = (t - sum) - y 00251 //c = ((sum + y) - sum) - y) 00252 c = t; 00253 c -= sum; 00254 c -= y; 00255 sum = t; 00256 } 00257 }; 00258 00259 00260 ///Class for computing the negitve free energy using thermodynamic integration. 00261 class NegativeFreeEnergy: public DataForMCMC 00262 { 00263 public: 00264 00265 ///@param d Necessary data 00266 NegativeFreeEnergy(const DataForMCMC& d) 00267 :DataForMCMC(d) 00268 { 00269 } 00270 00271 ///Give the noise variance given a sample number and growth parameters 00272 ///@param sample Sample number 00273 ///@param samples Total number of samples 00274 ///@param base_sigma Starting value of sigme 00275 ///@param scale_pow Exponent scaling 00276 double variance_from_sample(double sample, double samples, double base_sigma, double scale_pow) const 00277 { 00278 double scale = pow(1.25, sample * 1. / samples * scale_pow); 00279 double sigma = base_sigma * scale; 00280 double new_variance = sq(sigma); 00281 00282 return new_variance; 00283 } 00284 00285 ///Estimate free energy using the Slow Growth Thermodynamic Integration method given in 00286 ///Probalistic Inference Using Markov Chain Monte Carlo Methods, Radford. M. Neal, 1993 00287 ///Except using a 5 point stencil instead of forward differenceing in Eq 6.30 00288 ///@param spots list of spots 00289 ///@param spot_pixels Mask around each spot to use to save on computation 00290 double compute_with_mask(const Vector<>& spots, const vector<vector<int> >& spot_pixels) const 00291 { 00292 //Estimate free energy using the Slow Growth Thermodynamic Integration method given in 00293 //Probalistic Inference Using Markov Chain Monte Carlo Methods, Radford. M. Neal, 1993 00294 //Except using a 5 point stencil instead of forward differenceing in Eq 6.30 00295 double base_sigma = sqrt(variance); // should be 1 00296 double scale_pow = 100.0; 00297 00298 const unsigned int nspots = spots.size()/4; 00299 const unsigned int nframes = pixel_intensities.size(); 00300 const unsigned int npixels = pixels.size(); 00301 assert(spots.size() %4 == 0); 00302 assert(spot_pixels.size() == nspots); 00303 00304 //Compute the intensities and derivatives for all spot 00305 vector<vector<double> > spot_intensity; //[spot][pixel] 00306 for(unsigned int i=0; i < nspots; i++) 00307 spot_intensity.push_back(compute_spot_intensity(pixels, spots.slice<Dynamic,4>(i*4,4))); 00308 00309 GibbsSampler2 sampler(pixel_intensities, spot_intensity, spots_to_vector(spots), spot_pixels, A, pi, variance, sample_iterations); 00310 00311 double sum = 0; 00312 Kahan ksum; 00313 for(int sample=0; sample < samples; sample++) 00314 { 00315 //Compute the positions of the surrounding steps 00316 double var1 = variance_from_sample(sample-2, samples, base_sigma, scale_pow); 00317 double var2 = variance_from_sample(sample-1, samples, base_sigma, scale_pow); 00318 double var3 = variance_from_sample(sample+1, samples, base_sigma, scale_pow); 00319 double var4 = variance_from_sample(sample+2, samples, base_sigma, scale_pow); 00320 00321 //Take a sample 00322 sampler.set_variance(var2); 00323 sampler.next(DataForMCMC::get_rng()); 00324 00325 //Compute the SSD. This is fixed regardless of sigma. 00326 double err_sum=0; 00327 for(unsigned int frame=0; frame < nframes; frame++) 00328 for(unsigned int pixel=0; pixel < npixels; pixel++) 00329 err_sum -= sq(pixel_intensities[frame][pixel] - sampler.sample_intensities()[frame][pixel]); 00330 00331 //Compute the derivative using a five point stencil 00332 //This could be done in a better but less clear way 00333 double e1 = err_sum / (2*var1) - npixels*nframes*::log(2*M_PI*var1)/2; 00334 double e2 = err_sum / (2*var2) - npixels*nframes*::log(2*M_PI*var2)/2; 00335 double e3 = err_sum / (2*var3) - npixels*nframes*::log(2*M_PI*var3)/2; 00336 double e4 = err_sum / (2*var4) - npixels*nframes*::log(2*M_PI*var4)/2; 00337 sum += (-e1 + 8*e2 - 8*e3 + e4)/12; 00338 00339 ksum.add(-e1/12); 00340 ksum.add(8*e2/12); 00341 ksum.add(-8*e3/12); 00342 ksum.add(e4/12); 00343 } 00344 00345 double log_final = (log(variance_from_sample(samples, samples, base_sigma, scale_pow)*2*M_PI)/2) * npixels * nframes; 00346 00347 double priors=0; 00348 for(unsigned int i=0; i < nspots; i++) 00349 { 00350 priors += log_log_normal(spots[i*4+0], mu_brightness, sigma_brightness); 00351 priors += log_log_normal(spots[i*4+1], mu_blur, sigma_blur); 00352 } 00353 00354 /*cout << "Thermo:\n"; 00355 cout << "sum: " << sum -log_final << endl; 00356 cout << "kah: " << ksum.sum -log_final << endl; 00357 cout << "priors: " << priors + sum -log_final << endl; 00358 cout << " kah: " << priors + ksum.sum -log_final << endl; 00359 */ 00360 //cout << log_final << endl; 00361 //cout << sum + log_final << endl; 00362 00363 00364 sampler.set_variance(variance); 00365 return -(sum+priors - log_final); 00366 } 00367 00368 ///Estimate free energy using the Slow Growth Thermodynamic Integration method given in 00369 ///Probalistic Inference Using Markov Chain Monte Carlo Methods, Radford. M. Neal, 1993 00370 ///Except using a 5 point stencil instead of forward differenceing in Eq 6.30 00371 ///@param spots list of spots 00372 double operator()(const Vector<>& spots) const 00373 { 00374 double base_sigma = sqrt(variance); // should be 1 00375 double scale_pow = 100.0; 00376 00377 const unsigned int nspots = spots.size()/4; 00378 const unsigned int nframes = pixel_intensities.size(); 00379 const unsigned int npixels = pixels.size(); 00380 assert(spots.size() %4 == 0); 00381 00382 //Compute the intensities and derivatives for all spot 00383 vector<vector<double> > spot_intensity; //[spot][pixel] 00384 for(unsigned int i=0; i < nspots; i++) 00385 spot_intensity.push_back(compute_spot_intensity(pixels, spots.slice<Dynamic,4>(i*4,4))); 00386 00387 GibbsSampler sampler(pixel_intensities, spot_intensity, spots_to_vector(spots), A, pi, variance, sample_iterations); 00388 00389 double sum = 0; 00390 Kahan ksum; 00391 for(int sample=0; sample < samples; sample++) 00392 { 00393 //Compute the positions of the surrounding steps 00394 double var1 = variance_from_sample(sample-2, samples, base_sigma, scale_pow); 00395 double var2 = variance_from_sample(sample-1, samples, base_sigma, scale_pow); 00396 double var3 = variance_from_sample(sample+1, samples, base_sigma, scale_pow); 00397 double var4 = variance_from_sample(sample+2, samples, base_sigma, scale_pow); 00398 00399 //Take a sample 00400 sampler.set_variance(var2); 00401 sampler.next(DataForMCMC::get_rng()); 00402 00403 //Compute the SSD. This is fixed regardless of sigma. 00404 double err_sum=0; 00405 for(unsigned int frame=0; frame < nframes; frame++) 00406 for(unsigned int pixel=0; pixel < npixels; pixel++) 00407 err_sum -= sq(pixel_intensities[frame][pixel] - sampler.sample_intensities()[frame][pixel]); 00408 00409 //Compute the derivative using a five point stencil 00410 //This could be done in a better but less clear way 00411 double e1 = err_sum / (2*var1) - npixels*nframes*::log(2*M_PI*var1)/2; 00412 double e2 = err_sum / (2*var2) - npixels*nframes*::log(2*M_PI*var2)/2; 00413 double e3 = err_sum / (2*var3) - npixels*nframes*::log(2*M_PI*var3)/2; 00414 double e4 = err_sum / (2*var4) - npixels*nframes*::log(2*M_PI*var4)/2; 00415 sum += (-e1 + 8*e2 - 8*e3 + e4)/12; 00416 00417 ksum.add(-e1/12); 00418 ksum.add(8*e2/12); 00419 ksum.add(-8*e3/12); 00420 ksum.add(e4/12); 00421 } 00422 00423 double log_final = (log(variance_from_sample(samples, samples, base_sigma, scale_pow)*2*M_PI)/2) * npixels * nframes; 00424 00425 double priors=0; 00426 for(unsigned int i=0; i < nspots; i++) 00427 { 00428 priors += log_log_normal(spots[i*4+0], mu_brightness, sigma_brightness); 00429 priors += log_log_normal(spots[i*4+1], mu_blur, sigma_blur); 00430 } 00431 00432 /*cout << "Thermo:\n"; 00433 cout << "sum: " << sum -log_final << endl; 00434 cout << "kah: " << ksum.sum -log_final << endl; 00435 cout << "priors: " << priors + sum -log_final << endl; 00436 cout << " kah: " << priors + ksum.sum -log_final << endl; 00437 */ 00438 //cout << log_final << endl; 00439 //cout << sum + log_final << endl; 00440 00441 00442 sampler.set_variance(variance); 00443 return -(sum+priors - log_final); 00444 } 00445 }; 00446 00447 /// Class for sorting a list of indexes to an array of spots lexicographically 00448 /// according to the 2D positions of the spots. 00449 /// 00450 ///@param Cmp comparator function to specify less or greater 00451 ///@param First most significant position index 00452 ///@ingroup gMultiSpot 00453 template<class Cmp, int First> struct IndexLexicographicPosition{ 00454 const vector<Vector<4> >& spots; ///< Keep around the array of spots for later comprison 00455 00456 /// @param s Vector to sort indices of 00457 IndexLexicographicPosition(const vector<Vector<4> >& s) 00458 :spots(s) 00459 {} 00460 00461 00462 static const int Second = First==2?3:2; ///< Second most siginifcant position index for sorting 00463 00464 /// Compare two indexes into the array of spots 00465 bool operator()(int a, int b) 00466 { 00467 Cmp cmp; 00468 00469 if(cmp(spots[a][First], spots[b][First])) 00470 return true; 00471 else if(spots[a][First] == spots[b][First]) 00472 return cmp(spots[a][Second], spots[b][Second]); 00473 else 00474 return false; 00475 } 00476 }; 00477 00478 00479 ///Closure holding image data generated using samples drawn from the model. 00480 ///NB this is used with one spot removed (i.e. set to dark). As a result, the data 00481 ///is treated as the background when considering that spot in isolation. 00482 ///See FitSpots for naming of variables. 00483 ///@ingroup gStorm 00484 struct SampledBackgroundData 00485 { 00486 const vector<vector<vector<double> > >& sample_intensities_without_spot; //[sample][frame][pixel] 00487 const vector<vector<double> >& pixel_intensities; //[frame][pixel] 00488 const vector<ImageRef> pixels; 00489 00490 double mu_brightness, sigma_brightness, mu_blur, sigma_blur; 00491 const Matrix<3> A; 00492 const Vector<3> pi; 00493 double variance; 00494 00495 const vector<int> O; 00496 00497 SampledBackgroundData( 00498 const vector<vector<vector<double> > >& sample_intensities_without_spot_, 00499 const vector<vector<double> >& pixel_intensities_, 00500 const vector<ImageRef> pixels_, 00501 double mu_brightness_, 00502 double sigma_brightness_, 00503 double mu_blur_, 00504 double sigma_blur_, 00505 const Matrix<3> A_, 00506 const Vector<3> pi_, 00507 double variance_) 00508 :sample_intensities_without_spot(sample_intensities_without_spot_), 00509 pixel_intensities(pixel_intensities_), 00510 pixels(pixels_), 00511 mu_brightness(mu_brightness_), 00512 sigma_brightness(sigma_brightness_), 00513 mu_blur(mu_blur_), 00514 sigma_blur(sigma_blur_), 00515 A(A_), 00516 pi(pi_), 00517 variance(variance_), 00518 O(sequence(pixel_intensities.size())) 00519 { 00520 } 00521 }; 00522 00523 //!@cond Doxygen_Suppress 00524 //Do not use. 00525 struct SpotProbabilityWithSampledBackgroundFAKE: public SampledBackgroundData 00526 { 00527 SpotProbabilityWithSampledBackgroundFAKE(const SampledBackgroundData& d) 00528 :SampledBackgroundData(d) 00529 { 00530 } 00531 00532 //Compute the probability of spot 00533 double operator()(const Vector<4>& spot) const 00534 { 00535 vector<double> spot_intensities = compute_spot_intensity(pixels, spot); 00536 00537 double sum_log_prob = 0; 00538 00539 for(unsigned int s=0; s < sample_intensities_without_spot.size(); s++) 00540 { 00541 SpotWithBackground B(sample_intensities_without_spot[s], spot_intensities, pixel_intensities, variance); 00542 double log_prob = forward_algorithm(A, pi, B, O); 00543 00544 double logprior = log_log_normal(spot[0], mu_brightness, sigma_brightness) + 00545 log_log_normal(spot[1], mu_blur, sigma_blur); 00546 00547 //cout << setprecision(10) <<fixed << "Prob : " << log_prob + logprior << endl; 00548 00549 sum_log_prob += log_prob + logprior; 00550 } 00551 00552 double average_log_prob = sum_log_prob / sample_intensities_without_spot.size(); 00553 00554 // cout << "Ave Prob : " << average_log_prob << endl; 00555 00556 if(spot[0] < 0 || spot[1] < 0) 00557 return 1e100; 00558 00559 return average_log_prob; 00560 } 00561 }; 00562 //@endcond 00563 00564 ///Compute the derivative of the negative log probability with respect 00565 ///to the parameters of one spot, given some samples of the other spots. 00566 ///@ingroup gStorm 00567 struct SpotNegProbabilityDiffWithSampledBackground: public SampledBackgroundData 00568 { 00569 ///@param d Necessary data for construction 00570 SpotNegProbabilityDiffWithSampledBackground(const SampledBackgroundData& d) 00571 :SampledBackgroundData(d) 00572 { 00573 } 00574 00575 ///Compute the probability of spot 00576 ///@param spot Spot position 00577 Vector<4> operator()(const Vector<4>& spot) const 00578 { 00579 if(spot[0] <= 0 || spot[1] <= 0) 00580 return Ones * std::numeric_limits<double>::quiet_NaN(); 00581 00582 vector<pair<double, Vector<4> > > spot_intensities = compute_spot_intensity_derivatives(pixels, spot); 00583 00584 Vector<4> sum_diff_log = Zeros; 00585 00586 for(unsigned int s=0; s < sample_intensities_without_spot.size(); s++) 00587 { 00588 SpotWithBackground B(sample_intensities_without_spot[s], spot_intensities, pixel_intensities, variance); 00589 00590 pair<double, Vector<4> > r = forward_algorithm_deriv(A, pi, B, O); 00591 00592 sum_diff_log += r.second; 00593 } 00594 00595 Vector<4> diff_log = sum_diff_log / sample_intensities_without_spot.size(); 00596 00597 //Compute the log probability of the prior 00598 Vector<4> logprior_deriv = makeVector(diff_log_log_normal(spot[0], mu_brightness, sigma_brightness), 00599 diff_log_log_normal(spot[1], mu_blur, sigma_blur), 0, 0); 00600 00601 return -(diff_log + logprior_deriv); 00602 } 00603 }; 00604 00605 00606 ///Class for computing the Hessian of the negative free energy. 00607 ///@ingroup gStorm 00608 class FreeEnergyHessian: public DataForMCMC 00609 { 00610 public: 00611 00612 ///Constructor 00613 ///@param d All data required 00614 FreeEnergyHessian(const DataForMCMC& d) 00615 :DataForMCMC(d) 00616 { 00617 } 00618 00619 ///Compute the Hessian 00620 ///@param spots All spot positions 00621 ///@param spot spot to compute hessian for 00622 Matrix<4> hessian(const vector<Vector<4> >& spots, int spot) const 00623 { 00624 cout << "----Computing pure MCMC hessian\n"; 00625 const unsigned int nspots = spots.size(); 00626 const unsigned int nframes = pixel_intensities.size(); 00627 const unsigned int npixels = pixels.size(); 00628 cout << spot << " " << nspots << " " << nframes << " " << npixels << endl; 00629 00630 vector<vector<double> > spot_intensity; //[spot][pixel] 00631 for(unsigned int i=0; i < nspots; i++) 00632 spot_intensity.push_back(compute_spot_intensity(pixels, spots[i])); 00633 00634 vector<tuple<double, Vector<4>, Matrix<4> > > spot_hess_etc = compute_spot_intensity_hessian(pixels, spots[spot]); 00635 00636 GibbsSampler sampler(pixel_intensities, spot_intensity, spots, A, pi, variance, sample_iterations); 00637 00638 //Compute derivative of log probability, summed (ie integrated) 00639 Matrix<4> sum_hess1 = Zeros(spots.size()); 00640 Matrix<4> sum_hess2 = Zeros(spots.size()); 00641 Vector<4> sum_deriv = Zeros(spots.size()); 00642 00643 for(int sample=0; sample < samples; sample++) 00644 { 00645 sampler.next(rng); 00646 00647 //Compute d log P(data | x, model) / d model, for a given sample 00648 //And the hessian 00649 Matrix<4> hess = Zeros(spots.size()); 00650 Vector<4> deriv = Zeros(spots.size()); 00651 for(unsigned int frame=0; frame < nframes; frame++) 00652 { 00653 for(unsigned int pixel=0; pixel < npixels; pixel++) 00654 { 00655 double e = pixel_intensities[frame][pixel] - sampler.sample_intensities()[frame][pixel]; 00656 //Build up the derivative 00657 if(sampler.sample()[spot][frame] == 0) 00658 { 00659 hess += e * get<2>(spot_hess_etc[pixel]) - get<1>(spot_hess_etc[pixel]).as_col() * get<1>(spot_hess_etc[pixel]).as_row(); 00660 deriv += e * get<1>(spot_hess_etc[pixel]); 00661 00662 } 00663 } 00664 } 00665 00666 hess[0][0] += hess_log_log_normal(spots[spot][0], mu_brightness, sigma_brightness); 00667 hess[1][1] += hess_log_log_normal(spots[spot][1], mu_blur, sigma_blur); 00668 sum_hess1 += hess; 00669 00670 deriv[0] += diff_log_log_normal(spots[spot][0], mu_brightness, sigma_brightness); 00671 deriv[1] += diff_log_log_normal(spots[spot][1], mu_blur, sigma_blur); 00672 00673 sum_hess2 += deriv.as_col() * deriv.as_row(); 00674 00675 sum_deriv = sum_deriv + deriv; 00676 } 00677 00678 sum_hess1 /= (samples * variance); 00679 sum_hess2 /= (samples * variance); 00680 sum_deriv /= (samples * variance); 00681 00682 00683 cout << sum_hess1 << endl; 00684 cout << sum_hess2 << endl; 00685 cout << sum_deriv.as_col() * sum_deriv.as_row() << endl; 00686 00687 cout << "......." << sum_deriv << endl; 00688 //Put in the prior 00689 //The derivative prior parts cancel out. 00690 //Rather sensibly this means that the second derivatives can be 00691 //computed without reference to the prior, and then the prior can 00692 //be added in later, i.e.: P(data, parameters) = P(data|parameter) P(parameters) 00693 00694 //The second derivatives have been constructed to be diagonal 00695 DiagonalMatrix<4> hess_prior = Zeros(spots.size()); 00696 00697 cout << "sum of parts = \n" << sum_hess1 + sum_hess2 - sum_deriv.as_col() * sum_deriv.as_row() << endl; 00698 //TooN cannot currently add DiagonalMatrix to Matrix!! 00699 //sum_hess.diagonal_slice() += hess_prior.diagonal_slice(); 00700 00701 cout << "++++Done Computing pure MCMC hessian\n"; 00702 return sum_hess1 + sum_hess2 - sum_deriv.as_col() * sum_deriv.as_row(); 00703 } 00704 }; 00705 00706 ///Comparator functor for the first element of a std::pair 00707 struct LessSecond 00708 { 00709 ///Comparison function 00710 ///@param a 00711 ///@param b 00712 template<class A, class B> bool operator()(const pair<A,B>& a, const pair<A,B>& b) const 00713 { 00714 return a.second < b.second; 00715 } 00716 }; 00717 00718 //!@cond Doxygen_Suppress 00719 struct NthDeriv{ 00720 00721 const SpotNegProbabilityDiffWithSampledBackground& compute_deriv; 00722 int i; 00723 00724 NthDeriv(const SpotNegProbabilityDiffWithSampledBackground& c, int ii) 00725 :compute_deriv(c),i(ii) 00726 {} 00727 00728 double operator()(const Vector<4>& f) const 00729 { 00730 return compute_deriv(f)[i]; 00731 } 00732 }; 00733 //!@endcond 00734 00735 ///Compute the Hessian of the log probability. The background is sampled rather sparsely, and the 00736 ///spot in question is sampled much more densely using FFBS. 00737 ///@param spot Spot parameters 00738 ///@param d Background brightness (from other spots) 00739 ///@param bs_iterations Exter backward sampling iterations 00740 ///@param rng Random number generator 00741 ///@returns the Hessian of the log probability around the spot 00742 Matrix<4> sampled_background_spot_hessian_ffbs(const Vector<4>& spot, const SampledBackgroundData& d, int bs_iterations, MT19937& rng) 00743 { 00744 vector<tuple<double, Vector<4>, Matrix<4> > > spot_hess_etc = compute_spot_intensity_hessian(d.pixels, spot); 00745 vector<double> spot_intensities = compute_spot_intensity(d.pixels, spot); 00746 00747 Matrix<4> sum_hess_log = Zeros; 00748 Matrix<4> sum_diff2_log = Zeros; 00749 00750 vector<State> current_sample; 00751 00752 const unsigned int nframes = d.pixel_intensities.size(); 00753 const unsigned int npixels = d.pixels.size(); 00754 00755 Matrix<4> sum_hess = Zeros; 00756 Vector<4> sum_deriv = Zeros; 00757 00758 vector<pair<Matrix<4>, Vector<4> > > hess_and_deriv_part(nframes); 00759 00760 for(unsigned int s=0; s < d.sample_intensities_without_spot.size(); s++) 00761 { 00762 SpotWithBackground B(d.sample_intensities_without_spot[s], spot_intensities, d.pixel_intensities, d.variance); 00763 00764 //Compute what the per-frame hess and deriv parts are 00765 //if the spot is on in a frame. 00766 for(unsigned int frame=0; frame < nframes; frame++) 00767 { 00768 Matrix<4> hess = Zeros; 00769 Vector<4> deriv = Zeros; 00770 00771 for(unsigned int pixel=0; pixel < npixels; pixel++) 00772 { 00773 double e = d.pixel_intensities[frame][pixel] - (d.sample_intensities_without_spot[s][frame][pixel] + spot_intensities[pixel]); 00774 //Build up the derivative 00775 hess += e * get<2>(spot_hess_etc[pixel]) - get<1>(spot_hess_etc[pixel]).as_col() * get<1>(spot_hess_etc[pixel]).as_row(); 00776 deriv += e * get<1>(spot_hess_etc[pixel]); 00777 } 00778 hess_and_deriv_part[frame] = make_pair(hess, deriv); 00779 } 00780 00781 //Forward filtering 00782 std::vector<array<double, 3> > delta = forward_algorithm_delta(d.A, d.pi, B, d.O); 00783 00784 for(int i=0; i < bs_iterations; i++) 00785 { 00786 current_sample = backward_sampling<3,State>(d.A, delta, rng); 00787 00788 Matrix<4> hess = Zeros; 00789 Vector<4> deriv = Zeros; 00790 for(unsigned int frame=0; frame < nframes; frame++) 00791 if(current_sample[frame] == 0) 00792 { 00793 hess += hess_and_deriv_part[frame].first; 00794 deriv += hess_and_deriv_part[frame].second; 00795 } 00796 00797 sum_hess += hess + deriv.as_col() * deriv.as_row(); 00798 sum_deriv += deriv; 00799 } 00800 } 00801 00802 sum_hess /= (bs_iterations * d.sample_intensities_without_spot.size() * d.variance); 00803 sum_deriv /= (bs_iterations * d.sample_intensities_without_spot.size() * d.variance); 00804 00805 sum_hess -= sum_deriv.as_col() * sum_deriv.as_row(); 00806 00807 sum_hess[0][0] += hess_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness); 00808 sum_hess[1][1] += hess_log_log_normal(spot[1], d.mu_blur, d.sigma_blur); 00809 sum_deriv[0] += diff_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness); 00810 sum_deriv[1] += diff_log_log_normal(spot[1], d.mu_blur, d.sigma_blur); 00811 00812 //cout << "Turboderiv:" << sum_deriv << endl; 00813 //cout << "Turbohess:\n" << sum_hess << endl; 00814 00815 return sum_hess; 00816 } 00817 00818 ///Debugging function. Not mathematically correct. Do not use. 00819 Matrix<4> sampled_background_spot_hessian2(const Vector<4>& spot, const SampledBackgroundData& d) 00820 { 00821 vector<tuple<double, Vector<4>, Matrix<4> > > spot_intensities = compute_spot_intensity_hessian(d.pixels, spot); 00822 00823 Matrix<4> sum_hess_log = Zeros; 00824 Matrix<4> sum_diff2_log = Zeros; 00825 00826 for(unsigned int s=0; s < d.sample_intensities_without_spot.size(); s++) 00827 { 00828 SpotWithBackground B(d.sample_intensities_without_spot[s], spot_intensities, d.pixel_intensities, d.variance); 00829 00830 double prob; 00831 Vector<4> diff; 00832 Matrix<4> hess; 00833 00834 tie(prob, diff, hess) = forward_algorithm_hessian(d.A, d.pi, B, d.O); 00835 00836 sum_hess_log += hess; 00837 00838 diff += makeVector(diff_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness), diff_log_log_normal(spot[1], d.mu_blur, d.sigma_blur), 0, 0); 00839 sum_diff2_log += diff.as_col() * diff.as_row(); 00840 } 00841 00842 Matrix<4> hess_log = sum_hess_log / d.sample_intensities_without_spot.size(); 00843 Matrix<4> diff2_log = sum_diff2_log / d.sample_intensities_without_spot.size(); 00844 00845 //Add in the prior 00846 00847 hess_log[0][0] += hess_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness); 00848 hess_log[1][1] += hess_log_log_normal(spot[1], d.mu_blur, d.sigma_blur); 00849 00850 return hess_log + diff2_log; 00851 } 00852 00853 ///Debugging function. Not mathematically correct. Do not use. 00854 Matrix<4> sampled_background_spot_hessian_FAKE(const Vector<4>& spot, const SampledBackgroundData& d) 00855 { 00856 vector<tuple<double, Vector<4>, Matrix<4> > > spot_intensities = compute_spot_intensity_hessian(d.pixels, spot); 00857 00858 Matrix<4> sum_hess_log = Zeros; 00859 00860 for(unsigned int s=0; s < d.sample_intensities_without_spot.size(); s++) 00861 { 00862 SpotWithBackground B(d.sample_intensities_without_spot[s], spot_intensities, d.pixel_intensities, d.variance); 00863 00864 double prob; 00865 Vector<4> diff; 00866 Matrix<4> hess; 00867 00868 tie(prob, diff, hess) = forward_algorithm_hessian(d.A, d.pi, B, d.O); 00869 00870 sum_hess_log += hess; 00871 } 00872 00873 Matrix<4> hess_log = sum_hess_log / d.sample_intensities_without_spot.size(); 00874 00875 //Add in the prior 00876 00877 hess_log[0][0] += hess_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness); 00878 hess_log[1][1] += hess_log_log_normal(spot[1], d.mu_blur, d.sigma_blur); 00879 00880 return hess_log; 00881 } 00882 00883 ///Which pixels belong to a given spot? 00884 ///Find the indices of those pixels 00885 ///@ingroup gStorm 00886 void get_spot_pixels(const vector<ImageRef>& pixels, const Vector<4>& spot, vector<int>& out) 00887 { 00888 //Go out to three sigma 00889 00890 vector<ImageRef> pix = getDisc(spot[1]*6 + 1); 00891 out.resize(0); 00892 ImageRef offset = ir_rounded(spot.slice<2,2>()); 00893 for(unsigned int j=0; j < pix.size(); j++) 00894 { 00895 int pos = lower_bound(pixels.begin(), pixels.end(), pix[j] + offset) - pixels.begin(); 00896 if(pos != (int)pixels.size() && pixels[pos] == pix[j] + offset) 00897 out.push_back(pos); 00898 } 00899 00900 if(out.size() == 0) 00901 { 00902 cout << "********************************\n"; 00903 cout << "********************************\n"; 00904 cout << "********************************\n"; 00905 cout << "********************************\n"; 00906 cout << "********************************\n"; 00907 cout << "Oe noes!11one\n"; 00908 cout << pix.size() << endl; 00909 } 00910 } 00911 00912 00913 ///Tokenize a line 00914 ///@ingroup gUtility 00915 vector<string> split(const string& line) 00916 { 00917 vector<string> v; 00918 istringstream i(line); 00919 string s; 00920 00921 while(!i.eof()) 00922 { 00923 i >> s; 00924 if(i.fail()) 00925 break; 00926 v.push_back(s); 00927 } 00928 return v; 00929 } 00930 00931 ///Generic version of itoa. 00932 ///How many times has this been reimplemented?? 00933 ///@param x Value to convert to string 00934 ///@ingroup gUtility 00935 template<class C> inline string xtoa(const C& x) 00936 { 00937 ostringstream os; 00938 os << x; 00939 return os.str(); 00940 } 00941 00942 ///Inverse of xtoa() 00943 ///How many times has this been reimplemented?? 00944 ///@param s String to convert 00945 ///@param msg Mesage to print on error 00946 ///@ingroup gUtility 00947 template<class C> inline C atox(const string& s, const string& msg) 00948 { 00949 C c; 00950 istringstream i(s); 00951 i >> c; 00952 if(i.fail()) 00953 throw LogFileParseError("Error parsing " + msg + ". Text is `" + s + "'."); 00954 return c; 00955 } 00956 00957 /**Parser for multispot 5 log files. 00958 00959 Log files are mostly line oriented and contain various records 00960 00961 The main records are: 00962 00963 Iteraton: \#ITNUM 00964 MAIN: <list of spot parameters> 00965 00966 Pass: \#PASSNUM 00967 MT19937 <random number generator state> 00968 PASS\#PASSNUM: <list of spot parameters> 00969 ENDCHECKPOINT 00970 00971 Note that MAIN is redundant since it will be the same as the following PASS 1 (or the first pass 00972 computed if restoring from a checkpoint). 00973 00974 Data should only be considered valid after ENDCHECKPOINT has been read 00975 00976 Iteration is written once per iteration, not once per pass. (FIXME) 00977 00978 Which moron invented this file format??? 00979 00980 Note that the file format hasn't beren fixed, so that the output can easily be compared to the 00981 output of the historic version which is known to be good. 00982 00983 @param in Stream to parse file from 00984 @ingroup gStorm 00985 */ 00986 StateParameters parse_log_file(istream& in) 00987 { 00988 //A line read from the file 00989 string line; 00990 00991 //State lines known to be OK 00992 string rngline, passline, iterationline; 00993 bool state_ok=0; 00994 00995 //State lines read in, with flags of goodness 00996 string new_rngline, new_passline, new_iterationline; 00997 bool new_rngline_ok=0, new_passline_ok=0, new_iterationline_ok=0; 00998 00999 unsigned int lineno=0; 01000 bool doing_gvars = 0; 01001 01002 vector<ImageRef> pixels; 01003 01004 while(!in.eof()) 01005 { 01006 getline(in, line); 01007 if(in.fail()) 01008 break; 01009 01010 lineno++; 01011 01012 if(line == "ENDGVARLIST") 01013 { 01014 if(!doing_gvars) 01015 throw LogFileParseError("Spurious end of GVars"); 01016 doing_gvars = 0; 01017 } 01018 else if(doing_gvars) 01019 { 01020 GUI.ParseLine(line); 01021 } 01022 else if(line == "BEGINGVARLIST") 01023 { 01024 doing_gvars = 1; 01025 } 01026 if(line.substr(0, 11) == "Iteration: ") 01027 { 01028 new_iterationline = line; 01029 new_iterationline_ok = true; 01030 } 01031 else if(line.substr(0, 4) == "PASS") 01032 { 01033 new_passline = line; 01034 if(new_passline_ok) 01035 throw LogFileParseError("Duplicate PASS on line " + xtoa(lineno)); 01036 new_passline_ok = true; 01037 } 01038 else if(line.substr(0, 8) == "MT19937 ") 01039 { 01040 new_rngline = line; 01041 if(new_rngline_ok) 01042 throw LogFileParseError("Duplicate MT19937 on line " + xtoa(lineno)); 01043 01044 new_rngline_ok = true; 01045 01046 } 01047 else if(line == "ENDCHECKPOINT") 01048 { 01049 if(new_passline_ok && new_rngline_ok && new_iterationline_ok) 01050 { 01051 iterationline = new_iterationline; 01052 rngline = new_rngline; 01053 passline = new_passline; 01054 } 01055 else 01056 throw LogFileParseError("Reached checkpoint with missing data: " 01057 "it=" + xtoa(new_iterationline_ok) + 01058 " pa=" + xtoa(new_passline_ok) + 01059 " rg=" + xtoa(new_rngline_ok) + " on line " + xtoa(lineno)); 01060 01061 //Don't reset iteration since it only appears once for each entire 01062 //set of passes. 01063 new_rngline_ok = 0; 01064 new_passline_ok = 0; 01065 01066 state_ok = true; 01067 } 01068 else if(line.substr(0, 7) == "PIXELS ") 01069 { 01070 vector<string> l = split(line); 01071 if( (l.size() - 1)%2 == 0) 01072 { 01073 int n = (l.size()-1)/2; 01074 pixels.resize(n); 01075 for(int i=0; i < n; i++) 01076 { 01077 pixels[i].x = atox<int>(l[i*2+1+0], "pixels"); 01078 pixels[i].y = atox<int>(l[i*2+1+1], "pixels"); 01079 } 01080 } 01081 else 01082 throw LogFileParseError("Bad PIXELS line"); 01083 } 01084 } 01085 01086 if(!state_ok) 01087 throw LogFileParseError("No state found"); 01088 01089 if(pixels.size() == 0) 01090 throw LogFileParseError("No pixels, or pixels is empty"); 01091 01092 //Now parse the lines 01093 StateParameters p; 01094 vector<string> l; 01095 01096 //Parse the iterations 01097 l = split(iterationline); 01098 p.iteration = atox<int>(l[1], "iteration"); 01099 01100 //Parse the random number generator 01101 p.rng =shared_ptr<MT19937>(new MT19937); 01102 { 01103 istringstream rng_s(rngline); 01104 try{ 01105 p.rng->read(rng_s); 01106 } 01107 catch(MT19937::ParseError p) 01108 { 01109 throw LogFileParseError("Error parsing MT19937"); 01110 } 01111 } 01112 01113 //Parse PASS and the listing of spots 01114 l = split(passline); 01115 if( (l.size() - 1 ) % 4 == 0) 01116 { 01117 p.pass = atox<int>(l[0].substr(4), "pass"); 01118 01119 for(unsigned int i=0; i < (l.size()-1)/4; i++) 01120 { 01121 cout << l[i*4+1+0] << endl; 01122 cout << l[i*4+1+1] << endl; 01123 cout << l[i*4+1+2] << endl; 01124 cout << l[i*4+1+3] << endl; 01125 p.spots.push_back(makeVector( 01126 atox<double>(l[i*4+1+0], "spot"), 01127 atox<double>(l[i*4+1+1], "spot"), 01128 atox<double>(l[i*4+1+2], "spot"), 01129 atox<double>(l[i*4+1+3], "spot"))); 01130 } 01131 01132 } 01133 else 01134 throw LogFileParseError("Wrong number of elements in PASS line"); 01135 01136 //Set up the pixels (oh god the pixels) 01137 p.pixels = pixels; 01138 01139 return p; 01140 } 01141 01142 01143 01144 ///Setup the parameters for a run using the old and deeply peculiar method. 01145 ///This includes the unpleasant and diffucult so use de-checkpointing code. 01146 ///wtf. The use of this function is very strongly deprecated. 01147 ///@param log_ratios Image from which region is selected. 01148 ///@param ims Input data 01149 ///@param pixels Region for spot fitting to run in 01150 StateParameters generate_state_parameters_ye_olde(const BasicImage<double>& log_ratios, const vector<Image<float> >& ims, vector<ImageRef> pixels){ 01151 sort(pixels.begin(), pixels.end()); 01152 01153 const double variance = 1; // it should be 01154 01155 //To scale the X axis of a log-normal distribution, only 01156 //the mu parameter needs to be changed... 01157 const double intensity_mu = GV3::get<double>("intensity.rel_mu", 0., -1) + log(sqrt(variance)); 01158 const double intensity_sigma = GV3::get<double>("intensity.rel_sigma", 0., -1); 01159 const double blur_mu = GV3::get<double>("blur.mu", 0., -1); 01160 const double blur_sigma = GV3::get<double>("blur.sigma", 0., -1); 01161 01162 //The region was extracted at a certain threshold. 01163 //These regions may be too small, so some post-region finding dilation 01164 //may be performed. New spots are only placed at pixels which exceed the threshold. 01165 //post_dilate.threshold is (if set) used as the placing threshold so the placing threshold 01166 //can be different from the region-finding threshold. 01167 01168 //Note that as a result of dliation, regions of <pixels> may be below the threshold. 01169 //In the historic version, this could affect new spot placement. This feature is not supported 01170 //in this version. 01171 double threshold = GV3::get<double>("threshold", 0, -1); 01172 const double post_threshold = GV3::get<double>("post_dilate.threshold", -1, 1); 01173 if(post_threshold != -1) 01174 threshold = post_threshold; 01175 01176 01177 //If dilation after region finding is to be performed, then do it here. 01178 const double post_dilate_radius = GV3::get<double>("post_dilate.radius", 0, -1); 01179 if(post_dilate_radius != 0) 01180 { 01181 Image<byte> pix(ims[0].size()); 01182 pix.fill(0); 01183 01184 for(unsigned int i=0; i < pixels.size(); i++) 01185 pix[pixels[i]] = 255; 01186 01187 Image<byte> dilated = morphology(pix, getDisc(post_dilate_radius), Morphology::BinaryDilate<byte>()); 01188 01189 pixels.clear(); 01190 01191 ImageRef p(0,0); 01192 do 01193 if(dilated[p]) 01194 pixels.push_back(p); 01195 while(p.next(dilated.size())); 01196 } 01197 01198 01199 assert_same_size(ims); 01200 if(log_ratios.size() != ims[0].size()) 01201 { 01202 cerr << "Bad log ratios size\n"; 01203 exit(1); 01204 } 01205 01206 vector<Vector<4> > spots; 01207 //Spots can be either put down automatically, or specified 01208 //The auto-initialization is very strange. 01209 if(GV3::get<bool>("spots.auto_initialise", 1, 1)) 01210 { 01211 //You never get two spots in the same disc in the second stage of the algorithm 01212 vector<ImageRef> disc = getDisc(GV3::get<double>("spot_spread", 3.1, 1)); 01213 01214 //Record all the pixels 01215 map<ImageRef, double> valid_pixels; 01216 for(unsigned int i=0; i < pixels.size(); i++) 01217 if(log_ratios[pixels[i]] > threshold) 01218 valid_pixels.insert(make_pair(pixels[i], log_ratios[pixels[i]])); 01219 01220 01221 //Get some initial spots by finding the local maxima 01222 ImageRef neighbours[8] = { 01223 ImageRef(-1, -1), 01224 ImageRef( 0, -1), 01225 ImageRef( 1, -1), 01226 01227 ImageRef(-1, 0), 01228 ImageRef( 1, 0), 01229 01230 ImageRef(-1, 1), 01231 ImageRef( 0, 1), 01232 ImageRef( 1, 1), 01233 }; 01234 for(unsigned int i=0; i < pixels.size(); i++) 01235 { 01236 if(!(log_ratios[pixels[i]] > threshold)) 01237 goto not_a_maximum; 01238 01239 for(int j=0; j < 8; j++) 01240 if(!log_ratios.in_image(pixels[i] + neighbours[j]) || ! (log_ratios[pixels[i]] > log_ratios[pixels[i] + neighbours[j]])) 01241 goto not_a_maximum; 01242 01243 spots.push_back(makeVector(log_normal_mode(intensity_mu, intensity_sigma), log_normal_mode(blur_mu, blur_sigma), pixels[i].x, pixels[i].y)); 01244 01245 //Remove the pixels around the initial spots 01246 for(unsigned int j=0; j < disc.size(); j++) 01247 valid_pixels.erase(pixels[i] + disc[j]); 01248 01249 not_a_maximum:; 01250 } 01251 01252 for(unsigned int i=0; i < spots.size(); i++) 01253 cout << spots[i] << endl; 01254 01255 //Now place down extra spots in the remaining space. 01256 while(!valid_pixels.empty()) 01257 { 01258 ImageRef p = max_element(valid_pixels.begin(), valid_pixels.end(), LessSecond())->first; 01259 spots.push_back(makeVector(log_normal_mode(intensity_mu, intensity_sigma), log_normal_mode(blur_mu, blur_sigma), p.x, p.y)); 01260 01261 for(unsigned int j=0; j < disc.size(); j++) 01262 valid_pixels.erase(p + disc[j]); 01263 } 01264 01265 //This line allows extra spots to be placed down around each spot already put down. 01266 //This is a shocking hack and jenerally very unpleasant. 01267 double extra_r = GV3::get<double>("extra_spots", 0, 1); 01268 vector<ImageRef> extra = getDisc(extra_r); 01269 vector<Vector<4> > more_spots; 01270 for(unsigned int i=0; i < extra.size(); i++) 01271 if(extra[i] != ImageRef_zero) 01272 for(unsigned int j=0; j < spots.size(); j++) 01273 more_spots.push_back(spots[j] + makeVector(0, 0, extra[i].x, extra[i].y) / (2*extra_r+1)); 01274 01275 copy(more_spots.begin(), more_spots.end(), back_inserter(spots)); 01276 } 01277 else 01278 { 01279 Vector<> loaded_spots = GV3::get<Vector<> >("spots.manual_spots", "", -1); 01280 01281 if(loaded_spots.size()%4 != 0) 01282 { 01283 cerr << "Loaded spot size is not a multiple of 4\n"; 01284 exit(1); 01285 } 01286 01287 else 01288 spots = spots_to_vector(loaded_spots); 01289 } 01290 01291 //Initialize the MT19937 RNG from a seed. 01292 shared_ptr<MT19937> rng(new MT19937); 01293 rng->simple_seed(GV3::get<int>("seed", 0, 1)); 01294 01295 //Load in a checkpoint (precise RNG state, iteration and pass). 01296 int start_iteration=0; 01297 int start_pass=0; 01298 if(GV3::get<bool>("checkpoint", 0, 1)) 01299 { 01300 string rng_state = GV3::get<string>("checkpoint.rng.state", "", -1); 01301 istringstream rs(rng_state); 01302 rng->read(rs); 01303 start_iteration=GV3::get<int>("checkpoint.iteration", 0, -1); 01304 start_pass=GV3::get<int>("checkpoint.pass", 0, -1); 01305 } 01306 01307 StateParameters p; 01308 p.spots = spots; 01309 p.rng = rng; 01310 p.pass = start_pass; 01311 p.iteration = start_iteration; 01312 p.pixels = pixels; 01313 01314 return p; 01315 } 01316 01317 ///Very simple and inefficient dilation function. 01318 ///@ingroup gUtility 01319 set<ImageRef> dilate_mask(const vector<ImageRef>& v, double r) 01320 { 01321 vector<ImageRef> m = getDisc(r); 01322 01323 set<ImageRef> ret; 01324 01325 for(unsigned int i=0; i < v.size(); i++) 01326 for(unsigned int j=0; j < m.size(); j++) 01327 ret.insert(v[i] + m[j]); 01328 01329 return ret; 01330 } 01331 01332 ///How far should steps in brightness be limited to? 01333 ///@ingroup gStorm 01334 double brightness_motion_limit(double mu, double sigma, bool not_one) 01335 { 01336 if(not_one) 01337 return log_normal_std(mu, sigma); 01338 else 01339 return 1; 01340 } 01341 01342 01343 01344 01345 ///Mega class which actually does the meat of the spot fitting. 01346 ///probably could be refactored a bit. 01347 ///@ingroup gStorm 01348 class FitSpots 01349 { 01350 const vector<Image<float> >& ims; ///< Input data 01351 FitSpotsGraphics& graphics; ///< Graphics class. 01352 UserInterfaceCallback& ui; ///< Callbacks to provide user interface 01353 const vector<ImageRef> pixels; ///< Area in which to perform model fitting 01354 01355 //Spot positions 01356 vector<Vector<4> > spots; ///< State in terms of current spot positions 01357 01358 //Starting point 01359 const int start_iteration; ///< Starting iteration number (for restarting from checkpoint) 01360 int start_pass; ///< Starting pass (for restarting from checkpoint) 01361 01362 MT19937& rng; ///< Random numbewr generator 01363 01364 const double variance; ///< Variance of noise in data. Must be 1. 01365 const double intensity_mu; ///< Prior for spot intensity 01366 const double intensity_sigma; ///< Prior for spot intensity 01367 const double blur_mu; ///< Prior for spot shape 01368 const double blur_sigma; ///< Prior for spt shape 01369 01370 //pixels is dilated slightly, by a disk of size area_extra_radius. 01371 //The result is stored in allowed_area. This is used to implement a uniform 01372 //prior over position, which is uniform within allowed_area, and zero 01373 //everywhere else. 01374 // 01375 //This is implemented as a set, because the mask may extend beyond the borders of the 01376 //image slightly 01377 const double area_extra_radius; ///< Extra size beyone marked region in which spots are allowed to exist 01378 set<ImageRef> allowed_area; ///< Total allowed region, pixels dilated by area_extra_radius 01379 const int use_position_prior; ///< Should a proper prior over position be uesd? A clue: yes. 01380 const double position_prior; ///< Value for the posision prior, i.e. reciprocal of area 01381 01382 //General optimizing and sampling parameters 01383 const double max_motion; ///< Maximum motion on any axes for optimization. See ConjugateGradientOnly. 01384 const int sample_iterations; ///< Number of mixing samples to use in Gibbs sampling 01385 01386 //Task specific optimizing and sampling parameters: 01387 01388 //Main optimization loop 01389 const int main_cg_max_iterations; ///< Maximum iterations allowed for ConjugateGradientOnly in main optimization loop 01390 const int main_samples; ///< Number of samples to use in main loop 01391 const int main_passes; ///< Number of passes to perform per iteration in main loop 01392 const int outer_loop_iterations; ///< Total number of iterations to perform 01393 01394 //Spot selection loop 01395 const int add_remove_tries; ///< Number of attemts to add/remove a spot 01396 const int add_remove_opt_samples; ///< Number of samples to use in model modification phase 01397 const int add_remove_opt_retries; ///< Number of attempts restarting the optimization to escape saddle points 01398 const int add_remove_opt_hess_inner_samples; ///< Number of extra FFBS samples to use for computing Hessian when testing for convergence to non-saddle point 01399 const int h_outer_samples; ///< Number of samples used for computing Hessian as part of Laplace's approximation 01400 const int h_inner_samples; ///< Number of additional FFBS samples to use for computing Hessian as part of Laplace's approximation 01401 const int tsamples; ///< Number of samples to use in thermodynamic integration 01402 01403 // Average of all inputs (used for debugging) 01404 const Image<float> ave; ///< Average of input data: used for 01405 01406 01407 //File to save output to 01408 ofstream& save_spots; ///< Output stream for log file 01409 01410 //Time accumulators for benchmarking 01411 double time_gibbs; ///< Benchmarking data 01412 double time_cg; ///< Benchmarking data 01413 01414 ///Motion limit for ConjugateGradientOnly 01415 ///The x distance, y distance and spot size are all approximately the same scale 01416 ///which is of order 1. The brigntness is not. By default, the brightness limit is also 1. 01417 ///This flag controls whether is should be set to the standard deviation of the brightness prior 01418 ///distribution. This setting will put the motion limit on the same scale as the other three 01419 ///parameters. 01420 const bool scale_brightness_limit; 01421 const Vector<4> limit; ///< Limit vector for ConjugateGradientOnly 01422 01423 const Matrix<3> A; ///< Transition matrix 01424 const Vector<3> pi; ///< Initial probabilities 01425 01426 01427 vector<vector<double> > pixel_intensities; ///<Pixel intensities for all images [frame][pixel] 01428 01429 DataForMCMC data_for_t_mcmc; ///<Aggergated data for thermodynamic integration 01430 DataForMCMC data_for_h_mcmc; ///<Aggergated data for finding hessian 01431 01432 int iteration; ///< Iteration number 01433 01434 01435 TIME(cvd_timer timer;) 01436 public: 01437 01438 FitSpots(const vector<Image<float> >& ims_, FitSpotsGraphics& graphics_, UserInterfaceCallback& ui_, StateParameters& params, ofstream& save_spots_) 01439 :ims(ims_), graphics(graphics_),ui(ui_), 01440 01441 //Set up the main parameters 01442 pixels(params.pixels), 01443 spots(params.spots), 01444 start_iteration(params.iteration), 01445 start_pass(params.pass), 01446 rng(*params.rng), 01447 01448 01449 01450 //Set up all the system parameters 01451 variance(1), // it should be 01452 01453 //To scale the X axis of a log-normal distribution, only 01454 //the mu parameter needs to be changed... 01455 intensity_mu(GV3::get<double>("intensity.rel_mu", 0., -1) + log(sqrt(variance))), 01456 intensity_sigma(GV3::get<double>("intensity.rel_sigma", 0., -1)), 01457 blur_mu(GV3::get<double>("blur.mu", 0., -1)), 01458 blur_sigma(GV3::get<double>("blur.sigma", 0., -1)), 01459 01460 //Spot position prior 01461 area_extra_radius(GV3::get<double>("position.extra_radius", 0., -1)), 01462 allowed_area(dilate_mask(pixels, area_extra_radius)), 01463 use_position_prior(GV3::get<bool>("position.use_prior", true, -1)), 01464 position_prior(1.0 / allowed_area.size()), 01465 01466 //General optimizing and sampling parameters 01467 max_motion(GV3::get<double>("cg.max_motion", 0., -1)), 01468 sample_iterations(GV3::get<int>("gibbs.mixing_iterations", 0, -1)), 01469 01470 //Task specific optimizing and sampling parameters: 01471 01472 //Main optimization loop 01473 main_cg_max_iterations(GV3::get<double>("main.cg.max_iterations", 0., -1)), 01474 main_samples(GV3::get<int>("main.gibbs.samples", 0, -1)), 01475 main_passes(GV3::get<int>("main.passes", 0, -1)), 01476 outer_loop_iterations(GV3::get<int>("main.total_iterations", 100000000, 1)), 01477 01478 //Spot selection loop 01479 add_remove_tries(GV3::get<int>("add_remove.tries", 0, -1)), 01480 add_remove_opt_samples(GV3::get<int>("add_remove.optimizer.samples", 0, -1)), 01481 add_remove_opt_retries(GV3::get<int>("add_remove.optimizer.attempts", 0, -1)), 01482 add_remove_opt_hess_inner_samples(GV3::get<int>("add_remove.optimizer.hessian_inner_samples", 0, -1)), 01483 h_outer_samples(GV3::get<int>("add_remove.hessian.outer_samples", 0, -1)), 01484 h_inner_samples(GV3::get<int>("add_remove.hessian.inner_samples", 0, -1)), 01485 tsamples(GV3::get<int>("add_remove.thermo.samples", 0, -1)), 01486 01487 ave(average_image(ims_)), 01488 01489 save_spots(save_spots_), 01490 01491 time_gibbs(0), 01492 time_cg(0), 01493 01494 scale_brightness_limit(GV3::get<bool>("max_motion.use_brightness_std", 0, -1)), 01495 limit(makeVector(brightness_motion_limit(intensity_mu, intensity_sigma, scale_brightness_limit), 1, 1, 1)*max_motion), 01496 01497 A(GV3::get<Matrix<3> >("A", Zeros, 1)), 01498 pi(GV3::get<Vector<3> >("pi", Zeros, 1)), 01499 01500 01501 data_for_t_mcmc(pixels, pixel_intensities, intensity_mu, intensity_sigma, blur_mu, blur_sigma, variance, tsamples, sample_iterations, A, pi, rng), 01502 data_for_h_mcmc(pixels, pixel_intensities, intensity_mu, intensity_sigma, blur_mu, blur_sigma, variance, h_outer_samples, sample_iterations, A, pi, rng) 01503 01504 { 01505 assert_same_size(ims); 01506 01507 //Pixel intensities for all images [frame][pixel] 01508 pixel_intensities.resize(ims.size(), vector<double>(pixels.size())); 01509 for(unsigned int frame=0; frame < ims.size(); frame++) 01510 for(unsigned int p=0; p < pixels.size(); p++) 01511 pixel_intensities[frame][p] = ims[frame][pixels[p]]; 01512 01513 } 01514 01515 ///Perform a complete iteration of the optimzation stage of the spot firrint algorithm 01516 void optimize_each_spot_in_turn_for_several_passes() 01517 { 01518 //Precompute the intensities for all spot pixels 01519 vector<vector<double> > spot_intensities; //[spot][pixel] 01520 for(unsigned int i=0; i < spots.size(); i++) 01521 spot_intensities.push_back(compute_spot_intensity(pixels, spots[i])); 01522 01523 //Which pixels does each spot have? 01524 vector<vector<int> > spot_pixels; //[spot][pixel] 01525 spot_pixels.resize(spots.size()); 01526 for(unsigned int s=0; s < spots.size(); s++) 01527 get_spot_pixels(pixels, spots[s], spot_pixels[s]); 01528 01529 01530 //Optimize the model, N spots at a time. 01531 // 01532 for(int pass=start_pass; pass < main_passes; pass++) 01533 { 01534 save_spots << "Pass: " << pass << endl; 01535 rng.write(save_spots); 01536 save_spots << endl; 01537 01538 start_pass=0; // This is only nonzero first time, since we might chekpoint midway through an iteration 01539 save_spots << "PASS" << pass << ": " << setprecision(20) << scientific << spots_to_Vector(spots) << endl; 01540 save_spots << "ENDCHECKPOINT" << endl << flush; 01541 01542 ui.per_pass(iteration, pass, spots); 01543 //Sort spots according to pass%4 01544 01545 //Sort the spots so that the optimization runs in sweeps 01546 //This heiristic seems to increase the rate of propagation of information 01547 //about spot positions. 01548 01549 //Create a list of indices 01550 vector<int> index = sequence(spots.size()); 01551 01552 int passs = pass + iteration; 01553 //Sort the indices according to the position of the spot that they index 01554 if(passs%4 == 0) 01555 sort(index.begin(), index.end(), IndexLexicographicPosition<less<double>, 2>(spots)); 01556 else if(passs%4==1) 01557 sort(index.begin(), index.end(), IndexLexicographicPosition<greater<double>, 2>(spots)); 01558 else if(passs%4==1) 01559 sort(index.begin(), index.end(), IndexLexicographicPosition<less<double>, 3>(spots)); 01560 else 01561 sort(index.begin(), index.end(), IndexLexicographicPosition<greater<double>, 3>(spots)); 01562 01563 //Reorder the spots and their intensities and their pixel lists 01564 { 01565 vector<Vector<4> > tmp_spot(index.size()); 01566 vector<vector<double> > tmp_spot_intensities(index.size()); 01567 vector<vector<int> > tmp_spot_pixels(index.size()); 01568 for(unsigned int i=0; i < index.size(); i++) 01569 { 01570 tmp_spot[i] = spots[index[i]]; 01571 swap(tmp_spot_intensities[i], spot_intensities[index[i]]); 01572 swap(tmp_spot_pixels[i], spot_pixels[i]); 01573 } 01574 01575 swap(tmp_spot, spots); 01576 swap(tmp_spot_intensities, spot_intensities); 01577 swap(tmp_spot_pixels, spot_pixels); 01578 } 01579 01580 //Sweep through and optimize each spot in turn 01581 for(int s=0; s < (int)spots.size(); s++) 01582 { 01583 ui.per_spot(iteration, pass, s, spots.size()); 01584 ui.perhaps_stop(); 01585 01586 TIME(timer.reset();) 01587 //Get some samples with Gibbs sampling 01588 vector<vector<vector<State> > > sample_list; //[N][spot][frame]: list of samples drawn using Gibbs sampling 01589 vector<vector<vector<double> > > sample_intensities; //[sample][frame][pixel] 01590 01591 GibbsSampler2 sampler(pixel_intensities, spot_intensities, spots, spot_pixels, A, pi, variance, sample_iterations); 01592 for(int i=0; i < main_samples; i++) 01593 { 01594 sampler.next(rng); 01595 sample_list.push_back(sampler.sample()); 01596 sample_intensities.push_back(sampler.sample_intensities()); 01597 01598 ui.perhaps_stop(); 01599 } 01600 01601 //First, remove the spot from all the samples. 01602 for(unsigned int i=0; i < sample_list.size(); i++) 01603 remove_spot(sample_intensities[i], spot_intensities[s], sample_list[i][s]); 01604 01605 //cout << timer.get_time() << endl; 01606 TIME(time_gibbs += timer.reset();) 01607 01608 //Package up all the data 01609 SampledBackgroundData data(sample_intensities, pixel_intensities, pixels, 01610 intensity_mu, intensity_sigma, blur_mu, blur_sigma, 01611 A, pi, variance); 01612 01613 //Derivative computer: 01614 SpotNegProbabilityDiffWithSampledBackground compute_deriv(data); 01615 01616 01617 graphics.draw_pixels(pixels, 0, 0, 1, 1); 01618 graphics.draw_krap(spots, scale_to_bytes(ave), boundingbox(pixels), s); 01619 graphics.swap(); 01620 01621 //Optimize spot "s" 01622 //Optimize with the derivatives only since the actual probability 01623 //is much harder to compute 01624 ConjugateGradientOnly<4> cg(spots[s], compute_deriv, limit); 01625 01626 01627 cg.max_iterations = main_cg_max_iterations; 01628 01629 01630 #if 0 01631 cout << setprecision(10); 01632 cout << spots_to_Vector(spots) << endl; 01633 Matrix<4> hess, hess_errors; 01634 cout << "Hello, my name is Inigo Montoya\n"; 01635 /*for(int i=0; i < 4; i++) 01636 { 01637 Matrix<4, 2> d = numerical_gradient_with_errors(NthDeriv(compute_deriv, i), cg.x); 01638 hess[i] = d.T()[0]; 01639 hess_errors[i] = d.T()[1]; 01640 } 01641 */ 01642 //cout << "Errors:\n" << hess_errors << endl; 01643 //cout << "NHess:\n" << hess<< endl; 01644 Matrix<4> rhess = -sampled_background_spot_hessian(cg.x, data); 01645 cout << "Hess:\n" << rhess << endl; 01646 //cout << "Err:\n" << hess - rhess << endl; 01647 01648 //Vector<4> grad = compute_deriv(cg.x); 01649 01650 //Matrix<4> e = hess - rhess; 01651 01652 //for(int i=0; i < 4; i++) 01653 // for(int j=0; j < 4; j++) 01654 // e[i][j] /= hess_errors[i][j]; 01655 01656 //cout << "Err:\n" << e << endl; 01657 cout << "Deriv:" << compute_deriv(cg.x) << endl; 01658 //cout << "Full:\n" << sampled_background_spot_hessian2(cg.x, data) - grad.as_col()*grad.as_row() << endl; 01659 01660 FreeEnergyHessian hesscomputer(data_for_h_mcmc); 01661 01662 Matrix<4> nhess = hesscomputer.hessian(spots, 0); 01663 cout << "NHess:\n" << nhess << endl; 01664 01665 cout << "Turbo-N Hess:\n" << sampled_background_spot_hessian_ffbs(cg.x, data, 10000) << endl; 01666 01667 cout << "TI energy: " << NegativeFreeEnergy(data_for_t_mcmc)(spots_to_Vector(spots)) << endl; 01668 cout << "FA energy: " << SpotProbabilityWithSampledBackgroundFAKE(data)(cg.x) << endl; 01669 01670 01671 01672 //cout << "Numerical hessian from FD:\n" << numerical_hessian(SpotProbabilityWithSampledBackgroundFAKE(data), cg.x) << endl; 01673 exit(0); 01674 #endif 01675 //cout << "Starting opt... " << cg.x << endl; 01676 while(cg.iterate(compute_deriv)) 01677 { 01678 graphics.draw_krap(spots, scale_to_bytes(ave), boundingbox(pixels), s, cg.x); 01679 graphics.draw_pixels(pixels, 0, 0, 1, .2); 01680 graphics.swap(); 01681 ui.perhaps_stop(); 01682 //cout << cg.x << endl; 01683 } 01684 01685 //Update to use the result of the optimization 01686 spots[s] = cg.x; 01687 //cout << "End: " << cg.x << endl; 01688 01689 graphics.draw_krap(spots, scale_to_bytes(ave), boundingbox(pixels), -1); 01690 graphics.swap(); 01691 01692 //Recompute the new spot intensity, since the spot has changed 01693 spot_intensities[s] = compute_spot_intensity(pixels, spots[s]); 01694 01695 //Recompute which are the useful pixels 01696 get_spot_pixels(pixels, spots[s], spot_pixels[s]); 01697 01698 //Is the spot within the allowed area, i.e. is it's prior 0? 01699 //The prior is sero only if it we are using it and we're in an invalid area 01700 01701 ImageRef quantized_spot_position = ir_rounded(spots[s].slice<2,2>()); 01702 bool zero_prior = use_position_prior && (allowed_area.count(quantized_spot_position)==0); 01703 01704 //Check to see if spot has been ejected. If spot_pixels is empty, then it has certainly been ejected. 01705 if(spot_pixels[s].empty() || zero_prior) 01706 { 01707 //Spot has been ejected. Erase it. 01708 cout << " Erasing ejected spot: " << spot_pixels[s].empty() << " " << zero_prior << endl; 01709 cout << spots[s] << endl; 01710 //GUI_Pause(1); 01711 01712 spot_intensities.erase(spot_intensities.begin() + s); 01713 spot_pixels.erase(spot_pixels.begin() + s); 01714 spots.erase(spots.begin() + s); 01715 s--; 01716 //exit(0); 01717 } 01718 01719 //cout << timer.get_time() << endl; 01720 TIME(time_cg += timer.reset();) 01721 01722 //cout << "Times: " << time_gibbs << " " << time_cg << endl; 01723 //save_spots << "INTERMEDIATE: " << setprecision(15) << scientific << spots_to_Vector(spots) << endl; 01724 } 01725 } 01726 } 01727 01728 ///Perform a complete iteration of the model size modification stage of the spot fitting algorithm 01729 void try_modifying_model() 01730 { 01731 01732 for(int i=0; i < add_remove_tries; i++) 01733 { 01734 ui.per_modification(iteration, i, add_remove_tries); 01735 ui.perhaps_stop(); 01736 01737 cout << endl << endl << "Modifying the model" << endl << "======================\n"; 01738 cout << "Hello\n"; 01739 bool add_spot = (rng() > 0.5) || (spots.size() == 1); 01740 cout << "World\n"; 01741 01742 vector<Vector<4> > model_1, model_2; 01743 01744 01745 int original; //What is the original model? Model 1 or Model 2? 01746 01747 if(add_spot) 01748 { 01749 model_1 = spots; 01750 model_2 = model_1; 01751 01752 //Pick a pixel within the thresholded ones as a starting point 01753 int r; 01754 do 01755 { 01756 r = (int)(rng() * pixels.size()); 01757 //cout << r << " " << log_ratios[pixels[r]] << " " << pixels[r] << " " << threshold << endl; 01758 } 01759 while(0); 01760 01761 //This version does not (yet?) suppotrt thresholding on log_ratios 01762 //for placing spots, since the purpose of log_ratios has diminished. 01763 //while(log_ratios[pixels[r]] < threshold); 01764 01765 01766 model_2.push_back(makeVector(log_normal_mode(intensity_mu, intensity_sigma), 01767 log_normal_mode(blur_mu, blur_sigma), 01768 pixels[r].x + rng()-.5, pixels[r].y + rng() - .5)); 01769 cout << "Adding a spot\n"; 01770 01771 original = 1; 01772 } 01773 else 01774 { 01775 //Pick a random point to optimize/remove 01776 int a_random_spot = static_cast<int>(rng() * spots.size()); 01777 model_1 = spots; 01778 swap(model_1[model_1.size()-1], model_1[a_random_spot]); 01779 01780 model_2 = model_1; 01781 01782 model_1.pop_back(); 01783 cout << "Removing a spot\n"; 01784 original = 2; 01785 } 01786 01787 //The mobile spot is always the last spot of model_2 01788 const int spot = model_2.size() - 1; 01789 01790 cout << "Original model: " << original << endl; 01791 01792 //Precompute the intensities for all spot pixels 01793 //Model 2 is always one longer than model 1 and 01794 //differs only on the extra element 01795 vector<vector<double> > model2_spot_intensities; //[spot][pixel] 01796 for(unsigned int i=0; i < model_2.size(); i++) 01797 model2_spot_intensities.push_back(compute_spot_intensity(pixels, model_2[i])); 01798 01799 //Which pixels does each spot have? 01800 vector<vector<int> > model2_spot_pixels(model_2.size()); //[spot][pixel] 01801 for(unsigned int s=0; s < model_2.size(); s++) 01802 get_spot_pixels(pixels, model_2[s], model2_spot_pixels[s]); 01803 01804 //Optimize spot: 01805 { 01806 cout << "Optimizing spot for model selection\n"; 01807 01808 01809 //Get some samples with Gibbs sampling 01810 vector<vector<vector<State> > > sample_list; //[N][spot][frame]: list of samples drawn using Gibbs sampling 01811 vector<vector<vector<double> > > sample_intensities; //[sample][frame][pixel] 01812 01813 GibbsSampler2 sampler(pixel_intensities, model2_spot_intensities, model_2, model2_spot_pixels, A, pi, variance, sample_iterations); 01814 for(int i=0; i < add_remove_opt_samples; i++) 01815 { 01816 sampler.next(rng); 01817 sample_list.push_back(sampler.sample()); 01818 sample_intensities.push_back(sampler.sample_intensities()); 01819 ui.perhaps_stop(); 01820 } 01821 01822 //First, remove the spot from all the samples. 01823 for(unsigned int i=0; i < sample_list.size(); i++) 01824 remove_spot(sample_intensities[i], model2_spot_intensities[spot], sample_list[i][spot]); 01825 01826 //Package up all the data 01827 SampledBackgroundData data(sample_intensities, pixel_intensities, pixels, 01828 intensity_mu, intensity_sigma, blur_mu, blur_sigma, 01829 A, pi, variance); 01830 01831 //Derivative computer: 01832 SpotNegProbabilityDiffWithSampledBackground compute_deriv(data); 01833 01834 graphics.draw_krap(model_2, scale_to_bytes(ave), boundingbox(pixels), spot); 01835 graphics.swap(); 01836 01837 //Optimize spot "s" 01838 //Optimize with the derivatives only since the actual probability 01839 //is much harder to compute 01840 ConjugateGradientOnly<4> cg(model_2[spot], compute_deriv, limit); 01841 01842 01843 for(int attempt=0; attempt < add_remove_opt_retries; attempt++) 01844 { 01845 cout << "Attempt " << attempt << " of " << add_remove_opt_retries << endl; 01846 ui.perhaps_stop(); 01847 01848 //Optimize with conjugate gradient 01849 while(cg.iterate(compute_deriv)) 01850 { 01851 ui.perhaps_stop(); 01852 graphics.draw_krap(model_2, scale_to_bytes(ave), boundingbox(pixels), spot, cg.x); 01853 graphics.swap(); 01854 } 01855 01856 //Check for being at a saddle point (no point checking on the last try) 01857 //All eigenvectors should be negative at a maximum. 01858 //WTF: is this a bug? WTF? 01859 //It was this: 01860 //if(attempt < add_remove_tries - 1) 01861 if(attempt < add_remove_opt_retries - 1) 01862 { 01863 Matrix<4> hessian = sampled_background_spot_hessian_ffbs(cg.x, data, add_remove_opt_hess_inner_samples, rng); 01864 SymEigen<4> hess_decomp(hessian); 01865 01866 //cout << "What the fuck:" << endl << hessian << endl << hessian3<< endl << hessian2 << endl; 01867 01868 cout << "Eigenvalues are: " << hess_decomp.get_evalues() << endl; 01869 01870 if(hess_decomp.is_negdef()) 01871 break; 01872 else 01873 { 01874 //Restart in the direction of the best uphill part 01875 cg.init(cg.x + 0.1 * hess_decomp.get_evectors()[3], (hess_decomp.get_evectors()[3])); 01876 01877 01878 cout << "Grad = " << compute_deriv(cg.x) << endl; 01879 for(int i=0; i < 4; i++) 01880 { 01881 cout << "Direction: " << i << endl; 01882 cout << unit(compute_deriv(cg.x + 0.1*hess_decomp.get_evectors()[i])) * hess_decomp.get_evectors()[i] << endl; 01883 } 01884 01885 for(int i=0; i < 4; i++) 01886 { 01887 cout << "Direction: " << i << endl; 01888 Vector<4> d = Zeros; 01889 d[i] = 1; 01890 cout << unit(compute_deriv(cg.x + d)) * hess_decomp.get_evectors()[i] << endl; 01891 } 01892 } 01893 } 01894 } 01895 01896 01897 //Update to use the result of the optimization 01898 model_2[spot] = cg.x; 01899 01900 graphics.draw_krap(model_2, scale_to_bytes(ave), boundingbox(pixels), -1); 01901 graphics.swap(); 01902 01903 01904 //Update cached data based on the new spot position 01905 model2_spot_intensities[spot] = compute_spot_intensity(pixels, model_2[spot]); 01906 get_spot_pixels(pixels, model_2[spot], model2_spot_pixels[spot]); 01907 01908 cout << "Done optimizing for model selection\n"; 01909 } 01910 01911 01912 //Which model to keep? 01913 int keep=original; 01914 01915 //Compute position prior (and we might be able to reject it really quickly here) 01916 bool zero_prior = use_position_prior && (allowed_area.count(ir_rounded(model_2[spot].slice<2,2>()))==0); 01917 01918 if(zero_prior) 01919 { 01920 //Model 2 went bad, so we clearly keep model 1 01921 keep = 1; 01922 } 01923 else 01924 { 01925 01926 //The position prior is independent 01927 //Compute the difference model2 - model1 01928 //This is only valid if model2 is in the valid region 01929 double position_log_prior_model2_minus_model1; 01930 if(use_position_prior) 01931 position_log_prior_model2_minus_model1 = (model_2.size() - model_1.size()) * ln(position_prior); 01932 else 01933 position_log_prior_model2_minus_model1 = 0; 01934 01935 01936 //Integrate model_2 01937 //First compute the Hessian since this might go wrong. 01938 01939 //FreeEnergyHessian hesscomputer(data_for_h_mcmc); 01940 Matrix<4> hess;// = hesscomputer.hessian(model_2, spot); 01941 01942 //Use turbohess here since it is much faster, as the backwards sampling step is fast 01943 //We expect this hessian to be really quite different, if the spot has moved from 01944 //a long way away, since the sampling will have changed dramatically 01945 { 01946 //Get some samples with Gibbs sampling 01947 vector<vector<vector<State> > > sample_list; //[N][spot][frame]: list of samples drawn using Gibbs sampling 01948 vector<vector<vector<double> > > sample_intensities; //[sample][frame][pixel] 01949 01950 GibbsSampler sampler(pixel_intensities, model2_spot_intensities, model_2, A, pi, variance, sample_iterations); 01951 for(int i=0; i < h_outer_samples; i++) 01952 { 01953 ui.perhaps_stop(); 01954 sampler.next(rng); 01955 sample_list.push_back(sampler.sample()); 01956 sample_intensities.push_back(sampler.sample_intensities()); 01957 } 01958 01959 //First, remove the spot from all the samples. 01960 for(unsigned int i=0; i < sample_list.size(); i++) 01961 remove_spot(sample_intensities[i], model2_spot_intensities[spot], sample_list[i][spot]); 01962 01963 //Package up all the data 01964 SampledBackgroundData data(sample_intensities, pixel_intensities, pixels, 01965 intensity_mu, intensity_sigma, blur_mu, blur_sigma, 01966 A, pi, variance); 01967 01968 hess = sampled_background_spot_hessian_ffbs(model_2[spot], data, h_inner_samples, rng); 01969 } 01970 01971 01972 double det = determinant(-hess / (M_PI*2)); 01973 SymEigen<4> hess_decomp(-hess); 01974 cout << "Hessien Eigenvalues are: " << hess_decomp.get_evalues() << endl; 01975 const double smallest_evalue = 1e-6; 01976 01977 //If the determinant is negative, then we are still at a saddle point 01978 //despite the attempts above, so abandon the attempt. 01979 if(hess_decomp.get_evalues()[0] > smallest_evalue) 01980 { 01981 01982 //Compute the free energy of model 2 at the MLE estimate 01983 cout << "Model 2:\n"; 01984 // double model_2_energy = -NegativeFreeEnergy(data_for_t_mcmc)(spots_to_Vector(model_2)); 01985 double model_2_energy = -NegativeFreeEnergy(data_for_t_mcmc).compute_with_mask(spots_to_Vector(model_2), model2_spot_pixels); 01986 cout << "Energy: " << model_2_energy << endl; 01987 01988 //Combine the MLE energy and Hessian using Laplace's approximation 01989 double model_2_occam = -0.5 * log(det); 01990 double model_2_prob = model_2_energy + model_2_occam + position_log_prior_model2_minus_model1; 01991 01992 cout << "Occam: " << model_2_occam << endl; 01993 cout << "Position: " << position_log_prior_model2_minus_model1 << endl; 01994 cout << "Prob: " << model_2_prob << endl; 01995 01996 //Integrate model_1 01997 //It has no parameters, in this formulation. 01998 //double model_1_prob = -NegativeFreeEnergy(data_for_t_mcmc)(spots_to_Vector(model_1)); 01999 02000 //Note that model_1 always has one fewer spots, and the last spot is always the one 02001 //missing, so we can make the correct mask very easily: 02002 model2_spot_pixels.pop_back(); 02003 double model_1_prob = -NegativeFreeEnergy(data_for_t_mcmc).compute_with_mask(spots_to_Vector(model_1), model2_spot_pixels); 02004 cout << "Prob: " << model_1_prob << endl; 02005 //model_1_prob = -NegativeFreeEnergy(data_for_t_mcmc)(spots_to_Vector(model_1)); 02006 02007 if(model_2_prob > model_1_prob) 02008 keep=2; 02009 else 02010 keep=1; 02011 02012 cout << "Models evaluated\n"; 02013 } 02014 else 02015 { 02016 cout << "Determinant has bad eigenvalues!\n"; 02017 keep = original; 02018 cout << hess_decomp.get_evalues() << endl; 02019 } 02020 } 02021 02022 if(keep == 2) 02023 { 02024 spots = model_2; 02025 cout << "Keeping model 2\n"; 02026 02027 } 02028 else 02029 { 02030 spots = model_1; 02031 cout << "Keeping model 1\n"; 02032 } 02033 02034 if(original != keep) 02035 { 02036 cout << "Model changed!\n"; 02037 //break; 02038 } 02039 } 02040 } 02041 02042 ///Run the complete optimization algorithm. 02043 void run() 02044 { 02045 graphics.init(ims[0].size()); 02046 save_spots << "LOGVERSION 2" << endl; 02047 save_spots << "PIXELS"; 02048 for(unsigned int i=0; i < pixels.size(); i++) 02049 save_spots << " " << pixels[i].x << " " << pixels[i].y; 02050 save_spots << endl; 02051 02052 save_spots << "BEGINGVARLIST" << endl; 02053 GV3::print_var_list(save_spots, "", 1); 02054 save_spots << "ENDGVARLIST" << endl; 02055 02056 //TODO all GVARS are set, so dump out gvars. 02057 02058 cout << "Limit vector: " << limit << endl; 02059 02060 for(iteration=start_iteration; iteration < outer_loop_iterations ;iteration++) 02061 { 02062 save_spots << "Iteration: " << iteration << " (" << iteration * main_passes << ")" << endl; 02063 save_spots << "MAIN: " << setprecision(20) << scientific << spots_to_Vector(spots) << endl; 02064 02065 cout << endl << endl << "----------------------" << endl << "Optimizing:\n"; 02066 cout << spots.size() << endl; 02067 02068 02069 optimize_each_spot_in_turn_for_several_passes(); 02070 02071 //spot_intensities is be correct here! 02072 try_modifying_model(); 02073 } 02074 save_spots << "FINAL: " << setprecision(15) << scientific << spots_to_Vector(spots) << endl; 02075 } 02076 02077 }; 02078 02079 ///Wrapper function for using FitSpots 02080 ///@ingroup gStorm 02081 void fit_spots_new(const vector<Image<float> >& ims, StateParameters& p, ofstream& save_spots, FitSpotsGraphics& gr) 02082 { 02083 auto_ptr<UserInterfaceCallback> ui = null_ui(); 02084 FitSpots fit(ims, gr, *ui, p, save_spots); 02085 fit.run(); 02086 } 02087 02088 ///Wrapper function for using FitSpots 02089 ///@ingroup gStorm 02090 void fit_spots_new(const vector<Image<float> >& ims, StateParameters& p, ofstream& save_spots, FitSpotsGraphics& gr, UserInterfaceCallback& ui) 02091 { 02092 try{ 02093 FitSpots fit(ims, gr, ui, p, save_spots); 02094 fit.run(); 02095 } 02096 catch(UserInterfaceCallback::UserIssuedStop) 02097 { 02098 } 02099 }