00001 #include "mex.h" /* must appear first */ 00002 #include <stdlib.h> 00003 #include <stdio.h> 00004 #include <math.h> 00005 #include <memory.h> 00006 #include <limits.h> 00007 #include "mexhead.h" /* my mex defines */ 00008 #include "rng.h" /* random numbers */ 00009 #include "Doc/mrf_segment_wts_docstring.h" /* autogenerated from this file */ 00010 00011 00012 /************************************************************** 00013 00014 %mrf_segment_wts: segment with a discrete Markov random field 00015 % 00016 % [yp,post] = mrf_segment_wts(iter,T,beta,alpha,dist,y,lprob1,...,lprobK) 00017 % * Performs iter full sweeps (using temperature schedule T) of 00018 % Gibbs sampling on an input labeling y, with entries in 1..K, to produce 00019 % an output labeling yp. Posterior probability is optionally returned. 00020 % Posterior is actually an energy function, which is correct with respect 00021 % to changes in y, but does not have the correct scale factors which 00022 % vary with beta, alpha, and dist. 00023 % * Conditional distributions of pixel data x given class y are 00024 % calculated externally, and given by lprob1...lprobK, as log- 00025 % probabilities. 00026 % * Per-class biases are given by alpha, which can be empty, indicating 00027 % no bias. Otherwise, the interpretation is alpha(k) is the prior 00028 % log-probability of seeing class k. 00029 % * The smoothness parameter of the MRF (Potts model) is beta. If beta 00030 % is a matrix, beta(k,l) is the smoothness "reward" given to a site of 00031 % class k for having a neighbor of class l. The scalar beta thus 00032 % corresponds to a diagonal matrix with repeated beta entries. 00033 % (beta and alpha agree with definitions in the Besag paper below.) 00034 % * Pixel-pixel distances are given by dist, where dist(nu,m,n) gives 00035 % the distance between pixel (i,j) and its neighbor number nu, looking 00036 % up or left. For the 3x3 neighborhood, pixel s=(m,n) has 8 neighbors s', 00037 % and distances to 4 of them, where s'<s, at offsets: 00038 % (-1,-1),(0,-1),(1,-1),(-1,0), 00039 % are given in that order, in dist(i,j,:). The other neighbors 00040 % have s'>s, and the corresponding distances are listed in the 00041 % symmetric entries of dist. If dist=[], it is taken to be 00042 % everywhere 1, thus removing the direction-sensitive smoothing 00043 % (but still smoothing). 00044 % * Classes are 1..K, but labels NaN and 0 are not updated or counted 00045 % as neighbors. Any NaN in a log-probability forces a NaN in the 00046 % output class. 00047 % * A `clock' at each pixel may speed computation. This recognizes that, 00048 % if the neighbors of a pixel do not change, the Gibbs sampler is rolling 00049 % a stationary die once per iteration to determine the pixel label. 00050 % The waiting time until another label change is then geometric, 00051 % and this waiting time can be sampled once to short-circuit a series 00052 % of die rolls. See Ripley, below. 00053 % * The speedup of this method is greatest when few labels change. If 00054 % supplied, iter(2) is the threshold (in [0,1]) of #changed/#labels 00055 % for a switchover from the ordinary method to the clock method. 00056 % (Only one switch is permitted in the iteration sequence.) 00057 % If iter(2) = 0, the ordinary coin-flip method is used throughout; 00058 % if =1, the clock method is used throughout. 00059 % * Annealing is permitted through the `temperature' parameter T. 00060 % Initial temperature is T(1), reduced by a factor of T(2) at each 00061 % iteration. The default T(2) = 1 suppresses annealing. 00062 % Clocks are reset whenever the cumulative drop in temperature 00063 % reaches a factor of T(3). (Roughly, then, clocks are reset every 00064 % log(T(3))/log(T(2)) iterations.) If T(4) is present and equals 00065 % zero, additional iterations are done at zero temperature, at the 00066 % end of the normal annealing schedule, until the labels reach a 00067 % fixed point. (This is equivalent to Besag's ICM.) 00068 % * If iter[1] has a fractional part, that part is multiplied by 2**31 00069 % and rounded to set the desired random number seed; if not, a 00070 % pseudorandom seed is generated. This is provided to allow repeatability. 00071 % * This is implemented as a MEX file. 00072 % 00073 % Inputs: 00074 % int iter[1] or [2] = [0 0.05]; 00075 % real T[0] or [1] or [2] or [3] or [4] = [1 1 0.8 0]; 00076 % real beta[1] or [K,K]; 00077 % real alpha[K] or [0] = []; 00078 % real dist[nbr,m,n] or [0]; 00079 % int y[m,n]; -- 1 <= y <= K, or 0 or NaN 00080 % real lprob1[m,n]; 00081 % ... 00082 % real lprobK[m,n]; 00083 % 00084 % Outputs: 00085 % int yp[m,n]; -- 1 <= y <= K, or 0 or NaN 00086 % opt real post; 00087 % 00088 % See Also: mrf_segment, makemrfdiscwts 00089 % Geman and Geman, Stochastic relaxation, Gibbs distributions, and 00090 % the Bayesian restoration of images, IEEE PAMI Nov. 1984 00091 % J. Besag, On the statistical analysis of dirty pictures, JRSSB, 1986 00092 % B. D. Ripley, Statistical Inference for Spatial Processes, 00093 % Cambridge U., 1988, p. 99 00094 00095 % turmon sep/oct 2006, weighted distance 00096 % turmon 5 march 1999, modified to streamline for batch operations 00097 % MJT 18 Mar 1996 00098 00099 ***************************************************************/ 00100 /* Updated by -mex2pymex.py-ver1- on Wed Sep 23 16:55:52 2009 */ 00101 00102 /************************************************************** 00103 *** WEIGHTED DISTANCE IMPLEMENTATION NOTES 00104 THIS IS AN EXPERIMENTAL VERSION 00105 00106 07/nov/2006 00107 00108 Still to-do: check the kmax and clock variables eg for a small example 00109 as mentioned below. 00110 Tests on solar images seem OK, but would like to quantitatively test 00111 the rate of pixel class flips. 00112 00113 00114 04/nov/2006 00115 00116 Still need to check kmax and clock. 00117 00118 Also, one query: I thought the "most probable class and clock > it_left" 00119 property would imply the number of clocks to manage should be decreasing, 00120 in fact, in small examples, should be decreasing from say 16 to say 1 or 2 00121 active pixels. Does this actually happen? I couldn't find evidence. 00122 00123 Perhaps something as simple as a count of active clocks? 00124 00125 00126 03/nov/2006 00127 00128 checked kmax/0temp against earlier version: works 00129 calloc seems OK. 00130 00131 todo 00132 return clock/kmax to matlab for checks 00133 00134 00135 10/24 00136 Suggest an implementation change: 00137 - instead of resetting all the clocks when temperature ratchets down, 00138 don't reset large clocks as temperature drops 00139 00140 *************************************************************/ 00141 00142 /************************************************************* 00143 00144 WEIGHTED DISTANCE IMPLEMENTATION METHOD 00145 00146 type Count becomes a quasi-count (counts weighted neighbor classes) 00147 3d array count3 records quasi-counts for each site, each class 00148 00149 When s=(n,m) is altered from past_y->this_y, counts for each neighbor (i,j), 00150 (i,j) in {-1,0,1}^2 \ {0,0}, are NOW updated according to: 00151 00152 count3[past_y][n+i][m+j]--; 00153 count3[this_y][n+i][m+j]++; 00154 00155 This changed to: 00156 00157 dist = wtd_distance((m,n),(m+j,n+i)); 00158 count3[past_y][n+i][m+j] -= dist; 00159 count3[this_y][n+i][m+j] += dist; 00160 00161 and we define wtd_distance(s,s') like: 00162 00163 if (s<s') { 00164 nu = offset(i,j) // 0, 1, 2, or 3 00165 return dist(nu,m,n,nu) // lookup in array 00166 } else { 00167 nu = offset(-i,-j) // 0, 1, 2, or 3 00168 return dist(nu,m+j,n+i) 00169 } 00170 00171 A check is done [routine: check_counts()] verifying that the neighbor 00172 quasi-counts, which we update as we go along, are still correct at 00173 the end of the iteration. They are real-valued, so the comparison 00174 allows small differences. 00175 00176 ****************************************************************/ 00177 00178 typedef float Count; /* neighbors' per-class quasi-counts */ 00179 typedef unsigned int Clock; /* clock for expiration of label */ 00180 typedef unsigned char Class; /* class label */ 00181 #define ClassMax 8 /* maximum number of classes (can be increased) */ 00182 #define CLOCK_MAX UINT_MAX /* max integer held by Clock */ 00183 #define NBHD_WIDTH 1 /* width of neighborhood around one pixel */ 00184 #define NBHD_BLOCK (NBHD_WIDTH*2+1) /* total block size (odd) */ 00185 #define NBHD_NUM_2 ((NBHD_BLOCK*NBHD_BLOCK-1)/2) /* number of nbrs / 2 */ 00186 00187 #define NARGIN_MIN_const 7 /* constant to do arithmetic on below */ 00188 #define NARGIN_MIN (NARGIN_MIN_const) /* min number of inputs (one class) */ 00189 #define NARGIN_MAX (NARGIN_MIN_const+ClassMax-1) /* max number of inputs */ 00190 #define NARGOUT_MIN 0 /* min number of output args */ 00191 #define NARGOUT_MAX 2 /* max number of output args */ 00192 /*#undef NARGIN_MIN_const /* don't need this any more */ 00193 00194 #define ARG_iters 0 00195 #define ARG_T 1 00196 #define ARG_beta 2 00197 #define ARG_alpha 3 00198 #define ARG_dist 4 00199 #define ARG_y 5 00200 #define ARG_lprob 6 00201 00202 #define ARG_yp 0 00203 #define ARG_post 1 00204 00205 static const char *progname = "mrf_segment_wts"; 00206 #define PROGNAME mrf_segment_wts 00207 static const char *in_specs[NARGIN_MAX] = { 00208 "RS|RV(2)", 00209 "RS|RV(2)|RV(3)|RV(4)", 00210 "RS(1)|RM", 00211 "RV", 00212 "RA", /* dist */ 00213 "RM", /* y */ 00214 "RA|RM", /* lprob1 */ 00215 "RM", /* lprob2 */ 00216 "RM", /* lprob3 */ 00217 "RM", /* lprob4 */ 00218 "RM", /* lprob5 */ 00219 "RM", /* lprob6 */ 00220 "RM", /* lprob7 */ 00221 "RM"};/* lprob8 */ 00222 static const char *in_names[NARGIN_MAX] = { 00223 "iters", 00224 "T", 00225 "beta", 00226 "alpha", 00227 "dist", 00228 "y", 00229 "lprob1", 00230 "lprob2", 00231 "lprob3", 00232 "lprob4", 00233 "lprob5", 00234 "lprob6", 00235 "lprob7", 00236 "lprob8"}; 00237 static const char *out_names[NARGOUT_MAX] = { 00238 "yp", "post"}; 00239 00240 // defined just for brevity in a generated #include file 00241 #define SHORTNAME msw 00242 00243 /* 00244 * Default arguments (used in mexFunction) 00245 */ 00246 #define Iters_count 2 00247 #define Default_iters_count 2 00248 static double Default_iters[Default_iters_count] = { 0.0, 0.05 }; 00249 #define T_count 4 00250 #define Default_T_count 4 00251 static double Default_T[Default_T_count] = { 1.0, 1.0, 0.8, 0.0 }; 00252 00253 00254 /********************************************************************* 00255 * UTILITIES: Labels 00256 *********************************************************************/ 00257 00258 /* simple utilities */ 00259 #define ISLEGAL(l,L) (((l)>=0)&&((l)<L)) /* for indexing: 0 <= l < L */ 00260 #define ActiveLabel(y) ((!isnan(y)) && ((y) > 0)) /* not NaN and not 0 */ 00261 00262 00263 /* 00264 * set label to inactive if any log-probability is NaN 00265 */ 00266 static 00267 void 00268 find_inactive_labels( 00269 double **y, 00270 double ***logp, 00271 int M, 00272 int N, 00273 int K) 00274 { 00275 int m, n, k; /* counters */ 00276 const double nan = mxt_getnand(); 00277 00278 for (n = 0; n < N; n++) 00279 for (m = 0; m < M; m++) { 00280 for (k = 0; k < K; k++) 00281 if (isnan(logp[k][n][m])) { 00282 y[n][m] = nan; /* ie, inactive */ 00283 break; /* go to next pixel */ 00284 } 00285 } /* for m, n */ 00286 } 00287 00288 00289 /* 00290 * check_labels: Are classes y all integers in 1..K, or 0, or NaN? 00291 */ 00292 static 00293 int 00294 check_labels( 00295 int K, /* correct number of classes excluding 0 */ 00296 double *y, 00297 int N) 00298 { 00299 int n; 00300 00301 for (n = 0; n < N; n++) 00302 if (!isnan(y[n])) 00303 if (y[n] < 0 || y[n] > K || floor(y[n]) != y[n]) 00304 return(0); 00305 return(1); 00306 } 00307 00308 00309 /********************************************************************* 00310 * UTILITIES: Counts, aka Quasi-counts 00311 *********************************************************************/ 00312 00313 /* 00314 * sites2dist: given two sites, return their distance d(s,s'). 00315 * The distance array is a flat list generically indexed by (nu,m,n), 00316 * 0 <= nu < NBHD_NUM_2 (varies fastest) 00317 * 0 <= m < M (next fastest) 00318 * 0 <= n < N (varies slowest) 00319 * Sites are: 00320 * s = (m,n) 00321 * s'= (m+j,n+i) 00322 * and the distance array is size NBHD_NUM_2xMxN. For example, for 3x3 00323 * blocks centered about each site, sites have 8 neighbors, 00324 * NBHD_NUM_2 = 4 and NBHD_BLOCK = 3. For 5x5 blocks, sites have 00325 * 24 neighbors, NBHD_NUM_2 = 12, and NBHD_BLOCK = 5. 00326 * 00327 * The trick is finding an offset into this array. If the array 00328 * is null, the return value is always 1, so the distances 00329 * are isotropic (but not zero) in this case. 00330 * 00331 * The neighbor at (j,i) corresponds to an offset 00332 * nu = j + NBHD_BLOCK*i, 00333 * where j (corresponding to m) varies faster than i 00334 * (corresponding to n). 00335 * This is where the neighbor indexing is critical. 00336 * Eg, for del=3, we have 3x3 neighborhoods around the central 00337 * point [s], and del2half = 4 prior neighbors that are ordered 00338 * as shown below. The subsequent neighbors s' marked by [-] are 00339 * not stored with s because s is a prior neighbor of each such 00340 * s'. Storage is done this way so that every patch of distances 00341 * (ie, the numbered squares below) is still in the same indexing 00342 * order as the original images. So, for example, if we have all 00343 * 9 distances, a simple reshape(dists, [3 3]) will put them in 00344 * an immediately recognizable format. 00345 * n-> 00346 * m 0 3 - 00347 * | 1 s - 00348 * V 2 - - 00349 * In the general del case, neighbors are indexed by 00350 * nu = 0...NBHD_NUM_2-1, and nu=0 corresponds to the "farthest" 00351 * pixel (lexicographically) and nu=max corresponds to the site 00352 * closest to s. 00353 * 00354 * 1. If s' < s in lexicographic order, then the distance is stored 00355 * in the NBHD_NUM_2-length vector associated with s. The offset, nu, 00356 * into the vector is found from s-s' = (-j,-i), which is a pair of 00357 * nonnegative integers, since i < 0 or j < 0 in this case. 00358 * 2. If s' > s, then the distance is stored in the vector associated 00359 * with s'. The offset is found in the same way, from s'-s=(j,i), 00360 * which is again a pair of nonnegative integers. 00361 * This could be implemented as a macro, but doing so seems to offer 00362 * no speed advantage. 00363 */ 00364 static 00365 double 00366 sites2dist(double *dist, 00367 int M, 00368 int N, 00369 int m, 00370 int n, 00371 int j, 00372 int i) 00373 00374 { 00375 /* the nu below is a precursor to the nu in the narrative above */ 00376 double nu = j + NBHD_BLOCK*i; /* ie, delta_m + BLOCK*delta_n */ 00377 int offset; 00378 00379 if (!dist) return 1.0; /* null pointer */ 00380 if (nu < 0) /* case 1 above */ 00381 /* s' < s: return the (j,i) neighbor of s=(m,n) */ 00382 /* nu ranges from -NBHD_NUM_2(max offset)...-1(nearest), 00383 * we have to "flip" it by doing NBHD_NUM_2 + nu to get 00384 * the actual offset */ 00385 offset = (n*M+m)*NBHD_NUM_2 + (NBHD_NUM_2 + nu); 00386 else 00387 /* s' > s: return the (j,i) neighbor of s'=(m+j,n+i) */ 00388 /* nu ranges from +1(nearest)...NBHD_NUM_2(max offset) */ 00389 offset = ((n+i)*M+(m+j))*NBHD_NUM_2 + (NBHD_NUM_2 - nu); 00390 /* range check is disabled unless debug flag is on */ 00391 mxAssert(offset >= 0 && offset < M*N*NBHD_NUM_2, "sites2dist range error"); 00392 return dist[offset]; 00393 } 00394 00395 00396 /* 00397 * Initialize neighborhood quasi-counts based on label structure 00398 */ 00399 static 00400 void 00401 init_counts( 00402 Count ***count3, 00403 double **y2, /* in 1..K, or 0 */ 00404 double *dist, /* can be NULL */ 00405 int K, 00406 int M, 00407 int N) 00408 00409 { 00410 int m, n; /* counters */ 00411 int i, j; /* counters */ 00412 int k; /* counters */ 00413 00414 /* Computation */ 00415 for (n = 0; n < N; n++) 00416 for (m = 0; m < M; m++) { 00417 /* Find quasi-counts, of each label, over neighbors of site (m,n) */ 00418 for (k = 0; k < K; k++) 00419 count3[k][n][m] = 0; /* reset all quasi-counts */ 00420 if (!ActiveLabel(y2[n][m])) continue; /* just skip finding its nbrs */ 00421 for (i = -NBHD_WIDTH; i <= NBHD_WIDTH; i++) 00422 if (ISLEGAL(n+i,N)) 00423 for (j = -NBHD_WIDTH; j <= NBHD_WIDTH; j++) 00424 if (ISLEGAL(m+j,M) && ((i != 0) || (j != 0))) { 00425 if (ActiveLabel(y2[n+i][m+j])) 00426 count3[(int) (y2[n+i][m+j]-1)][n][m] += 00427 sites2dist(dist,M,N,m,n,j,i); ; /* y2 in 1..K */ 00428 } 00429 } /* for n, m */ 00430 } 00431 00432 00433 /* 00434 * Does current quasi-count array match the current labeling? 00435 * Return value: number of mismatches, or (-1) for calloc failure 00436 */ 00437 static 00438 int 00439 check_counts( 00440 int K, /* correct number of classes excluding 0 */ 00441 Count ***count3, 00442 double **y2, 00443 double *dist, /* can be NULL */ 00444 int M, 00445 int N) 00446 { 00447 int m, n; /* counters */ 00448 int i, j; /* counters */ 00449 int k; /* counters */ 00450 Count *count1; /* neighbor-counts for one pixel */ 00451 int retval = 0; /* assume OK */ 00452 00453 count1 = (Count *) calloc(K, sizeof(Count)); 00454 if (!count1) return -1; /* trouble */ 00455 /* Computation */ 00456 for (n = 0; n < N; n++) 00457 for (m = 0; m < M; m++) { 00458 /* Find counts of neighbors of each type */ 00459 for (k = 0; k < K; k++) 00460 count1[k] = 0; /* reset all quasi-count accumulators */ 00461 if (!ActiveLabel(y2[n][m])) continue; /* just skip finding its nbrs */ 00462 for (i = -NBHD_WIDTH; i <= NBHD_WIDTH; i++) 00463 if (ISLEGAL(n+i,N)) 00464 for (j = -NBHD_WIDTH; j <= NBHD_WIDTH; j++) 00465 if (ISLEGAL(m+j,M) && ((i != 0) || (j != 0))) { 00466 if (ActiveLabel(y2[n+i][m+j])) 00467 count1[(int) (y2[n+i][m+j]-1)] += 00468 sites2dist(dist,M,N,m,n,j,i); /* y2 in 1..K */ 00469 } 00470 /* Check count3 against count1 (float eps = 1.2e-7) */ 00471 for (k = 0; k < K; k++) 00472 if (fabs(count1[k] - count3[k][n][m]) > 00473 1e-4*max(1.0,fabs(count3[k][n][m]))) { 00474 /* 00475 mexPrintf("(m,n,k) = (%d,%d,%d) count1=%g, count3=%g del = %g\n", 00476 m, n, k, count1[k], count3[k][n][m], 00477 count1[k] - count3[k][n][m]); */ 00478 retval++; 00479 } 00480 } /* for n, m */ 00481 free(count1); 00482 return(retval); 00483 } 00484 00485 00486 /********************************************************************* 00487 * UTILITIES: Clocks 00488 *********************************************************************/ 00489 00490 /* 00491 * include routines for clock generation 00492 */ 00493 00494 #include "mrf_newclock.h" 00495 00496 00497 /* 00498 * Reset the clock associated with each image site. This is 00499 * done when temperature drops, which makes all probabilities 00500 * stale. 00501 * 00502 * This is nontrivial. We compare iter_remain to the current clock. 00503 * There are three cases: 00504 * clock <= iter_remain: reset clock. The temperature drop has 00505 * caused the probabilities to change, and the clock value 00506 * is stale. 00507 * clock > iter_remain and label is NOT the highest-probability 00508 * class: reset clock. The temperature drop will enhance the 00509 * probability of the highest-probability class relative to the 00510 * others, with the likely consequence of making the clock 00511 * (if figured again) smaller than it currently is. 00512 * clock > iter_remain and label IS highest-probability: leave 00513 * clock alone. The temperature drop will cause the probability 00514 * of the current class y (because it is highest) to be even 00515 * larger relative to the other classes. Thus its clock, 00516 * if chosen again, would be larger than it now is. Since it 00517 * will expire after updates cease, the class will never change. 00518 * Because so many labels are dominated by one class, the last case 00519 * is quite common. This is true with real data, but also true of 00520 * situations where the class balance is quite delicate. 00521 * 00522 * It is critical that kmax, the most probable class, be maintained 00523 * outside this routine. Both kmax and y are in the range 1..K, with 00524 * 0 representing "stale." 00525 * 00526 */ 00527 static 00528 void 00529 reset_clocks( 00530 Clock **clock2, /* clocks */ 00531 Class **kmax2, /* class of maximum probability */ 00532 double **y2, /* current class */ 00533 int iter_remain, /* iterations remaining */ 00534 int M, 00535 int N) 00536 { 00537 int m, n; /* counters */ 00538 00539 for (n = 0; n < N; n++) 00540 for (m = 0; m < M; m++) { 00541 /* reset clock only when it is now smaller than the number 00542 of iters left, or its class is not the most likely. 00543 Otherwise, decreasing temperatures imply iterations will 00544 run out before its clock does. 00545 Note, both kmax2 and y2 are in the range 1..K. kmax2 = 0 00546 indicates that kmax is stale. Such a value will never equal y2. 00547 */ 00548 if (!ActiveLabel(y2[n][m])) continue; /* clock irrelevant */ 00549 if (clock2[n][m] <= iter_remain || kmax2[n][m] != y2[n][m]) 00550 clock2[n][m] = 0; 00551 } /* for n, m */ 00552 } 00553 00554 /* 00555 * initialize both clocks and kmax by setting to zero, indicating 00556 * stale values for that site. 00557 */ 00558 static 00559 void 00560 init_clocks( 00561 Clock **clock2, /* clocks */ 00562 Class **kmax2, /* class of maximum probability */ 00563 int M, 00564 int N) 00565 { 00566 int m, n; /* counters */ 00567 00568 for (n = 0; n < N; n++) 00569 for (m = 0; m < M; m++) 00570 clock2[n][m] = kmax2[n][m] = 0; /* for initialization */ 00571 } 00572 00573 00574 /********************************************************************* 00575 * ROUTINES FOR LABELING 00576 * The first (per pixel MAP) is non-iterative, but all others are 00577 * iterative and need an outer loop to invoke them repeatedly 00578 *********************************************************************/ 00579 00580 /* 00581 * Initialize all labels using pixel-wise MAP estimate 00582 * Note, we only need the per-class probabilities and alpha, 00583 * there is no smoothness term. 00584 */ 00585 static 00586 void 00587 per_pixel_map_estimate( 00588 double **y, 00589 double ***logp, 00590 double *alpha, 00591 int M, 00592 int N, 00593 int K) 00594 { 00595 int m, n, k; /* counters */ 00596 double one_prob; /* holds one probability */ 00597 double winner; /* highest prob so far */ 00598 const double nan = mxt_getnand(); 00599 00600 for (n = 0; n < N; n++) 00601 for (m = 0; m < M; m++) { 00602 y[n][m] = 0.0; /* "undefined" to begin with */ 00603 for (k = 0; k < K; k++) { 00604 one_prob = logp[k][n][m] + alpha[k]; /* data term, plus label prior */ 00605 if (isnan(one_prob)) { 00606 /* nan -> invalid pixel; quit looping */ 00607 y[n][m] = nan; 00608 break; 00609 } else if (y[n][m] == 0.0 || one_prob > winner) { 00610 /* valid, and no winner yet, or new winner */ 00611 winner = one_prob; 00612 y[n][m] = k+1; /* stays in range 1..K */ 00613 } 00614 } /* for k */ 00615 /* end loop: y[n][m] != 0 */ 00616 } /* for m, n */ 00617 } 00618 00619 /* 00620 * find_posterior: finds the posterior probability of the current 00621 * labeling y2 using the stored (and assumed valid) quasi-counts 00622 * in count3. Returns this value as a double. 00623 */ 00624 static 00625 double 00626 find_posterior( 00627 double **y2, /* in 1..K, or 0 or NaN */ 00628 Count ***count3, 00629 double ***lprob, 00630 int K, 00631 double **beta2, 00632 double *alpha, 00633 int M, 00634 int N) 00635 00636 { 00637 int m, n; /* counters */ 00638 int l, k; /* class label */ 00639 double post; /* accumulate log-posterior */ 00640 double mrf_smooth; /* accumulates smoothness term of MRF */ 00641 00642 post = 0.0; 00643 for (n = 0; n < N; n++) 00644 for (m = 0; m < M; m++) { 00645 /* skip inactive pixels */ 00646 if (!ActiveLabel(y2[n][m])) continue; 00647 /* Find posterior of the class label y[n][m] */ 00648 k = y2[n][m]-1; /* in 0..K-1 */ 00649 /* find smoothness term if label #l is eventually chosen */ 00650 for (mrf_smooth = l = 0; l < K; l++) 00651 mrf_smooth += beta2[l][k] * count3[l][n][m]; /* wtd sum of counts */ 00652 /* three terms: class prior, local smoothness, data */ 00653 post += alpha[k] + mrf_smooth + lprob[k][n][m]; 00654 } 00655 return post; 00656 } 00657 00658 00659 /* 00660 * Computational routine: iterate_0temp 00661 * Performs one image sweep using stored neighbor-counts, 00662 * at "zero temperature" -- no sampling is used, so at each 00663 * iteration, each pixel is updated with the most likely label. 00664 * This corresponds to Besag's ICM algorithm. 00665 * 00666 * Returns fraction of active pixels that were changed: 00667 * this is used to determine when a stationary point has been 00668 * reached. 00669 */ 00670 static 00671 double 00672 iterate_0temp( 00673 double **y2, /* in 1..K, or 0 or NaN */ 00674 Count ***count3, 00675 Class **kmax2, 00676 double ***lprob, 00677 int K, 00678 double **beta2, 00679 double *alpha, 00680 double *dist, /* can be NULL */ 00681 int M, 00682 int N) 00683 00684 { 00685 int m, n; /* counters */ 00686 int i, j; /* counters */ 00687 int k, l; /* counters */ 00688 double lprob1; /* log-probability */ 00689 double lprob1_max; /* maximum log-probability */ 00690 const double lprob_max_init = -1E64; /* anything < log(minfloat) */ 00691 double mrf_smooth; /* accumulates smoothness term of MRF */ 00692 Count d1; /* the current quasi-count */ 00693 int this_y, past_y; /* integers for class labels */ 00694 int num_pel_active = 0, num_pel_flip = 0; /* # active or modified pels */ 00695 00696 for (n = 0; n < N; n++) 00697 for (m = 0; m < M; m++) { 00698 /* skip inactive pixels */ 00699 if (!ActiveLabel(y2[n][m])) continue; 00700 num_pel_active++; /* count active pixels */ 00701 /* if this label is already most probable, continue */ 00702 if (kmax2[n][m] == y2[n][m]) continue; 00703 /* Find log-probabilities, and the largest log-probability */ 00704 this_y = 0; /* anything in 0..K-1 is OK, it is overwritten in loop */ 00705 for (lprob1_max = lprob_max_init, k = 0; k < K; k++) { 00706 /* find smoothness term if label #l is eventually chosen */ 00707 for (mrf_smooth = l = 0; l < K; l++) 00708 mrf_smooth += beta2[l][k] * count3[l][n][m]; /* wtd sum of counts */ 00709 /* three terms: class prior, local smoothness, data */ 00710 lprob1 = alpha[k] + mrf_smooth + lprob[k][n][m]; 00711 if (lprob1 > lprob1_max) { 00712 /* update winning class */ 00713 lprob1_max = lprob1; 00714 this_y = k; /* new label candidate, in 0..K-1 */ 00715 } 00716 } 00717 /* Update the label y */ 00718 kmax2[n][m] = this_y+1; /* record most probable label in 1..K */ 00719 past_y = y2[n][m]-1; /* old label. NB! in 0..K-1 */ 00720 if (this_y == past_y) 00721 continue; /* no need to update neighbor counts, just go on */ 00722 y2[n][m] = this_y+1; /* new label as stored, for class in 1..K */ 00723 num_pel_flip++; /* label has changed */ 00724 /* Update costs in neighborhood for the change in label y */ 00725 /* printf("[%d,%d] replaces %d -> %d\n", m, n, past_y, this_y); */ 00726 for (i = -NBHD_WIDTH; i <= NBHD_WIDTH; i++) 00727 if (ISLEGAL(n+i,N)) 00728 for (j = -NBHD_WIDTH; j <= NBHD_WIDTH; j++) 00729 if (ISLEGAL(m+j,M)) 00730 if ((i != 0) || (j != 0)) { /* skip the current site */ 00731 /* update the neighborhood quasi-counts */ 00732 d1 = sites2dist(dist,M,N,m,n,j,i); 00733 count3[past_y][n+i][m+j] -= d1; 00734 count3[this_y][n+i][m+j] += d1; 00735 if (d1 > 0) 00736 kmax2[n+i][m+j] = 0; /* old max-prob is stale */ 00737 } 00738 } 00739 #ifdef DEBUG 00740 mexPrintf("0T: Pixels changed = %f = %d/%d\n", 00741 (double) num_pel_flip/num_pel_active, 00742 (int) num_pel_flip, (int) num_pel_active); 00743 #endif 00744 return((double) num_pel_flip/num_pel_active); /* efficiency measure */ 00745 } 00746 00747 00748 /* 00749 * Computational routine: iterate_count 00750 * Performs one image sweep using stored neighbor-counts 00751 * more efficient when many pixels are changing. 00752 * 00753 * Returns fraction of active pixels that were changed: 00754 * this is a measure of computational burden. 00755 */ 00756 static 00757 double 00758 iterate_count( 00759 double **y2, /* in 1..K, or 0 or NaN */ 00760 Count ***count3, 00761 double ***lprob, 00762 int K, 00763 double T, 00764 double **beta2, 00765 double *alpha, 00766 double *dist, /* can be NULL */ 00767 int M, 00768 int N) 00769 00770 { 00771 int m, n; /* counters */ 00772 int i, j; /* counters */ 00773 int k, l; /* counters */ 00774 double *prob1, *lprob1; /* probabilities and their logs */ 00775 double lprob1_max; /* maximum log-probability */ 00776 const double lprob_max_init = -1E64; /* anything < log(minfloat) */ 00777 const double Tinv = 1.0/T; /* prefer to multiply */ 00778 double mrf_smooth; /* accumulates smoothness term of MRF */ 00779 Count d1; /* the current quasi-count */ 00780 double sum; /* normalization of probability mass function */ 00781 double uni, rng_uniform(); /* random numbers */ 00782 int this_y, past_y; /* integers for class labels */ 00783 int num_pel_active = 0, num_pel_flip = 0; /* # active or modified pels */ 00784 00785 /* Set up per-color bins to hold probabilities */ 00786 prob1 = (double *) calloc(K, sizeof(double)); 00787 lprob1 = (double *) calloc(K, sizeof(double)); 00788 mxAssert(prob1 && lprob1, "mrf_segment_wts: failed calloc(count/lprob)"); 00789 /* Computation */ 00790 for (n = 0; n < N; n++) 00791 for (m = 0; m < M; m++) { 00792 /* skip inactive pixels */ 00793 if (!ActiveLabel(y2[n][m])) continue; 00794 num_pel_active++; /* count active pixels */ 00795 /* Find log-probabilities, and the largest log-probability */ 00796 for (lprob1_max = lprob_max_init, k = 0; k < K; k++) { 00797 /* find smoothness term if label #l is eventually chosen */ 00798 for (mrf_smooth = l = 0; l < K; l++) 00799 mrf_smooth += beta2[l][k] * count3[l][n][m]; /* wtd sum of counts */ 00800 /* three terms: class prior, local smoothness, data */ 00801 lprob1[k] = Tinv * (alpha[k] + mrf_smooth + lprob[k][n][m]); 00802 if (lprob1[k] > lprob1_max) lprob1_max = lprob1[k]; 00803 } 00804 /* compute probability normalization, scaled by exp(-lprob1_max) */ 00805 for (sum = k = 0; k < K; k++) 00806 sum += (prob1[k] = exp(lprob1[k] - lprob1_max)); /* rescale to max */ 00807 /* Note: 0 <= prob1[k] <= 1 and 1 <= sum <= K. prob1/sum is the pmf 00808 * of the new class; prob1 itself is un-normalized. */ 00809 /* Draw from the probability */ 00810 uni = rng_uniform()*sum; /* rng_uniform on [0,sum) */ 00811 for (k = 0; k < K; k++) 00812 if ((uni -= prob1[k]) <= 0) 00813 break; 00814 /* Update the label y */ 00815 past_y = y2[n][m]-1; /* old label. NB! in 0..K-1 */ 00816 y2[n][m] = k+1; /* new label as stored, for class in 1..K */ 00817 this_y = y2[n][m]-1; /* new label. NB! {this,past}_y both in 0..K-1 */ 00818 if (past_y == this_y) /* our state unchanged */ 00819 continue; /* no need to update neighbor counts, just go on */ 00820 num_pel_flip++; /* label has changed */ 00821 /* Update costs in neighborhood for the change in label y */ 00822 /* printf("[%d,%d] replaces %d -> %d\n", m, n, past_y, this_y); */ 00823 for (i = -NBHD_WIDTH; i <= NBHD_WIDTH; i++) 00824 if (ISLEGAL(n+i,N)) 00825 for (j = -NBHD_WIDTH; j <= NBHD_WIDTH; j++) 00826 if (ISLEGAL(m+j,M)) 00827 if ((i != 0) || (j != 0)) { /* skip the current site */ 00828 /* update the neighborhood quasi-counts */ 00829 d1 = sites2dist(dist,M,N,m,n,j,i); 00830 count3[past_y][n+i][m+j] -= d1; 00831 count3[this_y][n+i][m+j] += d1; 00832 } 00833 } 00834 /* printf("Efficiency = %f = %d/%d\n", 00835 (double) num_pel_flip/num_pel_active, 00836 (int) num_pel_flip, (int) num_pel_active); */ 00837 /* tidy up */ 00838 free(lprob1); 00839 free(prob1); 00840 return((double) num_pel_flip/num_pel_active); /* efficiency measure */ 00841 } 00842 00843 00844 /* 00845 * Core computational routine: iterate_clock 00846 * Performs one image sweep using running clocks and neighbor-quasi-counts. 00847 * It is most efficient when few pixels are changing. 00848 * 00849 * Like the other routines here, we keep track of the quasi-count array, 00850 * count3. This contains weighted distances, cumulative over all 00851 * neighbors of a given site, to neighbors of class 1,...,K. 00852 * We also keep track of kmax, the maximum-probability class number, 00853 * i.e. argmax_{k=1..K} Pr(y(s) == k | y(s'), s' ~ s) 00854 * This is in the range 1...K, or 0 if it is unknown. The latter is 00855 * true, for instance, if any neighbor's class assignment has 00856 * changed, which will make the previously computed probabilities 00857 * stale. 00858 * 00859 * Returns fraction of active pixels whose clock needed to be reset: 00860 * a measure of computational burden. This is *not* the same as the 00861 * fraction of pixels whose label changed, because sometimes clocks 00862 * need to be recomputed when neighbor classes change. 00863 */ 00864 static 00865 double 00866 iterate_clock( 00867 double **y2, /* in 1..K, or 0 or NaN */ 00868 Clock **clock2, 00869 Class **kmax2, 00870 Count ***count3, 00871 double ***lprob, 00872 int K, 00873 double T, 00874 int it_left, /* iterations remaining, for clock generation */ 00875 double **beta2, 00876 double *alpha, 00877 double *dist, /* can be NULL */ 00878 int M, 00879 int N) 00880 00881 { 00882 int m, n; /* counters */ 00883 int i, j; /* counters */ 00884 int k, l; /* counters */ 00885 double *prob1, *lprob1; /* prob's and log-probs, for one pel */ 00886 double lprob1_max; /* maximum log-probability at this pel */ 00887 const double lprob_max_init = -1E64; /* anything < log(minfloat) */ 00888 const double Tinv = 1.0/T; /* prefer to multiply */ 00889 double mrf_smooth; /* accumulates smoothness term of MRF */ 00890 Count d1; /* the current quasi-count */ 00891 double sum; /* normalization of probability mass function */ 00892 double uni, rng_uniform(); /* random numbers */ 00893 int this_y, past_y; /* integers for class labels */ 00894 int curr_class; /* class label, or sentinel value */ 00895 int num_pel_active = 0, num_pel_flip = 0; /* # active or modified pels */ 00896 int num_pel_expire = 0; /* # pels with expired clocks */ 00897 00898 /* Set up per-color bins to hold probabilities */ 00899 prob1 = (double *) calloc(K, sizeof(double)); 00900 lprob1 = (double *) calloc(K, sizeof(double)); 00901 mxAssert(prob1 && lprob1, "mrf_segment_wts: failed calloc(clock/lprob)"); 00902 /* Computation */ 00903 for (n = 0; n < N; n++) 00904 for (m = 0; m < M; m++) { 00905 /* skip inactive pixels */ 00906 if (!ActiveLabel(y2[n][m])) continue; 00907 num_pel_active++; /* count active pixels */ 00908 /* At each pel, there are three cases 00909 * 00910 * DESCRIPTION STATE ACTION 00911 * Clock Ticking clock > 1 decrement clock 00912 * Clock Expired clock = 1 draw different state 00913 * curr_class = choose new clock 00914 * <old state> reset neighbors' clocks 00915 * Clock Reset clock = 0 draw a state (needn't be different) 00916 * curr_class = -1 choose new clock 00917 * reset neighbors if state changed 00918 */ 00919 /* Case 1 above: If time remains, just decrement the clock */ 00920 if (clock2[n][m] > 1) { 00921 clock2[n][m]--; 00922 continue; 00923 } 00924 num_pel_flip++; /* need to sample, although label may not change */ 00925 if (clock2[n][m] == 1) num_pel_expire++; /* label must change */ 00926 /* ...otherwise, must re-evaluate probabilities and find a new state */ 00927 /* curr_class holds 00928 (1) class of this pel (0...K-1) if its clock expired 00929 (2) the sentinel value (-1) if its clock was reset */ 00930 curr_class = (clock2[n][m] == 0) ? -1 : (y2[n][m]-1); 00931 /* Find log-probabilities, and the largest log-probability */ 00932 for (lprob1_max = lprob_max_init, k = 0; k < K; k++) { 00933 /* find smoothness term if label #l is eventually chosen */ 00934 for (mrf_smooth = l = 0; l < K; l++) 00935 mrf_smooth += beta2[l][k] * count3[l][n][m]; /* wtd sum of counts */ 00936 /* three terms: class prior, local smoothness, data */ 00937 lprob1[k] = Tinv * (alpha[k] + mrf_smooth + lprob[k][n][m]); 00938 if (lprob1[k] > lprob1_max) { 00939 lprob1_max = lprob1[k]; 00940 kmax2[n][m] = k+1; /* succeeds for at least one k, in range 1..K */ 00941 } 00942 } 00943 /* compute probability normalization, scaled by exp(-lprob1_max) */ 00944 for (sum = k = 0; k < K; k++) { 00945 prob1[k] = exp(lprob1[k] - lprob1_max); /* rescale to max */ 00946 if (k != curr_class) /* skips summing curr_class if clock expired */ 00947 sum += prob1[k]; 00948 } 00949 /* Note: 0 <= prob1[k] <= 1; if curr_class == -1 then 1 <= sum <= K but 00950 * if curr_class >= 0, only know 0 <= sum <= K. If curr_class == -1, 00951 * prob1/sum is the pmf of the new class; in this case prob1 itself 00952 * is un-normalized. If curr_class >= 0, the last sentence is true 00953 * for prob1, excluding its curr_class entry, which is understood to 00954 * have zero probability. */ 00955 /* Draw from the probability */ 00956 uni = rng_uniform()*sum; /* rng_uniform on [0,sum) */ 00957 for (k = 0; k < K; k++) { 00958 if (k == curr_class) /* skips curr_class if clock expired, as above */ 00959 continue; 00960 if ((uni -= prob1[k]) <= 0) 00961 break; 00962 } 00963 /* end loop: note k != curr_class for sure */ 00964 /* Update the label y */ 00965 past_y = y2[n][m]-1; /* old label. NB! in 0..K-1 */ 00966 y2[n][m] = k+1; /* new label as stored, for class in 1..K */ 00967 this_y = y2[n][m]-1; /* new label. NB! {this,past}_y both in 0..K-1 */ 00968 /* Update clock */ 00969 if (past_y == this_y) { /* clock reset && our state unchanged */ 00970 /* must choose new clock because nbr changed => cost changed */ 00971 clock2[n][m] = (Clock) new_clock(prob1[this_y]/sum, it_left); 00972 /* however, need not reset neighbors' clocks: can continue */ 00973 continue; 00974 } 00975 /* Update costs in neighborhood for the change in label y */ 00976 /* printf("[%d,%d] replaces %d -> %d\n", m, n, past_y, this_y); */ 00977 for (i = -NBHD_WIDTH; i <= NBHD_WIDTH; i++) 00978 if (ISLEGAL(n+i,N)) 00979 for (j = -NBHD_WIDTH; j <= NBHD_WIDTH; j++) 00980 if (ISLEGAL(m+j,M)) 00981 if ((i != 0) || (j != 0)) { /* skip the current site */ 00982 /* update the neighborhood quasi-counts */ 00983 d1 = sites2dist(dist,M,N,m,n,j,i); 00984 count3[past_y][n+i][m+j] -= d1; /* -> range 0..K-1 */ 00985 count3[this_y][n+i][m+j] += d1; /* -> range 0..K-1 */ 00986 /* and reset the neighbors' clocks and max-k's */ 00987 if (d1 > 0) { 00988 clock2[n+i][m+j] = 0; /* old clock is invalid */ 00989 kmax2[n+i][m+j] = 0; /* old max-prob is stale */ 00990 } 00991 } 00992 /* Choose new clock for the current site (choose nbr clocks as we go) */ 00993 if (curr_class == -1) 00994 /* were not avoiding any class => sum as computed contains all probs */ 00995 clock2[n][m] = (Clock) new_clock(prob1[this_y]/sum, it_left); 00996 else 00997 /* were avoiding curr_class => sum excludes prob[curr_class] */ 00998 clock2[n][m] = (Clock) new_clock(prob1[this_y]/(sum+prob1[curr_class]), 00999 it_left); 01000 } 01001 #ifdef DEBUG 01002 printf("Efficiency = %f = %d/%d, %d expired\n", 01003 (double) num_pel_flip/num_pel_active, 01004 (int) num_pel_flip, (int) num_pel_active, num_pel_expire); 01005 #endif 01006 /* tidy up */ 01007 free(lprob1); 01008 free(prob1); 01009 return((double) num_pel_flip/num_pel_active); /* efficiency measure */ 01010 } 01011 01012 01013 01014 /********************************************************************* 01015 * OUTER LOOP 01016 * 01017 * Controls and initializes the iteration process 01018 * 01019 * Progresses through initialization then through various stages 01020 * of update which consist of sweeps through all pixels in the 01021 * image using the stored quasi-counts or clocks. 01022 *********************************************************************/ 01023 01024 /* stages determining which routine is used for labeling updates */ 01025 #define ITER_INIT 0 /* dummy state for startup */ 01026 #define ITER_COUNT 1 /* performing "count" updates */ 01027 #define ITER_CLOCK 2 /* performing "clock" updates */ 01028 #define ITER_0TEMP 3 /* considering final T=0 updates */ 01029 #define ITER_END 4 /* exit state */ 01030 01031 static 01032 control(double **yp2, /* result: labeling */ 01033 double *postprob,/* result: posterior probability, NULL ok */ 01034 Clock **clock2, /* place for per-label timers */ 01035 Class **kmax2, /* place for per-pixel most-likely-class */ 01036 Count ***count3, /* place for neighbor count */ 01037 int K, /* number of classes */ 01038 double *iters, /* iteration control */ 01039 double *T, /* temperature control */ 01040 double **beta2, /* smoothness */ 01041 double *alpha, /* per-class bias */ 01042 double *dist, /* inter-site distances */ 01043 double ***lprob3, /* log-probabilities of data */ 01044 int M, 01045 int N) /* size of input and result */ 01046 01047 { 01048 double flipfrac=0; /* how many pixels flipped in this iteration */ 01049 int stage = ITER_INIT; /* just initializing */ 01050 double iter_flipthresh; /* threshold controlling method using flipfrac */ 01051 int iter, iter_max; /* counter and target number of iters */ 01052 double T_iter; /* current temperature (never increases) */ 01053 double T_rat; /* temperature reduction ratio */ 01054 double T_step; /* temperature stepsize */ 01055 double T_thresh = -1; /* thresholded temperature ("clock" input) */ 01056 double T_0temp; /* zero if doing 0-temperature iterations */ 01057 int mismatch; /* number of mismatches in quasi-count check */ 01058 int count3_inited = 0; /* have we initialized count3 array? */ 01059 01060 /* assume RNG is already seeded */ 01061 /* set up symbolic names for inputs */ 01062 iter_max = iters[0]; /* target iter number */ 01063 iter_flipthresh = iters[1]; /* threshold on flipfrac for method change */ 01064 T_iter = T[0]; /* current temperature */ 01065 T_rat = T[1]; /* temperature drop per iter (multiplicative) */ 01066 T_step = T[2]; /* temp change until clock reset */ 01067 T_0temp= T[3]; /* T=0 iterations, or not */ 01068 /* done initializing: set stage up */ 01069 if (iter_max > 0) { 01070 /* some gibbs sampler iters will be done: start at COUNT or CLOCK */ 01071 if (iter_flipthresh < 1) 01072 stage = ITER_COUNT; /* typical: start with iterate_count */ 01073 else 01074 stage = ITER_CLOCK; /* start with iterate_clock */ 01075 } else { 01076 /* no g.s. iters: either 0 temperature iters, or none */ 01077 if (T_0temp == 0) 01078 stage = ITER_0TEMP; /* start with iterate_0temp */ 01079 else 01080 stage = ITER_END; /* no iters at all */ 01081 } 01082 /* initialize auxiliary variables if needed */ 01083 if (stage < ITER_END || postprob != NULL) { 01084 /* initialize neighbor count variables */ 01085 init_counts(count3, yp2, dist, K, M, N); 01086 count3_inited = 1; /* it's OK to check it later for consistency */ 01087 /* reset the per-site clocks and max-probability class */ 01088 init_clocks(clock2, kmax2, M, N); 01089 } 01090 /* Loop over several sweeps, using one method for each sweep */ 01091 for (iter = 0; stage < ITER_END; iter++) { 01092 /* if/else below guarantees iter < iter_max, else stage is 0TEMP */ 01093 if (iter < iter_max) { 01094 T_iter *= T_rat; /* ordinary annealing: lower the present temp'ture */ 01095 } else { 01096 stage = ITER_0TEMP; /* check for T=0 updates, and possibly leave */ 01097 T_iter = 0; /* unused at this stage, but maintain it */ 01098 } 01099 #ifdef DEBUG 01100 mexPrintf("I = %03d S%d (%.6f) T = %0.3f\n", 01101 iter, stage, flipfrac, T_iter); 01102 #endif 01103 /* perform one sweep, depending on selected method */ 01104 if (stage == ITER_COUNT) { 01105 /* perform a "count" update */ 01106 flipfrac = iterate_count(yp2, count3, lprob3, 01107 K, T_iter, beta2, alpha, dist, M, N); 01108 if (isnan(flipfrac)) flipfrac = 0; /* 0/0 case -> 0 */ 01109 /* switch update method if few labels change */ 01110 if (flipfrac < iter_flipthresh) stage = ITER_CLOCK; 01111 } else if (stage == ITER_CLOCK) { 01112 /* refresh on first clock pass, or if temp has changed too much */ 01113 if (T_thresh < 0 || T_iter < T_thresh*T_step) { 01114 /* printf("resetting clocks\n"); */ 01115 reset_clocks(clock2, kmax2, yp2, iter_max-iter, M, N); 01116 T_thresh = T_iter; /* reset temperature threshold also */ 01117 } 01118 /* perform a "clock" update */ 01119 flipfrac = iterate_clock(yp2, clock2, kmax2, count3, lprob3, 01120 K, T_thresh, iter_max-iter, 01121 beta2, alpha, dist, M, N); 01122 if (isnan(flipfrac)) flipfrac = 0; /* 0/0 case -> 0 */ 01123 } else { 01124 /* check to perform a zero-temperature update */ 01125 if (T_0temp != 0) { 01126 stage = ITER_END; /* no T=0 updates, break out of the loop */ 01127 continue; 01128 } 01129 flipfrac = iterate_0temp(yp2, count3, kmax2, lprob3, 01130 K, beta2, alpha, dist, M, N); 01131 if (isnan(flipfrac)) flipfrac = 0; /* 0/0 case -> 0 */ 01132 if (flipfrac == 0) 01133 stage = ITER_END; /* no more changes -> exit */ 01134 } /* if stage, else */ 01135 } /* for iter */ 01136 01137 if (postprob != NULL) 01138 /* posterior was desired: easy to find since we have count3 */ 01139 *postprob = find_posterior(yp2, count3, lprob3, K, beta2, alpha, M, N); 01140 /* consistency check for robustness */ 01141 if (count3_inited) 01142 if ((mismatch = check_counts(K, count3, yp2, dist, M, N)) != 0) { 01143 char errstr[200]; 01144 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01145 "%s: Internal error: " 01146 "%d of %d counts inconsistent", 01147 progname, mismatch, K*M*N), errstr)); 01148 } 01149 } 01150 01151 01152 /********************************************************************* 01153 * GATEWAY ROUTINE 01154 *********************************************************************/ 01155 #ifdef StaticP /* undefined under mex */ 01156 StaticP 01157 #endif 01158 void 01159 mexFunction( 01160 int nlhs, 01161 mxArray *plhs[], 01162 int nrhs, 01163 const mxArray *prhs[]) 01164 { 01165 int M, N, K; /* hold numeric parameters */ 01166 int i, k; /* counters */ 01167 int lprob_input_3d; /* was log-prob input one 3d matrix or not */ 01168 double *postprob; /* posterior probability, or NULL if unwanted */ 01169 double ***lprob3; /* matrix of data log-probabilities (3d) */ 01170 double **yp2; /* matrix of labels (2d) */ 01171 Count ***count3; /* matrix of neighbor quasi-counts (3d) */ 01172 Count *count; /* pointer to data referred to by above ptrs */ 01173 Clock **clock2; /* matrix of label clocks (2d) */ 01174 Clock *clock; /* pointer to data referred to by above ptrs */ 01175 Class **kmax2; /* matrix of most probable classes (2d) */ 01176 Class *kmax; /* pointer to data referred to by above ptrs */ 01177 double *iters; /* iteration input */ 01178 int rng_seed; /* the rng seed that was used */ 01179 char errstr[256]; 01180 01181 /* Hook for introspection (function signature, docstring) */ 01182 if (nrhs < 0) { 01183 plhs[0] = mxt_PackSignature((mxt_Signature) (-nrhs), 01184 NARGIN_MIN, NARGIN_MAX, 01185 NARGOUT_MIN, NARGOUT_MAX, 01186 in_names, in_specs, out_names, docstring); 01187 return; 01188 } 01189 /* 01190 * check args 01191 */ 01192 if ((nrhs < NARGIN_MIN) || (nrhs > NARGIN_MAX)) 01193 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01194 "%s: Expect %d <= input args <= %d", 01195 progname, NARGIN_MIN, NARGIN_MAX), errstr)); 01196 if ((nlhs < NARGOUT_MIN) || (nlhs > NARGOUT_MAX)) 01197 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01198 "%s: Expect %d <= output args <= %d", 01199 progname, NARGOUT_MIN, NARGOUT_MAX), errstr)); 01200 mexargparse(nrhs, prhs, in_names, in_specs, NULL, progname); 01201 01202 /* find how big the inputs are */ 01203 lprob_input_3d = (nrhs - ARG_lprob == 1); // single 3d logprob input? 01204 if (!lprob_input_3d) { 01205 K = nrhs - ARG_lprob; /* number of classes = number of spare inputs */ 01206 M = mxGetM(prhs[ARG_lprob]); 01207 N = mxGetN(prhs[ARG_lprob]); 01208 } else { 01209 if (mxGetNumberOfDimensions(prhs[ARG_lprob]) != 3) 01210 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01211 "%s: A single lprob must be 3-D", 01212 progname), errstr)); 01213 M = mxGetDimensions(prhs[ARG_lprob])[0]; 01214 N = mxGetDimensions(prhs[ARG_lprob])[1]; 01215 K = mxGetDimensions(prhs[ARG_lprob])[2]; 01216 } 01217 /* crude check -- will give a more informative message than later ones */ 01218 if (K > ClassMax || K < 2) 01219 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01220 "%s: Expect %d <= K <= %d", 01221 progname, 2, ClassMax), errstr)); 01222 01223 start_sizechecking(); 01224 /* beta */ 01225 sizeinit(prhs[ARG_beta]); 01226 sizeisMN(1, 1); /* beta = [1,1] */ 01227 sizeisMN(K, K); /* beta = [K,K] */ 01228 sizecheck_msg(progname, in_names, ARG_beta); 01229 /* alpha */ 01230 sizeinit(prhs[ARG_alpha]); 01231 sizeisMN(0, 0); /* alpha = [] */ 01232 sizeisMN(1, K); /* alpha = 1xK or Kx1 */ 01233 sizecheck_msg(progname, in_names, ARG_alpha); 01234 /* dist */ 01235 sizeinit(prhs[ARG_dist]); 01236 sizeisMN(0, 0); /* dist = [] (2d) */ 01237 sizeis3(0, 0, 0); /* dist = [] (3d) */ 01238 sizeisMN(NBHD_NUM_2*M, N); /* allow flattened dist for now */ 01239 sizeis3(NBHD_NUM_2, M, N); /* dist = NBR x M x N */ 01240 sizecheck_msg(progname, in_names, ARG_dist); 01241 /* check sizes of log-probability matrices */ 01242 if (!lprob_input_3d) /* i.e., if supplied individually */ 01243 for (k = 1; k < K; k++) { 01244 sizeinit(prhs[ARG_lprob]); 01245 sizeagree(prhs[ARG_lprob+k]); /* size(cost) == size(x) */ 01246 sizecheck_msg(progname, in_names, ARG_lprob); 01247 } 01248 /* check size of y */ 01249 sizeinit(prhs[ARG_y]); 01250 sizeisMN(0, 0); /* y = [] */ 01251 sizeisMN(M, N); /* y = [M,N] */ 01252 sizecheck_msg(progname, in_names, ARG_y); 01253 01254 /* 01255 * create space for output 01256 */ 01257 01258 /* make the space */ 01259 plhs[ARG_yp] = mxCreateDoubleMatrix(M, N, mxREAL); 01260 mxAssert(plhs[ARG_yp], "mrf_segment_wts: failed mxCreate (output y)"); 01261 setrange(plhs[ARG_yp], 0.0, 0.0); /* disables scaling */ 01262 yp2 = mxt_make_matrix2(plhs[ARG_yp], -1, -1, 0.0); /* 2d indexing into yp */ 01263 if (nlhs > ARG_post) { 01264 plhs[ARG_post] = mxCreateDoubleMatrix(1, 1, mxREAL); 01265 mxAssert(plhs[ARG_post], "mrf_segment_wts: failed mxCreate (output post)"); 01266 setrange(plhs[ARG_post], 0.0, 0.0); /* disables scaling */ 01267 postprob = mxGetPr(plhs[ARG_post]); 01268 } else { 01269 postprob = NULL; /* sentinel for not wanted */ 01270 } 01271 01272 /* 01273 * Establish index arrays for nonstandard matrices 01274 */ 01275 /* 1: set up each of K probability maps for 2d indexing */ 01276 if (lprob_input_3d) { 01277 /* this is freed with one call to mxFree */ 01278 lprob3 = mxt_matrix3_index(mxGetPr(prhs[ARG_lprob]), M, N, K); 01279 mxAssert(lprob3, "mrf_segment_wts: failed calloc (lprob3)"); 01280 } else { 01281 lprob3 = (double ***) calloc(K, sizeof(double **)); /* submatrix ptrs */ 01282 mxAssert(lprob3, "mrf_segment_wts: failed calloc (lprob3)"); 01283 for (k = 0; k < K; k++) { 01284 lprob3[k] = mxt_make_matrix2(prhs[ARG_lprob + k], -1, -1, 0.0); 01285 mxAssert(lprob3[k], "mrf_segment_wts: failed calloc (lprob3[k])"); 01286 } 01287 } 01288 /* 2: set up count as a 3d matrix */ 01289 /* (cannot use mxt_make_matrix2, which is for double) */ 01290 count = (Count *) calloc(K*M*N, sizeof(Count)); /* all counts */ 01291 count3 = (Count ***) calloc(K, sizeof(Count **)); /* ptrs to submat's */ 01292 mxAssert(count && count3, "mrf_segment_wts: failed calloc (count)"); 01293 for (k = 0; k < K; k++) { 01294 count3[k] = (Count **) calloc(N, sizeof(Count *)); /* column indexes */ 01295 mxAssert(count3[k], "mrf_segment_wts: failed calloc (count3[k])"); 01296 for (i = 0; i < N; i++) 01297 count3[k][i] = count + k*(M*N) + i*M; /* set up col ptrs */ 01298 } 01299 /* 3: set up clock as a 2d matrix (again, not of doubles) */ 01300 clock = (Clock *) calloc(N*M, sizeof(Clock)); /* all clocks */ 01301 clock2 = (Clock **) calloc(N, sizeof(Clock *)); /* 2d indexes */ 01302 mxAssert(clock && clock2, "mrf_segment_wts: failed calloc (clock)"); 01303 for (i = 0; i < N; i++) 01304 clock2[i] = clock + i*M; /* set up column pointers */ 01305 01306 /* 4: set up kmax as a 2d matrix (again, not of doubles) */ 01307 kmax = (Class *) calloc(N*M, sizeof(Class)); /* all clocks */ 01308 kmax2 = (Class **) calloc(N, sizeof(Class *)); /* 2d indexes */ 01309 mxAssert(kmax && kmax2, "mrf_segment_wts: failed calloc (clock)"); 01310 for (i = 0; i < N; i++) 01311 kmax2[i] = kmax + i*M; /* set up column pointers */ 01312 01313 /* 01314 * Initialize yp from y or lprob 01315 */ 01316 /* propagate y -> yp, or initialize yp from lprob */ 01317 if (mxGetN(prhs[ARG_y]) == 0) { 01318 /* initialize yp from log-probabilities */ 01319 per_pixel_map_estimate(yp2, lprob3, 01320 mxt_make_vector(prhs[ARG_alpha], K, 01321 (double *) NULL, 0), 01322 M, N, K); 01323 } else { 01324 /* first, make sure IC is valid */ 01325 if (!check_labels(K, mxGetPr(prhs[ARG_y]), M*N)) 01326 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01327 "%s: Classes are 0, NaN, or 1..%d", 01328 progname, K), errstr)); 01329 /* then copy IC to new labeling area */ 01330 memcpy((void *) &(yp2[0][0]), 01331 (void *) mxGetPr(prhs[ARG_y]), 01332 M * N * sizeof(double)); 01333 /* propagate any NaN's in prob-maps through to the labeling */ 01334 find_inactive_labels(yp2, lprob3, M, N, K); 01335 } 01336 01337 /* 01338 * Set up rng seed 01339 */ 01340 iters = mxt_make_vector(prhs[ARG_iters], 01341 Iters_count, Default_iters, Default_iters_count); 01342 /* note, if below is 0, no seed was given */ 01343 rng_seed = (int) rint(2147483648.0 * fmod(iters[0], 1.0)); 01344 /* initialize the RNG in one of two ways */ 01345 if (rng_seed == 0) 01346 rng_seed = rng_init_state(); /* varies from run to run */ 01347 else 01348 rng_init_state_seeded(rng_seed); /* deterministic */ 01349 01350 /* 01351 * do the computation 01352 */ 01353 /* enter main loop */ 01354 control(yp2, 01355 postprob, /* posterior output, if desired */ 01356 clock2, /* pointer structure set up above */ 01357 kmax2, /* pointer structure set up above */ 01358 count3, /* pointer structure set up above */ 01359 K, 01360 iters, /* found above */ 01361 mxt_make_vector(prhs[ARG_T], T_count, Default_T, Default_T_count), 01362 mxt_make_matrix1(prhs[ARG_beta], K, K, 1.0), 01363 mxt_make_vector(prhs[ARG_alpha], K, (double *) NULL, 0), 01364 mxGetNumberOfElements(prhs[ARG_dist]) == 0 ? 01365 ((double * ) NULL) : 01366 mxGetPr(prhs[ARG_dist]), 01367 lprob3, /* pointer structure set up above */ 01368 M, N); 01369 /* ensure classes are 1..K, 0, or NaN */ 01370 if (!check_labels(K, &(yp2[0][0]), M*N)) 01371 mexErrMsgTxt((snprintf(errstr, sizeof(errstr), 01372 "%s: Internal error: labels out of bounds", 01373 progname), errstr)); 01374 /* free the temporary space up */ 01375 mxFree(yp2); /* pointer vector allocated with mxt_mm2 */ 01376 free(kmax); 01377 free(kmax2); 01378 free(clock); 01379 free(clock2); 01380 free(count); 01381 for (k = 0; k < K; k++) 01382 free(count3[k]); /* allocated with calloc */ 01383 free(count3); 01384 if (lprob_input_3d) { 01385 mxFree(lprob3); /* allocated with mxt_matrix3_index */ 01386 } else { 01387 for (k = 0; k < K; k++) 01388 mxFree(lprob3[k]); /* allocated with mxt_mm2 */ 01389 free(lprob3); /* allocated with calloc */ 01390 } 01391 } 01392 01393 01394 01395 /* Hook for generic tail matter */ 01396 #ifdef MEX2C_TAIL_HOOK 01397 #include "mex2c_tail.h" 01398 #endif 01399