mean_shift.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /* PURPOSE: Develop the image segments */
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <float.h>
  5. #include <math.h>
  6. #include <time.h>
  7. #include <grass/gis.h>
  8. #include <grass/glocale.h>
  9. #include <grass/raster.h>
  10. #include <grass/segment.h> /* segmentation library */
  11. #include "pavl.h"
  12. #include "iseg.h"
  13. int remove_small_clumps(struct globals *globals);
  14. /* standard gauss function:
  15. * a * exp(-(x - m)^2 / (2 * stddev^2)
  16. * a is not needed because the sum of weights is calculated for each
  17. * sampling window
  18. * (x - m)^2 is the squared difference = diff2
  19. * stddev^2 is the variance
  20. * this code can be further simplified, e.g. by supplying 2 * var instead
  21. * of var
  22. *
  23. * the standard deviation is the bandwidth
  24. * */
  25. static double gauss_kernel(double diff2, double var)
  26. {
  27. return exp(-diff2 / (2 * var));
  28. }
  29. int mean_shift(struct globals *globals)
  30. {
  31. int row, col, t, n;
  32. int mwrow, mwrow1, mwrow2, mwnrows, mwcol, mwcol1, mwcol2, mwncols, radiusc;
  33. double hspat, hspec, hspat2, hspec2, sigmaspat2, sigmaspec2;
  34. double hspecad, hspecad2;
  35. double ka2;
  36. double w, wsum;
  37. LARGEINT n_changes;
  38. double alpha2, maxdiff2;
  39. struct ngbr_stats Rin, Rout, Rn;
  40. double diff, diff2;
  41. SEGMENT *seg_tmp;
  42. double mindiff, mindiffzero, mindiffavg, mindiffzeroavg;
  43. double avgdiff, avgdiffavg;
  44. LARGEINT nvalid, count;
  45. int do_gauss = 0, do_adaptive, do_progressive;
  46. Rin.mean = G_malloc(globals->datasize);
  47. Rout.mean = G_malloc(globals->datasize);
  48. Rn.mean = G_malloc(globals->datasize);
  49. alpha2 = globals->alpha * globals->alpha;
  50. do_adaptive = globals->ms_adaptive;
  51. do_progressive = globals->ms_progressive;
  52. globals->candidate_count = 0;
  53. flag_clear_all(globals->candidate_flag);
  54. /* Set candidate flag to true/1 for all non-NULL cells */
  55. for (row = globals->row_min; row < globals->row_max; row++) {
  56. for (col = globals->col_min; col < globals->col_max; col++) {
  57. if (!(FLAG_GET(globals->null_flag, row, col))) {
  58. FLAG_SET(globals->candidate_flag, row, col);
  59. globals->candidate_count++;
  60. }
  61. }
  62. }
  63. /* spatial bandwidth */
  64. hspat = globals->hs;
  65. if (hspat < 1) {
  66. hspat = 1.5;
  67. globals->hs = hspat;
  68. }
  69. hspat2 = hspat * hspat;
  70. sigmaspat2 = hspat2 / 9.;
  71. radiusc = hspat; /* radius in cells truncated to integer */
  72. mwnrows = mwncols = radiusc * 2 + 1;
  73. /* estimate spectral bandwidth for given spatial bandwidth */
  74. mindiffavg = mindiffzeroavg = 0;
  75. avgdiffavg = 0;
  76. nvalid = 0;
  77. G_message(_("Estimating spectral bandwidth for spatial bandwidth %g..."), hspat);
  78. G_percent_reset();
  79. for (row = globals->row_min; row < globals->row_max; row++) {
  80. G_percent(row - globals->row_min,
  81. globals->row_max - globals->row_min, 4);
  82. mwrow1 = row - radiusc;
  83. mwrow2 = mwrow1 + mwnrows;
  84. if (mwrow1 < globals->row_min)
  85. mwrow1 = globals->row_min;
  86. if (mwrow2 > globals->row_max)
  87. mwrow2 = globals->row_max;
  88. for (col = globals->col_min; col < globals->col_max; col++) {
  89. if ((FLAG_GET(globals->null_flag, row, col)))
  90. continue;
  91. /* get current band values */
  92. Segment_get(globals->bands_in, (void *)Rin.mean,
  93. row, col);
  94. mwcol1 = col - radiusc;
  95. mwcol2 = mwcol1 + mwncols;
  96. if (mwcol1 < globals->col_min)
  97. mwcol1 = globals->col_min;
  98. if (mwcol2 > globals->col_max)
  99. mwcol2 = globals->col_max;
  100. /* get minimum spectral distance for this cell */
  101. count = 0;
  102. mindiff = globals->max_diff;
  103. mindiffzero = globals->max_diff;
  104. avgdiff = 0;
  105. for (mwrow = mwrow1; mwrow < mwrow2; mwrow++) {
  106. for (mwcol = mwcol1; mwcol < mwcol2; mwcol++) {
  107. if ((FLAG_GET(globals->null_flag, mwrow, mwcol)))
  108. continue;
  109. if (mwrow == row && mwcol == col)
  110. continue;
  111. diff = mwrow - row;
  112. diff2 = diff * diff;
  113. diff = mwcol - col;
  114. diff2 += diff * diff;
  115. if (diff2 <= hspat2) {
  116. Segment_get(globals->bands_in, (void *)Rn.mean,
  117. mwrow, mwcol);
  118. /* get spectral distance */
  119. diff2 = (globals->calculate_similarity)(&Rin, &Rn, globals);
  120. if (mindiff > diff2)
  121. mindiff = diff2;
  122. if (mindiffzero > diff2 && diff2 > 0)
  123. mindiffzero = diff2;
  124. avgdiff += sqrt(diff2);
  125. count++;
  126. }
  127. }
  128. }
  129. if (count) {
  130. nvalid++;
  131. if (mindiff > 0)
  132. mindiffavg += sqrt(mindiff);
  133. mindiffzeroavg += sqrt(mindiffzero);
  134. if (avgdiff > 0)
  135. avgdiffavg += avgdiff / count;
  136. }
  137. }
  138. }
  139. G_percent(1, 1, 1);
  140. if (!nvalid) {
  141. G_fatal_error(_("Empty moving windows"));
  142. }
  143. mindiffavg /= nvalid;
  144. mindiffzeroavg /= nvalid;
  145. avgdiffavg /= nvalid;
  146. G_debug(1, "Average minimum difference to neighbours: %g", mindiffavg);
  147. G_debug(1, "Average minimum difference excl zero to neighbours: %g", mindiffzeroavg);
  148. G_debug(1, "Average average difference to neighbours: %g", avgdiffavg);
  149. /* use avgdiffavg as hspec for adaptive bandwidth */
  150. hspec = globals->hr;
  151. if (hspec < 0 || hspec >= 1) {
  152. hspec = sqrt(avgdiffavg / 10.0);
  153. hspec = avgdiffavg;
  154. hspec = mindiffzeroavg;
  155. if (do_progressive)
  156. G_message(_("Initial range bandwidth: %g"), hspec);
  157. else
  158. G_message(_("Estimated range bandwidth: %g"), hspec);
  159. globals->hr = hspec;
  160. }
  161. else {
  162. G_message(_("Estimated range bandwidth: %g"), mindiffzeroavg);
  163. }
  164. if (do_adaptive) {
  165. /* bandwidth is now standard deviation for adaptive bandwidth
  166. * using a gaussian function with range bandwidth used as
  167. * bandwidth for the gaussian function
  168. * the aim is to produce similar but improved results with
  169. * adaptive bandwidth
  170. * thus increase bandwidth */
  171. hspec = sqrt(hspec);
  172. }
  173. hspec2 = hspec * hspec;
  174. sigmaspec2 = hspec2 / 9.;
  175. if (!do_progressive) {
  176. G_message(_("Spatial bandwidth: %g"), hspat);
  177. G_message(_("Range bandwidth: %g"), hspec);
  178. }
  179. G_debug(4, "Starting to process %"PRI_LONG" candidate cells",
  180. globals->candidate_count);
  181. t = 0;
  182. n_changes = 1;
  183. maxdiff2 = 0;
  184. while (t < globals->end_t && n_changes > 0) {
  185. G_message(_("Processing pass %d..."), ++t);
  186. /* cells within an object should become more similar with each pass
  187. * therefore the spectral bandwidth could be decreased
  188. * and the spatial bandwidth could be increased */
  189. /* spatial bandwidth: double the area covered by the moving window
  190. * area = M_PI * hspat * hspat
  191. * new hspat = sqrt(M_PI * hspat * hspat * 2 / M_PI)
  192. * no good, too large increases */
  193. if (do_progressive) {
  194. if (t > 1)
  195. hspat *= 1.1;
  196. hspat2 = hspat * hspat;
  197. sigmaspat2 = hspat2 / 9.;
  198. radiusc = hspat; /* radius in cells truncated to integer */
  199. mwnrows = mwncols = radiusc * 2 + 1;
  200. /* spectral bandwidth: reduce by 0.7 */
  201. if (t > 1)
  202. hspec *= 0.9;
  203. hspec2 = hspec * hspec;
  204. sigmaspec2 = hspec2 / 9.;
  205. G_verbose_message(_("Spatial bandwidth: %g"), hspat);
  206. G_verbose_message(_("Range bandwidth: %g"), hspec);
  207. }
  208. n_changes = 0;
  209. maxdiff2 = 0;
  210. /* swap input and output */
  211. seg_tmp = globals->bands_in;
  212. globals->bands_in = globals->bands_out;
  213. globals->bands_out = seg_tmp;
  214. /*process candidate cells */
  215. G_percent_reset();
  216. for (row = globals->row_min; row < globals->row_max; row++) {
  217. G_percent(row - globals->row_min,
  218. globals->row_max - globals->row_min, 4);
  219. mwrow1 = row - radiusc;
  220. mwrow2 = mwrow1 + mwnrows;
  221. if (mwrow1 < globals->row_min)
  222. mwrow1 = globals->row_min;
  223. if (mwrow2 > globals->row_max)
  224. mwrow2 = globals->row_max;
  225. for (col = globals->col_min; col < globals->col_max; col++) {
  226. if ((FLAG_GET(globals->null_flag, row, col)))
  227. continue;
  228. /* get current band values */
  229. Segment_get(globals->bands_in, (void *)Rin.mean,
  230. row, col);
  231. /* init output */
  232. for (n = 0; n < globals->nbands; n++)
  233. Rout.mean[n] = 0.;
  234. mwcol1 = col - radiusc;
  235. mwcol2 = mwcol1 + mwncols;
  236. if (mwcol1 < globals->col_min)
  237. mwcol1 = globals->col_min;
  238. if (mwcol2 > globals->col_max)
  239. mwcol2 = globals->col_max;
  240. hspecad2 = hspec2;
  241. if (do_adaptive) {
  242. /* adapt initial range bandwidth */
  243. ka2 = hspec2; /* OTB: conductance parameter */
  244. avgdiff = 0;
  245. count = 0;
  246. for (mwrow = mwrow1; mwrow < mwrow2; mwrow++) {
  247. for (mwcol = mwcol1; mwcol < mwcol2; mwcol++) {
  248. if ((FLAG_GET(globals->null_flag, mwrow, mwcol)))
  249. continue;
  250. if (mwrow == row && mwcol == col)
  251. continue;
  252. diff = mwrow - row;
  253. diff2 = diff * diff;
  254. diff = mwcol - col;
  255. diff2 += diff * diff;
  256. if (diff2 <= hspat2) {
  257. Segment_get(globals->bands_in, (void *)Rn.mean,
  258. mwrow, mwcol);
  259. /* get spectral distance */
  260. diff2 = (globals->calculate_similarity)(&Rin, &Rn, globals);
  261. avgdiff += sqrt(diff2);
  262. count++;
  263. }
  264. }
  265. }
  266. hspecad2 = 0;
  267. if (avgdiff > 0) {
  268. avgdiff /= count;
  269. hspecad = hspec;
  270. /* OTB-like, contrast enhancing */
  271. hspecad = exp(-avgdiff * avgdiff / (2 * ka2)) * avgdiff;
  272. /* preference for large regions, from Perona Malik 1990
  273. * if the settings are right, it could be used to reduce noise */
  274. /* hspecad = 1 / (1 + (avgdiff * avgdiff / (2 * hspec2))); */
  275. hspecad2 = hspecad * hspecad;
  276. G_debug(1, "avg spectral diff: %g", avgdiff);
  277. G_debug(1, "initial hspec2: %g", hspec2);
  278. G_debug(1, "adapted hspec2: %g", hspecad2);
  279. }
  280. }
  281. /* actual mean shift */
  282. wsum = 0;
  283. for (mwrow = mwrow1; mwrow < mwrow2; mwrow++) {
  284. for (mwcol = mwcol1; mwcol < mwcol2; mwcol++) {
  285. if ((FLAG_GET(globals->null_flag, mwrow, mwcol)))
  286. continue;
  287. diff = mwrow - row;
  288. diff2 = diff * diff;
  289. diff = mwcol - col;
  290. diff2 += diff * diff;
  291. if (diff2 <= hspat2) {
  292. w = 1;
  293. if (do_gauss)
  294. w = gauss_kernel(diff2, sigmaspat2);
  295. Segment_get(globals->bands_in, (void *)Rn.mean,
  296. mwrow, mwcol);
  297. /* check spectral distance */
  298. diff2 = (globals->calculate_similarity)(&Rin, &Rn, globals);
  299. if (diff2 <= hspecad2) {
  300. if (do_gauss)
  301. w *= gauss_kernel(diff2, sigmaspec2);
  302. wsum += w;
  303. for (n = 0; n < globals->nbands; n++)
  304. Rout.mean[n] += w * Rn.mean[n];
  305. }
  306. }
  307. }
  308. }
  309. if (wsum > 0) {
  310. for (n = 0; n < globals->nbands; n++)
  311. Rout.mean[n] /= wsum;
  312. }
  313. else {
  314. for (n = 0; n < globals->nbands; n++)
  315. Rout.mean[n] = Rin.mean[n];
  316. }
  317. /* put new band values */
  318. Segment_put(globals->bands_out, (void *)Rout.mean,
  319. row, col);
  320. /* if the squared difference between old and new band values
  321. * is larger than alpha2, then increase n_changes */
  322. diff2 = (globals->calculate_similarity)(&Rin, &Rout, globals);
  323. if (diff2 > alpha2)
  324. n_changes++;
  325. if (maxdiff2 < diff2)
  326. maxdiff2 = diff2;
  327. }
  328. }
  329. G_percent(1, 1, 1);
  330. G_message(_("Changes > threshold: %"PRI_LONG", largest change: %g"), n_changes, sqrt(maxdiff2));
  331. }
  332. if (n_changes > 1)
  333. G_message(_("Mean shift stopped at %d due to reaching max iteration limit, more changes may be possible"), t);
  334. else
  335. G_message(_("Mean shift converged after %d iterations"), t);
  336. /* identify connected components */
  337. cluster_bands(globals);
  338. /* remove small regions */
  339. remove_small_clumps(globals);
  340. return TRUE;
  341. }
  342. static int cmp_rc(const void *first, const void *second)
  343. {
  344. struct rc *a = (struct rc *)first, *b = (struct rc *)second;
  345. if (a->row == b->row)
  346. return (a->col - b->col);
  347. return (a->row - b->row);
  348. }
  349. static void free_item(void *p)
  350. {
  351. G_free(p);
  352. }
  353. static int find_best_neighbour(struct globals *globals, int row, int col,
  354. int this_id, struct NB_TREE *nbtree,
  355. int *reg_size, struct ngbr_stats **Rbest,
  356. int *best_n_row, int *best_n_col)
  357. {
  358. int rown, coln, n, count;
  359. int neighbors[8][2];
  360. struct rc next, ngbr_rc, *pngbr_rc;
  361. struct rclist rilist;
  362. int no_check;
  363. int ngbr_id;
  364. struct pavl_table *visited;
  365. struct ngbr_stats Ri, Rk, *Rfound;
  366. double sim, best_sim;
  367. int best_n_id;
  368. int have_Ri;
  369. Ri.mean = G_malloc(globals->datasize);
  370. Rk.mean = G_malloc(globals->datasize);
  371. nbtree_clear(nbtree);
  372. FLAG_UNSET(globals->candidate_flag, row, col);
  373. visited = pavl_create(cmp_rc, NULL);
  374. ngbr_rc.row = row;
  375. ngbr_rc.col = col;
  376. pngbr_rc = G_malloc(sizeof(struct rc));
  377. *pngbr_rc = ngbr_rc;
  378. pavl_insert(visited, pngbr_rc);
  379. pngbr_rc = NULL;
  380. /* breadth-first search */
  381. next.row = row;
  382. next.col = col;
  383. rclist_init(&rilist);
  384. count = 1;
  385. best_n_id = -1;
  386. best_sim = 2;
  387. do {
  388. have_Ri = 0;
  389. globals->find_neighbors(next.row, next.col, neighbors);
  390. n = globals->nn - 1;
  391. do {
  392. rown = neighbors[n][0];
  393. coln = neighbors[n][1];
  394. no_check = 0;
  395. if (rown < globals->row_min || rown >= globals->row_max ||
  396. coln < globals->col_min || coln >= globals->col_max)
  397. no_check = 1;
  398. if (!no_check && (FLAG_GET(globals->null_flag, rown, coln)))
  399. no_check = 1;
  400. ngbr_rc.row = rown;
  401. ngbr_rc.col = coln;
  402. if (pngbr_rc == NULL)
  403. pngbr_rc = G_malloc(sizeof(struct rc));
  404. *pngbr_rc = ngbr_rc;
  405. if (!no_check && pavl_insert(visited, pngbr_rc) == NULL) {
  406. pngbr_rc = NULL;
  407. /* get neighbor ID */
  408. Segment_get(&globals->rid_seg, (void *) &ngbr_id, rown, coln);
  409. /* same neighbour */
  410. if (ngbr_id == this_id) {
  411. count++;
  412. rclist_add(&rilist, rown, coln);
  413. FLAG_UNSET(globals->candidate_flag, rown, coln);
  414. }
  415. else { /* different neighbour */
  416. /* compare to this cell next.row, next.col */
  417. if (!have_Ri) {
  418. Segment_get(globals->bands_out, (void *) Ri.mean, next.row, next.col);
  419. have_Ri = 1;
  420. }
  421. Segment_get(globals->bands_out, (void *) Rk.mean, rown, coln);
  422. sim = globals->calculate_similarity(&Ri, &Rk, globals);
  423. if (best_sim > sim) {
  424. best_sim = sim;
  425. best_n_id = ngbr_id;
  426. *best_n_row = rown;
  427. *best_n_col = coln;
  428. }
  429. /* find in neighbor tree */
  430. Rk.id = ngbr_id;
  431. if ((Rfound = nbtree_find(nbtree, &Rk))) {
  432. Rfound->count++;
  433. if (*Rbest && (*Rbest)->count < Rfound->count)
  434. *Rbest = Rfound;
  435. }
  436. else {
  437. Rk.count = 1;
  438. Rk.row = rown;
  439. Rk.col = coln;
  440. nbtree_insert(nbtree, &Rk);
  441. if (!(*Rbest))
  442. *Rbest = nbtree_find(nbtree, &Rk);
  443. }
  444. }
  445. }
  446. } while (n--); /* end do loop - next neighbor */
  447. } while (rclist_drop(&rilist, &next)); /* while there are cells to check */
  448. rclist_destroy(&rilist);
  449. if (pngbr_rc)
  450. G_free(pngbr_rc);
  451. pavl_destroy(visited, free_item);
  452. G_free(Ri.mean);
  453. G_free(Rk.mean);
  454. *reg_size = count;
  455. return best_n_id;
  456. }
  457. static int check_reg_size(struct globals *globals, int minsize, int row, int col)
  458. {
  459. int rown, coln, n;
  460. int neighbors[8][2];
  461. int this_id;
  462. int ngbr_id;
  463. LARGEINT reg_size;
  464. struct pavl_table *visited;
  465. struct rc next, ngbr_rc, *pngbr_rc;
  466. struct rclist rilist;
  467. int no_check;
  468. if (!(FLAG_GET(globals->candidate_flag, row, col)))
  469. return minsize;
  470. FLAG_UNSET(globals->candidate_flag, row, col);
  471. visited = pavl_create(cmp_rc, NULL);
  472. ngbr_rc.row = row;
  473. ngbr_rc.col = col;
  474. pngbr_rc = G_malloc(sizeof(struct rc));
  475. *pngbr_rc = ngbr_rc;
  476. pavl_insert(visited, pngbr_rc);
  477. pngbr_rc = NULL;
  478. /* get this ID */
  479. Segment_get(&globals->rid_seg, (void *) &this_id, row, col);
  480. /* breadth-first search */
  481. next.row = row;
  482. next.col = col;
  483. rclist_init(&rilist);
  484. reg_size = 1;
  485. do {
  486. globals->find_neighbors(next.row, next.col, neighbors);
  487. n = globals->nn - 1;
  488. do {
  489. rown = neighbors[n][0];
  490. coln = neighbors[n][1];
  491. no_check = 0;
  492. if (rown < globals->row_min || rown >= globals->row_max ||
  493. coln < globals->col_min || coln >= globals->col_max)
  494. no_check = 1;
  495. if (!no_check && (FLAG_GET(globals->null_flag, rown, coln)))
  496. no_check = 1;
  497. ngbr_rc.row = rown;
  498. ngbr_rc.col = coln;
  499. if (pngbr_rc == NULL)
  500. pngbr_rc = G_malloc(sizeof(struct rc));
  501. *pngbr_rc = ngbr_rc;
  502. if (!no_check && pavl_insert(visited, pngbr_rc) == NULL) {
  503. pngbr_rc = NULL;
  504. /* get neighbour ID */
  505. Segment_get(&globals->rid_seg, (void *) &ngbr_id, rown, coln);
  506. /* same neighbour */
  507. if (ngbr_id == this_id) {
  508. reg_size++;
  509. rclist_add(&rilist, rown, coln);
  510. FLAG_UNSET(globals->candidate_flag, rown, coln);
  511. }
  512. }
  513. } while (n--); /* end do loop - next neighbor */
  514. } while (rclist_drop(&rilist, &next)); /* while there are cells to check */
  515. rclist_destroy(&rilist);
  516. if (pngbr_rc)
  517. G_free(pngbr_rc);
  518. pavl_destroy(visited, free_item);
  519. return reg_size;
  520. }
  521. static int update_rid(struct globals *globals, int row, int col, int new_id)
  522. {
  523. int rown, coln, n;
  524. int neighbors[8][2];
  525. int this_id;
  526. int ngbr_id;
  527. struct rc next;
  528. struct rclist rilist;
  529. int no_check;
  530. /* get this ID */
  531. Segment_get(&globals->rid_seg, (void *) &this_id, row, col);
  532. Segment_put(&globals->rid_seg, (void *) &new_id, row, col);
  533. /* breadth-first search */
  534. next.row = row;
  535. next.col = col;
  536. rclist_init(&rilist);
  537. do {
  538. globals->find_neighbors(next.row, next.col, neighbors);
  539. n = globals->nn - 1;
  540. do {
  541. rown = neighbors[n][0];
  542. coln = neighbors[n][1];
  543. no_check = 0;
  544. if (rown < globals->row_min || rown >= globals->row_max ||
  545. coln < globals->col_min || coln >= globals->col_max)
  546. no_check = 1;
  547. if (!no_check && (FLAG_GET(globals->null_flag, rown, coln)))
  548. no_check = 1;
  549. if (!no_check) {
  550. /* get neighbour ID */
  551. Segment_get(&globals->rid_seg, (void *) &ngbr_id, rown, coln);
  552. /* same neighbour */
  553. if (ngbr_id == this_id) {
  554. rclist_add(&rilist, rown, coln);
  555. Segment_put(&globals->rid_seg, (void *) &new_id, rown, coln);
  556. }
  557. }
  558. } while (n--); /* end do loop - next neighbor */
  559. } while (rclist_drop(&rilist, &next)); /* while there are cells to check */
  560. rclist_destroy(&rilist);
  561. return 1;
  562. }
  563. int remove_small_clumps(struct globals *globals)
  564. {
  565. int row, col, i;
  566. struct NB_TREE *nbtree;
  567. int this_id;
  568. struct ngbr_stats *Rbest;
  569. int best_n_id, best_n_row, best_n_col;
  570. int reg_size;
  571. CELL *renumber, n_regions, min_rid;
  572. /* two possible modes
  573. * best (most similar) neighbor
  574. * neighbor with longest shared boundary
  575. */
  576. if (globals->min_segment_size < 2)
  577. return 0;
  578. G_message(_("Merging segments smaller than %d cells..."), globals->min_segment_size);
  579. /* init renumber */
  580. renumber = (CELL *) G_malloc(sizeof(CELL) * (globals->max_rid + 1));
  581. for (i = 0; i <= globals->max_rid; i++)
  582. renumber[i] = 0;
  583. /* clear candidate flag */
  584. flag_clear_all(globals->candidate_flag);
  585. min_rid = globals->max_rid;
  586. /* Set candidate flag to true/1 for all non-NULL cells */
  587. for (row = globals->row_min; row < globals->row_max; row++) {
  588. for (col = globals->col_min; col < globals->col_max; col++) {
  589. if (!(FLAG_GET(globals->null_flag, row, col))) {
  590. FLAG_SET(globals->candidate_flag, row, col);
  591. Segment_get(&globals->rid_seg, (void *) &this_id, row, col);
  592. /* renumber is region size */
  593. if (renumber[this_id] <= globals->min_segment_size) {
  594. renumber[this_id]++;
  595. if (min_rid > this_id)
  596. min_rid = this_id;
  597. }
  598. }
  599. }
  600. }
  601. min_rid--;
  602. nbtree = nbtree_create(globals->nbands, globals->datasize);
  603. /* go through all cells */
  604. G_percent_reset();
  605. for (row = globals->row_min; row < globals->row_max; row++) {
  606. G_percent(row - globals->row_min,
  607. globals->row_max - globals->row_min, 2);
  608. for (col = globals->col_min; col < globals->col_max; col++) {
  609. if ((FLAG_GET(globals->null_flag, row, col)))
  610. continue;
  611. if (!(FLAG_GET(globals->candidate_flag, row, col)))
  612. continue;
  613. /* get this ID */
  614. Segment_get(&globals->rid_seg, (void *) &this_id, row, col);
  615. reg_size = renumber[this_id];
  616. best_n_id = 1;
  617. while (reg_size < globals->min_segment_size && best_n_id > 0) {
  618. Rbest = NULL;
  619. reg_size = 1;
  620. best_n_row = best_n_col = -1;
  621. best_n_id = find_best_neighbour(globals, row, col, this_id,
  622. nbtree, &reg_size, &Rbest,
  623. &best_n_row, &best_n_col);
  624. /* Rbest: pointer to most common neighbour
  625. * best_n_id, best_n_[row|col]: most similar neighbour */
  626. if (reg_size < globals->min_segment_size && best_n_id > 0) {
  627. /* update rid */
  628. update_rid(globals, row, col, best_n_id);
  629. /* mark as merged */
  630. renumber[best_n_id] += renumber[this_id];
  631. reg_size = renumber[best_n_id];
  632. renumber[this_id] = 0;
  633. this_id = best_n_id;
  634. }
  635. }
  636. }
  637. }
  638. G_percent(1, 1, 1);
  639. n_regions = 0;
  640. /* renumber becomes new region ID */
  641. for (i = 1; i <= globals->max_rid; i++) {
  642. if (renumber[i] > 0) {
  643. renumber[i] = ++n_regions;
  644. }
  645. }
  646. G_message(_("Renumbering remaining %d segments..."), n_regions);
  647. for (row = globals->row_min; row < globals->row_max; row++) {
  648. G_percent(row - globals->row_min,
  649. globals->row_max - globals->row_min, 4);
  650. for (col = globals->col_min; col < globals->col_max; col++) {
  651. if ((FLAG_GET(globals->null_flag, row, col)))
  652. continue;
  653. /* get this ID */
  654. Segment_get(&globals->rid_seg, (void *) &this_id, row, col);
  655. if (Rast_is_c_null_value(&this_id) || this_id < 1)
  656. continue;
  657. this_id = renumber[this_id] + min_rid;
  658. Segment_put(&globals->rid_seg, (void *) &this_id, row, col);
  659. }
  660. }
  661. G_percent(1, 1, 1);
  662. globals->max_rid = n_regions + min_rid;
  663. G_free(renumber);
  664. nbtree_clear(nbtree);
  665. return 1;
  666. }