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 #include "NormalDistributionForce.h"
00051
00052 namespace lsseg {
00053
00054
00055 NormalDistributionForce::NormalDistributionForce(const Image<double>* img,
00056 Mask* m,
00057 bool multireg_mode)
00058
00059 : multi_region_mode_(multireg_mode)
00060 {
00061 init(img, m);
00062 }
00063
00064
00065 void NormalDistributionForce::init(const Image<double>* img, const Mask* mask)
00066
00067 {
00068
00069 assert(img);
00070 assert(!mask || mask->numChannels() == 1);
00071 assert(!mask || img->spatial_compatible(*mask));
00072
00073 img_ = img;
00074 mask_ = mask;
00075 const int nchan = img->numChannels();
00076 mu_in_.resize(nchan);
00077 mu_out_.resize(nchan);
00078 inv_sigma_in_.resize(nchan);
00079 inv_sigma_out_.resize(nchan);
00080 precalc_log_.resize(nchan);
00081 }
00082
00083
00084 void NormalDistributionForce::update(const LevelSetFunction& phi)
00085
00086 {
00087
00088 assert(phi.spatial_compatible(*img_));
00089
00090 compute_averages(phi);
00091 compute_deviations(phi);
00092 }
00093
00094
00095 double NormalDistributionForce::force2D(int x, int y) const
00096
00097 {
00098 return force(img_->indexOf(x, y));
00099 }
00100
00101
00102 double NormalDistributionForce::force3D(int x, int y, int z) const
00103
00104 {
00105 return force(img_->indexOf(x, y, z));
00106 }
00107
00108
00109 double NormalDistributionForce::force(size_t ix) const
00110
00111 {
00112
00113 assert(!mask_ || (*mask_)[ix]);
00114
00115 double res = 0;
00116 const int CNUM = img_->numChannels();
00117 const int CSIZE = img_->channelSize();
00118
00119 if (multi_region_mode_) {
00120 for (int c = 0; c < CNUM; ++c) {
00121 const size_t c_offset = c * CSIZE;
00122 const double s1_inv = inv_sigma_in_[c];
00123 const double img_val = (*img_)[ix + c_offset];
00124 const double tmp = (img_val - mu_in_[c]) * s1_inv;
00125 res += precalc_log_[c] - 0.5 * tmp * tmp;
00126 }
00127 } else {
00128 for (int c = 0; c < CNUM; ++c) {
00129 const size_t c_offset = c * CSIZE;
00130 const double s1_inv = inv_sigma_in_[c];
00131 const double s2_inv = inv_sigma_out_[c];
00132 const double img_val = (*img_)[ix + c_offset];
00133 const double tmp1 = (img_val - mu_in_[c]) * s1_inv;
00134 const double tmp2 = (img_val - mu_out_[c]) * s2_inv;
00135 res += precalc_log_[c] + 0.5 * (tmp2 * tmp2 - tmp1 * tmp1);
00136 }
00137 }
00138 return res;
00139 }
00140
00141
00142 void NormalDistributionForce::force(LevelSetFunction& res, const Mask* m) const
00143
00144 {
00145 assert(!m || img_->spatial_compatible(*m));
00146 assert(img_->spatial_compatible(res));
00147 const size_t SIZE = res.size();
00148
00149
00150 if (m) {
00151 if (mask_) {
00152 for (size_t it = 0; it < SIZE; ++it) {
00153 res[it] = ((*m)[it] && (*mask_)[it]) ? force(it) : 0;
00154 }
00155 } else {
00156 for (size_t it = 0; it < SIZE; ++it) {
00157 res[it] = (*m)[it] ? force(it) : 0;
00158 }
00159 }
00160 } else {
00161 if (mask_) {
00162 for (size_t it = 0; it < SIZE; ++it) {
00163 res[it] = (*mask_)[it] ? force(it) : 0;
00164 }
00165 } else {
00166 for (size_t it = 0; it < SIZE; ++it) {
00167 res[it] = force(it);
00168 }
00169 }
00170 }
00171 }
00172
00173
00174 void NormalDistributionForce::compute_averages(const LevelSetFunction& phi)
00175
00176 {
00177 assert(img_->spatial_compatible(phi));
00178 const size_t CSIZE = img_->channelSize();
00179
00180 for (int c = 0; c < img_->numChannels(); ++c) {
00181 size_t num_in = 0;
00182 size_t num_out = 0;
00183
00184
00185 mu_in_[c] = mu_out_[c] = 0;
00186 const size_t c_offset = c * CSIZE;
00187
00188 if (mask_) {
00189 for (size_t i = 0; i < CSIZE; ++i) {
00190 if ((*mask_)[i]) {
00191 const double img_val = (*img_)[i + c_offset];
00192 if (phi[i] <= 0) {
00193 ++num_in;
00194 mu_in_[c] += img_val;
00195 } else {
00196 ++num_out;
00197 mu_out_[c] += img_val;
00198 }
00199 }
00200 }
00201 } else {
00202
00203 for (size_t i = 0; i < CSIZE; ++i) {
00204 const double img_val = (*img_)[i + c_offset];
00205 if (phi[i] <= 0) {
00206 ++num_in;
00207 mu_in_[c] +=img_val;
00208 } else {
00209 ++num_out;
00210 mu_out_[c] += img_val;
00211 }
00212 }
00213 }
00214 if (num_in > 0) {
00215 mu_in_[c] /= double(num_in);
00216 }
00217 if (num_out > 0) {
00218 mu_out_[c] /= double(num_out);
00219 }
00220 }
00221 }
00222
00223
00224 void NormalDistributionForce::compute_deviations(const LevelSetFunction& phi)
00225
00226 {
00227
00228
00229 const double PI = 3.1415926535897932384;
00230 const double log_inv_root_2pi = log(double(1)/sqrt(2 * PI));
00231
00232 assert(img_->spatial_compatible(phi));
00233 const double EPS = 1.0e-2;
00234 const size_t CSIZE = img_->channelSize();
00235
00236 for (int c = 0; c < img_->numChannels(); ++c) {
00237 size_t num_in = 0;
00238 size_t num_out = 0;
00239
00240 const size_t c_offset = c * CSIZE;
00241
00242 if (mask_) {
00243 for (size_t i = 0; i < CSIZE; ++i) {
00244 if((*mask_)[i]) {
00245 const double img_val = (*img_)[i + c_offset];
00246 if (phi[i] <= double(0)) {
00247 ++num_in;
00248 const double diff = mu_in_[c] - img_val;
00249 inv_sigma_in_[c] += diff * diff;
00250 } else {
00251 ++num_out;
00252 const double diff = mu_out_[c] - img_val;
00253 inv_sigma_out_[c] += diff * diff;
00254 }
00255 }
00256 }
00257 } else {
00258
00259 for (size_t i = 0; i < CSIZE; ++i) {
00260 const double img_val = (*img_)[i + c_offset];
00261 if (phi[i] <= double(0)) {
00262 ++num_in;
00263 const double diff = mu_in_[c] - img_val;
00264 inv_sigma_in_[c] += diff * diff;
00265 } else {
00266 ++num_out;
00267 const double diff = mu_out_[c] - img_val;
00268 inv_sigma_out_[c] += diff * diff;
00269 }
00270 }
00271 }
00272 if (num_in > 0) {
00273 inv_sigma_in_[c] /= double(num_in);
00274 inv_sigma_in_[c] = sqrt(inv_sigma_in_[c]);
00275 inv_sigma_in_[c] = double(1) / (inv_sigma_in_[c] > EPS ? inv_sigma_in_[c] : EPS);
00276 } else {
00277 inv_sigma_in_[c] = double(1) / EPS;
00278 }
00279 if (num_out > 0) {
00280 inv_sigma_out_[c] /= double(num_out);
00281 inv_sigma_out_[c] = sqrt(inv_sigma_out_[c]);
00282 inv_sigma_out_[c] = double(1) / (inv_sigma_out_[c] > EPS ? inv_sigma_out_[c] : EPS);
00283 } else {
00284 inv_sigma_out_[c] = double(1) / EPS;
00285 }
00286 precalc_log_[c] = multi_region_mode_ ?
00287 log(inv_sigma_in_[c]) + log_inv_root_2pi :
00288 log(inv_sigma_in_[c] / inv_sigma_out_[c]);
00289 }
00290 }
00291
00292
00293 };