/home/oan/prosjekt/gotools/segmentation/gpl_distro/lsseg_1.0_gpl/src/ParzenDistributionForce.C

Go to the documentation of this file.
00001 //===========================================================================
00002 // The Level-Set Segmentation Library (LSSEG)
00003 //
00004 //
00005 // Copyright (C) 2000-2005 SINTEF ICT, Applied Mathematics, Norway.
00006 //
00007 // This program is free software; you can redistribute it and/or          
00008 // modify it under the terms of the GNU General Public License            
00009 // as published by the Free Software Foundation version 2 of the License. 
00010 //
00011 // This program 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          
00014 // GNU 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, write to the Free Software            
00018 // Foundation, Inc.,                                                      
00019 // 59 Temple Place - Suite 330,                                           
00020 // Boston, MA  02111-1307, USA.                                           
00021 //
00022 // Contact information: e-mail: tor.dokken@sintef.no                      
00023 // SINTEF ICT, Department of Applied Mathematics,                         
00024 // P.O. Box 124 Blindern,                                                 
00025 // 0314 Oslo, Norway.                                                     
00026 // 
00027 //
00028 // Other licenses are also available for this software, notably licenses
00029 // for:
00030 // - Building commercial software.                                        
00031 // - Building software whose source code you wish to keep private.        
00032 //
00033 //===========================================================================
00034 //===========================================================================
00035 //                                                                           
00036 // File: ParzenDistributionForce.C                                          
00037 //                                                                           
00038 // Created: Thu Mar  2 15:10:49 2006                                         
00039 //                                                                           
00040 // Author: Odd A. Andersen <Odd.Andersen@sintef.no>
00041 //                                                                           
00042 // Revision: $Id: ParzenDistributionForce.C,v 1.2 2006/11/13 02:29:28 oan Exp $
00043 //                                                                           
00044 // Description:
00047 //                                                                           
00048 //===========================================================================
00049 
00050 // recent changes:
00051 // 2006/03/30:  changed functions update(), fixChannelDistributionTo(), saveChannelDistribution(),
00052 //                              init() and get_histogram() so that they can handle histograms for inner and outer 
00053 //                              regions separately.
00054 //                              removed function dumpHistogram() -> functionality is now covert by saveChannelDistribution()
00055 
00056 #include "ParzenDistributionForce.h"
00057 #include "cimg_dependent.h" // for blurring function
00058 #include "errormacros.h"
00059 #include <assert.h>
00060 #include <vector>
00061 #include <fstream> //@@ debug
00062 
00063 using namespace std;
00064 
00065 namespace lsseg {
00066 
00067 //===========================================================================
00068 ParzenDistributionForce::ParzenDistributionForce(const Image<double>* img, 
00069                                                    Mask* m,
00070                                                    bool multireg_mode)
00071 //===========================================================================
00072     : multi_region_mode_(multireg_mode), num_force_bins_(256)
00073 {
00074     init(img, m);
00075 }
00076 
00077 //===========================================================================
00078 void ParzenDistributionForce::init(const Image<double>* img, const Mask* m)
00079 //===========================================================================
00080 {
00081     // verification of contract
00082     assert(img); // there should be an image to segment
00083     assert(!m || m->numChannels() == 1); // if mask is present, it shall have 1 channel
00084     assert(!m || img->spatial_compatible(*m)); // if mask is present, it shall have same shape
00085                                                // as the image to segment
00086 
00087     img_ = img;
00088     mask_ = m;
00089 
00090     const int nchan = img->numChannels();
00091     hist_.resize(nchan);
00092     is_fixed_.resize(nchan);
00093     precalc_force_.resize(nchan);
00094     force_bin_factor_.resize(nchan);
00095     channel_ranges_.resize(nchan);
00096 
00097     for (int c = 0; c != nchan; ++c) {
00098         double& rmin = channel_ranges_[c].first;
00099         double& rmax = channel_ranges_[c].second;
00100         rmin = *std::min_element(img_->channelBegin(c), img_->channelEnd(c));
00101         rmax = *std::max_element(img_->channelBegin(c), img_->channelEnd(c)); 
00102         
00103         force_bin_factor_[c] = num_force_bins_ / (rmax - rmin);
00104 
00105         hist_[c].first = hist_[c].second = makeDefaultHistogram(c);
00106         precompute_force(c, hist_[c].first, hist_[c].second, precalc_force_[c]);
00107         is_fixed_[c].first = is_fixed_[c].second = false;
00108     }
00109 }
00110 
00111 //===========================================================================
00112 void ParzenDistributionForce::saveChannelDistribution(int channel, 
00113                                                        std::ostream& os, 
00114                                                        bool inside) const
00115 //===========================================================================
00116 {
00117     assert(channel >= 0 && channel < img_->numChannels());
00118     if (inside) {
00119         hist_[channel].first.write(os);
00120     } else {
00121         hist_[channel].second.write(os);
00122     }
00123 }
00124 
00125 //===========================================================================
00126 void ParzenDistributionForce::fixDistributionToUniform(int channel, bool inside)
00127 //===========================================================================
00128 {
00129     const int num_bins = 1; // use only one bin
00130     Histogram h(channel_ranges_[channel].first, channel_ranges_[channel].second, num_bins);
00131     h.binValues()[0] = 1;
00132     if (inside) {
00133         hist_[channel].first = h;
00134         is_fixed_[channel].first = true;
00135     } else {
00136         hist_[channel].second = h;
00137         is_fixed_[channel].second = true;
00138     }
00139     precompute_force(channel, hist_[channel].first, hist_[channel].second, precalc_force_[channel]);
00140 }
00141 
00142 //===========================================================================
00143 void ParzenDistributionForce::fixChannelDistributionTo(int channel, std::istream& is, bool inside)
00144 //===========================================================================
00145 {
00146     // reading distribution
00147     Histogram h;
00148     h.read(is);
00149     
00150     if (inside) {
00151         hist_[channel].first = h;
00152         is_fixed_[channel].first = true;
00153     } else {
00154         hist_[channel].second = h;
00155         is_fixed_[channel].second = true;
00156     }
00157 
00158     // recompute forces
00159     precompute_force(channel, hist_[channel].first, hist_[channel].second, precalc_force_[channel]);
00160 }
00161 
00162 //===========================================================================
00163 void ParzenDistributionForce::unfixChannelDistribution(int channel, bool inside)
00164 //===========================================================================
00165 {
00166     if (inside) {
00167         is_fixed_[channel].first = false;
00168         hist_[channel].first = makeDefaultHistogram(channel);
00169     } else {
00170         is_fixed_[channel].second = false;
00171         hist_[channel].second = makeDefaultHistogram(channel);
00172     }
00173 }
00174 
00175 //===========================================================================
00176 Histogram ParzenDistributionForce::makeDefaultHistogram(int channel) const 
00177 //===========================================================================
00178 {
00179     const int DEFAULT_NUM_BINS = 256;
00180 
00181     return Histogram(channel_ranges_[channel].first, 
00182                      channel_ranges_[channel].second,
00183                      DEFAULT_NUM_BINS);
00184 }
00185 
00187 //void ParzenDistributionForce::dumpHistogram(char* filename, 
00188 //                                           int channel, 
00189 //                                           bool inside) const
00191 //{
00192 //    ofstream os(filename);
00193 //    for (int i = 0; i < num_bins_; ++i) {
00194 //      if (inside) {
00195 //          os << idist_[channel][i] << " ";
00196 //      } else {
00197 //          os << odist_[channel][i] << " ";
00198 //      }
00199 //    }
00200 //    os.close();
00201 //}
00202 
00203 //===========================================================================
00204 void ParzenDistributionForce::update(const LevelSetFunction& phi) 
00205 //===========================================================================
00206 {
00207     assert(phi.spatial_compatible(*img_));
00208     const double sigma_h = 8; // blur factor
00209     const int num_channels = img_->numChannels();
00210 
00211     for (int ch = 0; ch < num_channels; ++ch) {
00212         if (is_fixed_[ch].first && is_fixed_[ch].second) {
00213             // nothing to do for this channel
00214             continue;
00215         }
00216         Histogram dummy; // even though either of 'idist' and 'odist' below
00217                          // might be assigned to this vector, we know that they
00218                          // will not both be assigned to it at the same time,
00219                          // due to the test above.
00220         Histogram& ihist = is_fixed_[ch].first ? dummy : hist_[ch].first;
00221         Histogram& ohist = is_fixed_[ch].second ? dummy : hist_[ch].second;
00222 
00223         get_histogram(ch, phi, ihist, ohist);
00224             
00225         // blurring histogram (a little hacked)
00226         ihist.blur(sigma_h);
00227         ohist.blur(sigma_h);
00228 
00229         // precalculating the induced force for this value in this channel
00230         precompute_force(ch, hist_[ch].first, hist_[ch].second, precalc_force_[ch]);
00231     }
00232 }
00233 
00234 //===========================================================================
00235 void ParzenDistributionForce::get_histogram(int channel, 
00236                                              const LevelSetFunction& phi,
00237                                              Histogram& ihist,
00238                                              Histogram& ohist) const
00239 //===========================================================================
00240 {
00241     ihist.init(channel_ranges_[channel].first, channel_ranges_[channel].second, num_force_bins_);
00242     ohist.init(channel_ranges_[channel].first, channel_ranges_[channel].second, num_force_bins_);
00243 
00244     vector<double>& idist = ihist.binValues();
00245     vector<double>& odist = ohist.binValues();
00246     std::fill(idist.begin(), idist.end(), 1); // by starting with one 'free pixel' in each bin,
00247     std::fill(odist.begin(), odist.end(), 1); // we assure that no bin will end up with a zero value,
00248     double area_inside = 0;                   // which would give rise to possibly infinite forces later.
00249     double area_outside = 0;
00250     
00251     const double* data = img_->channelBegin(channel);
00252     const double* end = phi.end();
00253 
00254     // computing distributions
00255     if (mask_) {
00256         const char* m_ptr = mask_ ? mask_->begin() : 0;
00257         for (const double* it_phi = phi.begin(); it_phi != end; ++it_phi, ++data) {
00258             if (*m_ptr++) {
00259                 const int bin_ix = getForceBin(*data, channel);
00260                 assert(bin_ix >= 0 && bin_ix < num_force_bins_);
00261                 if (*it_phi <= 0) {
00262                     idist[bin_ix] += 1;
00263                     area_inside += 1;
00264                 } else {
00265                     odist[bin_ix] += 1;
00266                     area_outside += 1;
00267                 }
00268             }
00269         }
00270     } else {
00271         for (const double* it_phi = phi.begin(); it_phi != end; ++it_phi, ++data) {
00272             const int bin_ix = getForceBin(*data, channel);
00273             assert(bin_ix >= 0 && bin_ix < num_force_bins_);
00274             if (*it_phi <= 0) {
00275                 idist[bin_ix] += 1;
00276                 area_inside += 1;
00277             } else {
00278                 odist[bin_ix] += 1;
00279                 area_outside += 1;
00280             }
00281         }
00282     }
00283     // normalizing
00284     double area_inside_inv = area_inside != 0 ? double(1) / area_inside : 1;
00285     double area_outside_inv = area_outside != 0 ? double(1) / area_outside : 1;
00286     for (int i = 0; i < num_force_bins_; ++i) {
00287         odist[i] *= area_outside_inv;
00288         idist[i] *= area_inside_inv;
00289     }
00290 }
00291 
00292 //===========================================================================
00293 int ParzenDistributionForce::getForceBin(double val, int channel) const
00294 //===========================================================================
00295 {
00296     int res = int((val - channel_ranges_[channel].first) * force_bin_factor_[channel]);
00297     if (res >= num_force_bins_) {
00298         --res;
00299     }
00300     return res;
00301 }
00302 
00303 //===========================================================================
00304 double ParzenDistributionForce::force2D(int x, int y) const
00305 //===========================================================================
00306 {
00307     return force(img_->indexOf(x, y));    
00308 }
00309 
00310 //===========================================================================
00311 double ParzenDistributionForce::force3D(int x, int y, int z) const 
00312 //===========================================================================
00313 {
00314     return force(img_->indexOf(x, y, z));
00315 }
00316 
00317 //===========================================================================
00318 double ParzenDistributionForce::force(size_t ix) const
00319 //===========================================================================
00320 {
00321     // force only defined inside mask
00322     assert(!mask_ || (*mask_)[ix]);
00323 
00324     const size_t chan_size = img_->channelSize();
00325     const int num_channels = img_->numChannels();
00326 
00327     double res = 0;
00328 
00329     for (int c = 0; c < num_channels; ++c) {
00330         
00331         int bin_ix = getForceBin((*img_)[c * chan_size + ix], c);
00332         res += precalc_force_[c][bin_ix];
00333     }
00334     return res;
00335 }
00336 
00337 //===========================================================================
00338 void ParzenDistributionForce::force(LevelSetFunction& res, const Mask* m) const
00339 //===========================================================================
00340 {
00341     assert(!m || img_->spatial_compatible(*m));
00342     assert(img_->spatial_compatible(res));
00343     const size_t SIZE = res.size();
00344 
00345     // explicit checking of mask presence for optimization reasons
00346     if (m) {
00347         if (mask_) {
00348             for (size_t it = 0; it < SIZE; ++it) {
00349                 res[it] = ((*m)[it] && (*mask_)[it]) ? force(it) : 0;
00350             }
00351         } else {
00352             for (size_t it = 0; it < SIZE; ++it) {
00353                 res[it] = (*m)[it] ? force(it) : 0;
00354             }
00355         }
00356     } else {
00357         if (mask_) {
00358             for (size_t it = 0; it < SIZE; ++it) {
00359                 res[it] = (*mask_)[it] ? force(it) : 0;
00360             }
00361         } else {
00362             for (size_t it = 0; it < SIZE; ++it) {
00363                 res[it] = force(it);
00364             }
00365         }
00366     }
00367 }
00368 
00369 //===========================================================================
00370 double ParzenDistributionForce::getCenterBinValue(int channel, int ix)
00371 //===========================================================================
00372 {
00373     double min = channel_ranges_[channel].first;
00374     double max = channel_ranges_[channel].second;
00375     return min + (double(ix) + 0.5) / force_bin_factor_[channel];
00376 }
00377 
00378 //===========================================================================
00379 void ParzenDistributionForce::precompute_force(int channel,
00380                                                const Histogram& ihist,
00381                                                const Histogram& ohist,
00382                                                std::vector<double>& forcevec)
00383 //===========================================================================
00384 {
00385     forcevec.resize(num_force_bins_);
00386     
00387     // precalculating the induced force for this value
00388     std::fill(forcevec.begin(), forcevec.end(), 0);
00389     const double min_possible = double(1) / double(img_->size());
00390     if (multi_region_mode_) {
00391         for (int i = 0; i < num_force_bins_; ++i) {
00392             double val = ihist.valueFor(getCenterBinValue(channel, i));
00393             val = (val > min_possible) ? val : min_possible;
00394             forcevec[i] = log(val);
00395         }
00396     } else {
00397         for (int i = 0; i < num_force_bins_; ++i) {
00398 
00399             double val = getCenterBinValue(channel, i);
00400             double ival = ihist.valueFor(val);
00401             double oval = ohist.valueFor(val);
00402             ival = (ival > min_possible) ? ival : min_possible;
00403             oval = (oval > min_possible) ? oval : min_possible;
00404             forcevec[i] = log(ival / oval);
00405         }
00406     }
00407 }
00408 
00409 
00410 }; // end namespace lsseg

Generated on Tue Nov 28 18:35:47 2006 for lsseg by  doxygen 1.4.7