00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #include "ParzenDistributionForce.h"
00057 #include "cimg_dependent.h"
00058 #include "errormacros.h"
00059 #include <assert.h>
00060 #include <vector>
00061 #include <fstream>
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
00082 assert(img);
00083 assert(!m || m->numChannels() == 1);
00084 assert(!m || img->spatial_compatible(*m));
00085
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;
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
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
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
00188
00189
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 void ParzenDistributionForce::update(const LevelSetFunction& phi)
00205
00206 {
00207 assert(phi.spatial_compatible(*img_));
00208 const double sigma_h = 8;
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
00214 continue;
00215 }
00216 Histogram dummy;
00217
00218
00219
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
00226 ihist.blur(sigma_h);
00227 ohist.blur(sigma_h);
00228
00229
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);
00247 std::fill(odist.begin(), odist.end(), 1);
00248 double area_inside = 0;
00249 double area_outside = 0;
00250
00251 const double* data = img_->channelBegin(channel);
00252 const double* end = phi.end();
00253
00254
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
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
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
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
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 };