create_isegs.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  1. /* PURPOSE: Develop the image segments */
  2. /* Currently only region growing is implemented */
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <float.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <grass/gis.h>
  9. #include <grass/glocale.h>
  10. #include <grass/raster.h>
  11. #include <grass/segment.h> /* segmentation library */
  12. #include <grass/rbtree.h> /* Red Black Tree library functions */
  13. #include "iseg.h"
  14. #define EPSILON 1.0e-8
  15. #define MAX(a,b) ( ((a)>(b)) ? (a) : (b) )
  16. #define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
  17. /* internal functions */
  18. static int merge_regions(struct ngbr_stats *, struct reg_stats *, /* Ri */
  19. struct ngbr_stats *, struct reg_stats *, /* Rk */
  20. int,
  21. struct globals *);
  22. static int search_neighbors(struct ngbr_stats *, /* Ri */
  23. struct reg_stats *,
  24. struct NB_TREE *, /* Ri's neighbors */
  25. double *, /* highest similarity */
  26. struct ngbr_stats *, /* Ri's best neighbor */
  27. struct reg_stats *,
  28. struct globals *);
  29. static int set_candidate_flag(struct ngbr_stats *, int , struct globals *);
  30. static int find_best_neighbor(struct ngbr_stats *, struct reg_stats *,
  31. struct NB_TREE *, struct ngbr_stats *,
  32. struct reg_stats *, double *, int,
  33. struct globals *);
  34. static int calculate_reg_stats(int, int, struct reg_stats *,
  35. struct globals *);
  36. /* function used by binary tree to compare items */
  37. static int compare_rc(const void *first, const void *second)
  38. {
  39. struct rc *a = (struct rc *)first, *b = (struct rc *)second;
  40. if (a->row < b->row)
  41. return -1;
  42. if (a->row > b->row)
  43. return 1;
  44. /* same row */
  45. if (a->col < b->col)
  46. return -1;
  47. if (a->col > b->col)
  48. return 1;
  49. /* same row and col */
  50. return 0;
  51. }
  52. static int compare_ints(const void *first, const void *second)
  53. {
  54. int a = *(int *)first, b = *(int *)second;
  55. return (a < b ? -1 : (a > b));
  56. }
  57. static int compare_double(double first, double second)
  58. {
  59. /* standard comparison, gives good results */
  60. if (first < second)
  61. return -1;
  62. return (first > second);
  63. /* fuzzy comparison,
  64. * can give weird results if EPSILON is too large or
  65. * if the formula is changed because this is operating at the
  66. * limit of double fp precision */
  67. if (first < second && first + first * EPSILON < second)
  68. return -1;
  69. if (first > second && first > second + second * EPSILON)
  70. return 1;
  71. return 0;
  72. }
  73. static int dump_Ri(struct ngbr_stats *Ri, struct reg_stats *Ri_rs, double *Ri_sim,
  74. double *Rk_sim, int *Ri_nn, int *Rk_nn, struct globals *globals)
  75. {
  76. int i;
  77. G_debug(0, "Ri, Ri_rs ID: %d, %d", Ri->id, Ri_rs->id);
  78. G_debug(0, "Ri, Ri_rs count: %d, %d", Ri->count, Ri_rs->count);
  79. for (i = 0; i < globals->nbands; i++) {
  80. G_debug(0, "Ri, Ri_rs mean %d: %g, %g", i, Ri->mean[i], Ri_rs->mean[i]);
  81. G_debug(0, "Ri_rs sum %d: %g", i, Ri_rs->sum[i]);
  82. }
  83. G_debug(0, "Ri nn: %d", *Ri_nn);
  84. if (Rk_nn)
  85. G_debug(0, "Rk nn: %d", *Rk_nn);
  86. G_debug(0, "Ri similarity: %g", *Ri_sim);
  87. if (Rk_sim)
  88. G_debug(0, "Rk similarity: %g", *Rk_sim);
  89. return 1;
  90. }
  91. int create_isegs(struct globals *globals)
  92. {
  93. int row, col;
  94. int successflag = 1;
  95. int have_bound;
  96. CELL current_bound, bounds_val;
  97. G_debug(1, "segmentation method: %d", globals->method);
  98. if (globals->bounds_map == NULL) {
  99. /* just one time through loop */
  100. successflag = region_growing(globals);
  101. }
  102. else {
  103. /* outer processing loop for polygon constraints */
  104. for (current_bound = globals->lower_bound;
  105. current_bound <= globals->upper_bound; current_bound++) {
  106. G_debug(1, "current_bound = %d", current_bound);
  107. have_bound = 0;
  108. /* get min/max row/col to narrow the processing window */
  109. globals->row_min = globals->nrows;
  110. globals->row_max = 0;
  111. globals->col_min = globals->ncols;
  112. globals->col_max = 0;
  113. for (row = 0; row < globals->nrows; row++) {
  114. for (col = 0; col < globals->ncols; col++) {
  115. segment_get(&globals->bounds_seg, &bounds_val,
  116. row, col);
  117. if (bounds_val == current_bound) {
  118. have_bound = 1;
  119. FLAG_UNSET(globals->null_flag, row, col);
  120. if (globals->row_min > row)
  121. globals->row_min = row;
  122. if (globals->row_max < row)
  123. globals->row_max = row;
  124. if (globals->col_min > col)
  125. globals->col_min = col;
  126. if (globals->col_max < col)
  127. globals->col_max = col;
  128. }
  129. else
  130. FLAG_SET(globals->null_flag, row, col);
  131. }
  132. }
  133. globals->row_max++;
  134. globals->col_max++;
  135. if (have_bound)
  136. successflag = region_growing(globals);
  137. } /* end outer loop for processing polygons */
  138. }
  139. return successflag;
  140. }
  141. int region_growing(struct globals *globals)
  142. {
  143. int row, col, t;
  144. double threshold, adjthresh, Ri_similarity, Rk_similarity;
  145. double alpha2, divisor; /* threshold parameters */
  146. int n_merges, do_merge; /* number of merges on that iteration */
  147. int pathflag; /* =1 if we didn't find mutually best neighbors, continue with Rk */
  148. int candidates_only;
  149. struct ngbr_stats Ri,
  150. Rk,
  151. Rk_bestn, /* Rk's best neighbor */
  152. *next;
  153. int Ri_nn, Rk_nn; /* number of neighbors for Ri/Rk */
  154. struct NB_TREE *Ri_ngbrs, *Rk_ngbrs;
  155. struct NB_TRAV travngbr;
  156. /* not all regions are in the tree, but we always need reg_stats for Ri and Rk */
  157. struct reg_stats Ri_rs, Rk_rs, Rk_bestn_rs;
  158. double *dp;
  159. struct NB_TREE *tmpnbtree;
  160. G_verbose_message("Running region growing algorithm");
  161. /* init neighbor stats */
  162. Ri.mean = G_malloc(globals->datasize);
  163. Rk.mean = G_malloc(globals->datasize);
  164. Rk_bestn.mean = G_malloc(globals->datasize);
  165. Ri_ngbrs = nbtree_create(globals->nbands, globals->datasize);
  166. Rk_ngbrs = nbtree_create(globals->nbands, globals->datasize);
  167. /* init region stats */
  168. Ri_rs.mean = G_malloc(globals->datasize);
  169. Ri_rs.sum = G_malloc(globals->datasize);
  170. Rk_rs.mean = G_malloc(globals->datasize);
  171. Rk_rs.sum = G_malloc(globals->datasize);
  172. Rk_bestn_rs.mean = G_malloc(globals->datasize);
  173. Rk_bestn_rs.sum = G_malloc(globals->datasize);
  174. t = 0;
  175. n_merges = 2;
  176. /* threshold calculation */
  177. alpha2 = globals->alpha * globals->alpha;
  178. threshold = alpha2;
  179. G_debug(1, "Squared threshold: %g", threshold);
  180. /* make the divisor a constant ? */
  181. divisor = globals->nrows + globals->ncols;
  182. while (t < globals->end_t && n_merges > 1) {
  183. G_message(_("Pass %d:"), ++t);
  184. n_merges = 0;
  185. globals->candidate_count = 0;
  186. flag_clear_all(globals->candidate_flag);
  187. /* Set candidate flag to true/1 for all non-NULL cells */
  188. for (row = globals->row_min; row < globals->row_max; row++) {
  189. for (col = globals->col_min; col < globals->col_max; col++) {
  190. if (!(FLAG_GET(globals->null_flag, row, col))) {
  191. FLAG_SET(globals->candidate_flag, row, col);
  192. globals->candidate_count++;
  193. }
  194. }
  195. }
  196. G_debug(4, "Starting to process %d candidate cells",
  197. globals->candidate_count);
  198. /*process candidate cells */
  199. for (row = globals->row_min; row < globals->row_max; row++) {
  200. G_percent(row, globals->row_max, 4);
  201. for (col = globals->col_min; col < globals->col_max; col++) {
  202. if (!(FLAG_GET(globals->candidate_flag, row, col)))
  203. continue;
  204. pathflag = TRUE;
  205. candidates_only = TRUE;
  206. nbtree_clear(Ri_ngbrs);
  207. nbtree_clear(Rk_ngbrs);
  208. G_debug(4, "Next starting cell: row, %d, col, %d",
  209. row, col);
  210. /* First cell in Ri is current row/col */
  211. Ri.row = row;
  212. Ri.col = col;
  213. /* get Ri's segment ID */
  214. segment_get(&globals->rid_seg, (void *)&Ri.id, Ri.row, Ri.col);
  215. if (Ri.id < 0)
  216. continue;
  217. /* find segment neighbors */
  218. /* find Ri's best neighbor, clear candidate flag */
  219. Ri_similarity = 2;
  220. Ri_rs.id = Ri.id;
  221. fetch_reg_stats(Ri.row, Ri.col, &Ri_rs, globals);
  222. memcpy(Ri.mean, Ri_rs.mean, globals->datasize);
  223. Ri.count = Ri_rs.count;
  224. /* Ri is now complete */
  225. G_debug(4, "Ri is now complete");
  226. /* find best neighbor, get region stats for Rk */
  227. Ri_nn = find_best_neighbor(&Ri, &Ri_rs, Ri_ngbrs,
  228. &Rk, &Rk_rs, &Ri_similarity,
  229. 1, globals);
  230. /* Rk is now complete */
  231. G_debug(4, "Rk is now complete");
  232. if (Ri_nn == 0) {
  233. /* this can only happen if only one segment is left */
  234. G_debug(4, "Segment had no valid neighbors");
  235. pathflag = FALSE;
  236. Ri.count = 0;
  237. }
  238. if (/* !(t & 1) && */ Ri_nn == 1 &&
  239. !(FLAG_GET(globals->candidate_flag, Rk.row, Rk.col)) &&
  240. compare_double(Ri_similarity, threshold) == -1) {
  241. /* this is slow ??? */
  242. int smaller = Rk.count;
  243. if (Ri.count < Rk.count)
  244. smaller = Ri.count;
  245. adjthresh = pow(alpha2, 1. + (double) smaller / divisor);
  246. if (compare_double(Ri_similarity, adjthresh) == -1) {
  247. G_debug(4, "Ri nn == 1");
  248. if (Rk.count < 2)
  249. G_fatal_error("Rk count too low");
  250. if (Rk.count < Ri.count)
  251. G_debug(4, "Rk count lower than Ri count");
  252. merge_regions(&Ri, &Ri_rs, &Rk, &Rk_rs, 1, globals);
  253. n_merges++;
  254. }
  255. pathflag = FALSE;
  256. }
  257. /* this is slow ??? */
  258. if (/* t & */ 1) {
  259. if ((globals->nn < 8 && Rk.count <= 8) ||
  260. (globals->nn >= 8 && Rk.count <= globals->nn))
  261. candidates_only = FALSE;
  262. }
  263. while (pathflag) {
  264. pathflag = FALSE;
  265. /* optional check if Rk is candidate
  266. * to prevent backwards merging */
  267. if (candidates_only &&
  268. !(FLAG_GET(globals->candidate_flag, Rk.row, Rk.col))) {
  269. Ri_similarity = 2;
  270. }
  271. candidates_only = TRUE;
  272. if (compare_double(Ri_similarity, threshold) == -1) {
  273. do_merge = 1;
  274. /* we'll have the neighbor pixel to start with. */
  275. G_debug(4, "Working with Rk");
  276. /* find Rk's best neighbor, do not clear candidate flag */
  277. Rk_similarity = Ri_similarity;
  278. Rk_bestn_rs.count = 0;
  279. /* Rk_rs is already complete */
  280. Rk_nn = find_best_neighbor(&Rk, &Rk_rs, Rk_ngbrs,
  281. &Rk_bestn,
  282. &Rk_bestn_rs,
  283. &Rk_similarity, 0,
  284. globals);
  285. /* not mutually best neighbors */
  286. if (Rk_similarity != Ri_similarity) {
  287. /* important for fp precision limit
  288. * because region stats may be calculated
  289. * in two slightly different ways */
  290. if (Ri_similarity - Rk_similarity > EPSILON)
  291. do_merge = 0;
  292. }
  293. /* Ri has only one neighbor, merge */
  294. if (Ri_nn == 1 && Rk_nn > 1)
  295. do_merge = 1;
  296. /* adjust threshold */
  297. if (do_merge) {
  298. int smaller = Rk.count;
  299. if (Ri.count < Rk.count)
  300. smaller = Ri.count;
  301. adjthresh = pow(alpha2, 1. + (double) smaller / divisor);
  302. do_merge = 0;
  303. if (compare_double(Ri_similarity, adjthresh) == -1) {
  304. do_merge = 1;
  305. }
  306. }
  307. if (do_merge) {
  308. G_debug(4, "merge neighbor trees");
  309. Ri_nn -= Ri_ngbrs->count;
  310. Ri_nn += (Rk_nn - Rk_ngbrs->count);
  311. globals->ns.id = Rk.id;
  312. nbtree_remove(Ri_ngbrs, &(globals->ns));
  313. nbtree_init_trav(&travngbr, Rk_ngbrs);
  314. while ((next = nbtree_traverse(&travngbr))) {
  315. if (!nbtree_find(Ri_ngbrs, next) && next->id != Ri.id)
  316. nbtree_insert(Ri_ngbrs, next);
  317. }
  318. nbtree_clear(Rk_ngbrs);
  319. Ri_nn += Ri_ngbrs->count;
  320. merge_regions(&Ri, &Ri_rs, &Rk, &Rk_rs, 1, globals);
  321. /* Ri is now updated, Rk no longer usable */
  322. /* made a merge, need another iteration */
  323. n_merges++;
  324. Ri_similarity = 2;
  325. Rk_similarity = 2;
  326. /* we have checked the neighbors of Ri, Rk already
  327. * use faster version of finding the best neighbor
  328. */
  329. /* use neighbor tree to find Ri's new best neighbor */
  330. search_neighbors(&Ri, &Ri_rs, Ri_ngbrs, &Ri_similarity,
  331. &Rk, &Rk_rs, globals);
  332. if (Ri_nn > 0 && compare_double(Ri_similarity, threshold) == -1) {
  333. pathflag = TRUE;
  334. /* candidates_only:
  335. * FALSE: less passes, takes a bit longer, but less memory
  336. * TRUE: more passes, is a bit faster */
  337. candidates_only = FALSE;
  338. }
  339. /* else end of Ri -> Rk chain since we merged Ri and Rk
  340. * go to next row, col */
  341. }
  342. else {
  343. if (compare_double(Rk_similarity, threshold) == -1) {
  344. pathflag = TRUE;
  345. }
  346. /* test this: can it cause an infinite loop ? */
  347. if (!(FLAG_GET(globals->candidate_flag, Rk.row, Rk.col)))
  348. pathflag = FALSE;
  349. if (Rk_nn < 2)
  350. pathflag = FALSE;
  351. if (Rk.id < 1)
  352. pathflag = FALSE;
  353. if (pathflag) {
  354. /* clear candidate flag for Rk */
  355. if (FLAG_GET(globals->candidate_flag, Rk.row, Rk.col)) {
  356. set_candidate_flag(&Rk, FALSE, globals);
  357. }
  358. /* Use Rk as next Ri:
  359. * this is the eCognition technique. */
  360. G_debug(4, "do ecog");
  361. Ri_nn = Rk_nn;
  362. Ri_similarity = Rk_similarity;
  363. dp = Ri.mean;
  364. Ri = Rk;
  365. Rk = Rk_bestn;
  366. Rk_bestn.mean = dp;
  367. Ri_rs.id = Rk_rs.id;
  368. Rk_rs.id = Rk_bestn_rs.id;
  369. Rk_bestn_rs.id = 0;
  370. Ri_rs.count = Rk_rs.count;
  371. Rk_rs.count = Rk_bestn_rs.count;
  372. Rk_bestn_rs.count = 0;
  373. dp = Ri_rs.mean;
  374. Ri_rs.mean = Rk_rs.mean;
  375. Rk_rs.mean = Rk_bestn_rs.mean;
  376. Rk_bestn_rs.mean = dp;
  377. dp = Ri_rs.sum;
  378. Ri_rs.sum = Rk_rs.sum;
  379. Rk_rs.sum = Rk_bestn_rs.sum;
  380. Rk_bestn_rs.sum = dp;
  381. tmpnbtree = Ri_ngbrs;
  382. Ri_ngbrs = Rk_ngbrs;
  383. Rk_ngbrs = tmpnbtree;
  384. nbtree_clear(Rk_ngbrs);
  385. }
  386. }
  387. } /* end if < threshold */
  388. } /* end pathflag */
  389. } /* next col */
  390. } /* next row */
  391. /* finished one pass for processing candidate pixels */
  392. G_verbose_message("%d merges", n_merges);
  393. G_debug(4, "Finished pass %d", t);
  394. }
  395. /*end t loop *//*TODO, should there be a max t that it can iterate for? Include t in G_message? */
  396. if (n_merges > 1)
  397. G_message(_("Segmentation processes stopped at %d due to reaching max iteration limit, more merges may be possible"), t);
  398. else
  399. G_message(_("Segmentation converged after %d iterations."), t);
  400. /* ****************************************************************************************** */
  401. /* final pass, ignore threshold and force a merge for small segments with their best neighbor */
  402. /* ****************************************************************************************** */
  403. if (globals->min_segment_size > 1) {
  404. G_message(_("Merging segments smaller than %d cells"), globals->min_segment_size);
  405. threshold = globals->alpha * globals->alpha;
  406. flag_clear_all(globals->candidate_flag);
  407. n_merges = 0;
  408. /* Set candidate flag to true/1 for all non-NULL cells */
  409. for (row = globals->row_min; row < globals->row_max; row++) {
  410. for (col = globals->col_min; col < globals->col_max; col++) {
  411. if (!(FLAG_GET(globals->null_flag, row, col))) {
  412. FLAG_SET(globals->candidate_flag, row, col);
  413. globals->candidate_count++;
  414. }
  415. }
  416. }
  417. G_debug(4, "Starting to process %d candidate cells",
  418. globals->candidate_count);
  419. /* process candidate cells */
  420. for (row = globals->row_min; row < globals->row_max; row++) {
  421. G_percent(row, globals->row_max, 9);
  422. for (col = globals->col_min; col < globals->col_max; col++) {
  423. int do_merge = 1;
  424. if (!(FLAG_GET(globals->candidate_flag, row, col)))
  425. continue;
  426. nbtree_clear(Ri_ngbrs);
  427. nbtree_clear(Rk_ngbrs);
  428. Ri.row = row;
  429. Ri.col = col;
  430. /* get segment id */
  431. segment_get(&globals->rid_seg, (void *) &Ri.id, row, col);
  432. if (Ri.id < 0)
  433. continue;
  434. Ri_rs.id = Ri.id;
  435. /* get segment size */
  436. fetch_reg_stats(Ri.row, Ri.col, &Ri_rs, globals);
  437. memcpy(Ri.mean, Ri_rs.mean, globals->datasize);
  438. Ri.count = Ri_rs.count;
  439. while (do_merge) {
  440. do_merge = 0;
  441. /* merge all smaller than min size */
  442. if (Ri.count < globals->min_segment_size)
  443. do_merge = 1;
  444. Ri_nn = 0;
  445. Ri_similarity = 2;
  446. if (do_merge) {
  447. /* find Ri's best neighbor, clear candidate flag */
  448. Ri_nn = find_best_neighbor(&Ri, &Ri_rs, Ri_ngbrs,
  449. &Rk, &Rk_rs,
  450. &Ri_similarity, 1,
  451. globals);
  452. }
  453. if (Ri_nn > 0) {
  454. nbtree_clear(Ri_ngbrs);
  455. /* merge Ri with Rk */
  456. /* do not clear candidate flag for Rk */
  457. merge_regions(&Ri, &Ri_rs, &Rk, &Rk_rs, 0, globals);
  458. n_merges++;
  459. if (Ri_nn <= 0 || Ri.count >= globals->min_segment_size)
  460. do_merge = 0;
  461. }
  462. }
  463. }
  464. }
  465. G_percent(1, 1, 1);
  466. /* finished one pass for processing candidate pixels */
  467. G_verbose_message("%d merges", n_merges);
  468. }
  469. /* free neighbor stats */
  470. G_free(Ri.mean);
  471. G_free(Rk.mean);
  472. G_free(Rk_bestn.mean);
  473. nbtree_clear(Ri_ngbrs);
  474. nbtree_clear(Rk_ngbrs);
  475. free(Ri_ngbrs);
  476. free(Rk_ngbrs);
  477. /* free region stats */
  478. G_free(Ri_rs.mean);
  479. G_free(Ri_rs.sum);
  480. G_free(Rk_rs.mean);
  481. G_free(Rk_rs.sum);
  482. G_free(Rk_bestn_rs.mean);
  483. G_free(Rk_bestn_rs.sum);
  484. return TRUE;
  485. }
  486. static int find_best_neighbor(struct ngbr_stats *Ri,
  487. struct reg_stats *Ri_rs,
  488. struct NB_TREE *Ri_ngbrs,
  489. struct ngbr_stats *Rk,
  490. struct reg_stats *Rk_rs,
  491. double *sim, int clear_cand,
  492. struct globals *globals)
  493. {
  494. int n, n_ngbrs, no_check, cmp;
  495. struct rc ngbr_rc, next;
  496. struct rclist rilist;
  497. double tempsim;
  498. int neighbors[8][2];
  499. struct RB_TREE *no_check_tree; /* cells already checked */
  500. struct reg_stats *rs_found;
  501. G_debug(4, "find_best_neighbor()");
  502. /* dynamics of the region growing algorithm
  503. * some regions are growing fast, often surrounded by many small regions
  504. * not all regions are equally growing, some will only grow at a later stage ? */
  505. /* *** initialize data *** */
  506. no_check_tree = rbtree_create(compare_rc, sizeof(struct rc));
  507. ngbr_rc.row = Ri->row;
  508. ngbr_rc.col = Ri->col;
  509. rbtree_insert(no_check_tree, &ngbr_rc);
  510. n_ngbrs = 0;
  511. /* TODO: add size of largest region to reg_tree, use this as min */
  512. Rk->count = globals->ncells;
  513. Rk->id = Rk_rs->id = 0;
  514. if (Ri->id != Ri_rs->id)
  515. G_fatal_error("Ri = %d but Ri_rs = %d", Ri->id, Ri_rs->id);
  516. if (Ri->id <= 0)
  517. G_fatal_error("Ri is %d", Ri->id);
  518. if (Ri_rs->id <= 0)
  519. G_fatal_error("Ri_rs is %d", Ri_rs->id);
  520. /* go through segment, spreading outwards from head */
  521. rclist_init(&rilist);
  522. /* check neighbors of start cell */
  523. next.row = Ri->row;
  524. next.col = Ri->col;
  525. do {
  526. /* remove from candidates */
  527. if (clear_cand)
  528. FLAG_UNSET(globals->candidate_flag, next.row, next.col);
  529. G_debug(5, "find_pixel_neighbors for row: %d , col %d",
  530. next.row, next.col);
  531. globals->find_neighbors(next.row, next.col, neighbors);
  532. n = globals->nn - 1;
  533. do {
  534. globals->ns.row = ngbr_rc.row = neighbors[n][0];
  535. globals->ns.col = ngbr_rc.col = neighbors[n][1];
  536. no_check = (ngbr_rc.row < globals->row_min ||
  537. ngbr_rc.row >= globals->row_max ||
  538. ngbr_rc.col < globals->col_min ||
  539. ngbr_rc.col >= globals->col_max);
  540. n_ngbrs += no_check;
  541. if (!no_check) {
  542. no_check = ((FLAG_GET(globals->null_flag, ngbr_rc.row,
  543. ngbr_rc.col)) != 0);
  544. n_ngbrs += no_check;
  545. if (!no_check) {
  546. if (!rbtree_find(no_check_tree, &ngbr_rc)) {
  547. /* not yet checked, don't check it again */
  548. rbtree_insert(no_check_tree, &ngbr_rc);
  549. /* get neighbor ID */
  550. segment_get(&globals->rid_seg,
  551. (void *) &(globals->ns.id),
  552. ngbr_rc.row, ngbr_rc.col);
  553. if (globals->ns.id == Ri->id) {
  554. /* want to check this neighbor's neighbors */
  555. rclist_add(&rilist, ngbr_rc.row, ngbr_rc.col);
  556. }
  557. else {
  558. /* new neighbor ? */
  559. if (nbtree_find(Ri_ngbrs, &globals->ns) == NULL) {
  560. /* get values for Rk */
  561. globals->rs.id = globals->ns.id;
  562. rs_found = rgtree_find(globals->reg_tree,
  563. &(globals->rs));
  564. if (!rs_found) {
  565. /* region stats are not in search tree */
  566. rs_found = &(globals->rs);
  567. calculate_reg_stats(ngbr_rc.row, ngbr_rc.col,
  568. rs_found, globals);
  569. }
  570. globals->ns.mean = rs_found->mean;
  571. globals->ns.count = rs_found->count;
  572. /* globals->ns is now complete */
  573. tempsim = (globals->calculate_similarity)(Ri, &globals->ns, globals);
  574. cmp = compare_double(tempsim, *sim);
  575. if (cmp == -1) {
  576. *sim = tempsim;
  577. /* copy temp Rk to Rk */
  578. Rk->row = ngbr_rc.row;
  579. Rk->col = ngbr_rc.col;
  580. Rk->id = rs_found->id;
  581. Rk->count = rs_found->count;
  582. memcpy(Rk->mean, rs_found->mean,
  583. globals->datasize);
  584. Rk_rs->id = Rk->id;
  585. Rk_rs->count = Rk->count;
  586. memcpy(Rk_rs->mean, rs_found->mean,
  587. globals->datasize);
  588. memcpy(Rk_rs->sum, rs_found->sum,
  589. globals->datasize);
  590. }
  591. else if (cmp == 0) {
  592. /* resolve ties: prefer smaller regions */
  593. if (Rk->count > globals->ns.count) {
  594. /* copy temp Rk to Rk */
  595. Rk->row = ngbr_rc.row;
  596. Rk->col = ngbr_rc.col;
  597. Rk->id = rs_found->id;
  598. Rk->count = rs_found->count;
  599. memcpy(Rk->mean, rs_found->mean,
  600. globals->datasize);
  601. Rk_rs->id = Rk->id;
  602. Rk_rs->count = Rk->count;
  603. memcpy(Rk_rs->mean, rs_found->mean,
  604. globals->datasize);
  605. memcpy(Rk_rs->sum, rs_found->sum,
  606. globals->datasize);
  607. }
  608. }
  609. n_ngbrs++;
  610. nbtree_insert(Ri_ngbrs, &globals->ns);
  611. }
  612. }
  613. }
  614. }
  615. }
  616. } while (n--); /* end do loop - next neighbor */
  617. } while (rclist_drop(&rilist, &next)); /* while there are cells to check */
  618. /* clean up */
  619. rbtree_destroy(no_check_tree);
  620. return n_ngbrs;
  621. }
  622. void find_four_neighbors(int p_row, int p_col,
  623. int neighbors[8][2])
  624. {
  625. /* north */
  626. neighbors[0][0] = p_row - 1;
  627. neighbors[0][1] = p_col;
  628. /* east */
  629. neighbors[1][0] = p_row;
  630. neighbors[1][1] = p_col + 1;
  631. /* south */
  632. neighbors[2][0] = p_row + 1;
  633. neighbors[2][1] = p_col;
  634. /* west */
  635. neighbors[3][0] = p_row;
  636. neighbors[3][1] = p_col - 1;
  637. return;
  638. }
  639. void find_eight_neighbors(int p_row, int p_col,
  640. int neighbors[8][2])
  641. {
  642. /* get the 4 orthogonal neighbors */
  643. find_four_neighbors(p_row, p_col, neighbors);
  644. /* get the 4 diagonal neighbors */
  645. /* north-west */
  646. neighbors[4][0] = p_row - 1;
  647. neighbors[4][1] = p_col - 1;
  648. /* north-east */
  649. neighbors[5][0] = p_row - 1;
  650. neighbors[5][1] = p_col + 1;
  651. /* south-west */
  652. neighbors[6][0] = p_row + 1;
  653. neighbors[6][1] = p_col - 1;
  654. /* south-east */
  655. neighbors[7][0] = p_row + 1;
  656. neighbors[7][1] = p_col + 1;
  657. return;
  658. }
  659. /* similarity / distance between two points based on their input raster values */
  660. /* assumes first point values already saved in files->bands_seg - only run segment_get once for that value... */
  661. /* TODO: segment_get already happened for a[] values in the main function. Could remove a[] from these parameters */
  662. double calculate_euclidean_similarity(struct ngbr_stats *Ri,
  663. struct ngbr_stats *Rk,
  664. struct globals *globals)
  665. {
  666. double val = 0., diff;
  667. int n = globals->nbands - 1;
  668. /* squared euclidean distance, sum the square differences for each dimension */
  669. do {
  670. diff = Ri->mean[n] - Rk->mean[n];
  671. val += diff * diff;
  672. } while (n--);
  673. /* the return value should always be in the range 0 - 1 */
  674. if (val <= 0)
  675. return 0.;
  676. val /= globals->max_diff;
  677. #ifdef _OR_SHAPE_
  678. if (globals->shape_weight < 1)
  679. val = val * globals->shape_weight + (1 - globals->shape_weight) *
  680. calculate_shape(rsi, rsk, nshared, globals);
  681. #endif
  682. return val;
  683. }
  684. double calculate_manhattan_similarity(struct ngbr_stats *Ri,
  685. struct ngbr_stats *Rk,
  686. struct globals *globals)
  687. {
  688. double val = 0.;
  689. int n = globals->nbands - 1;
  690. /* squared euclidean distance, sum the square differences for each dimension */
  691. do {
  692. val += Ri->mean[n] - Rk->mean[n];
  693. } while (n--);
  694. /* the return value should always be in the range 0 - 1 */
  695. if (val <= 0)
  696. return 0.;
  697. val /= globals->max_diff;
  698. #ifdef _OR_SHAPE_
  699. if (globals->shape_weight < 1)
  700. val = val * globals->shape_weight + (1 - globals->shape_weight) *
  701. calculate_shape(rsi, rsk, nshared, globals);
  702. #endif
  703. return val;
  704. }
  705. double calculate_shape(struct reg_stats *rsi, struct reg_stats *rsk,
  706. int nshared, struct globals *globals)
  707. {
  708. /*
  709. In the eCognition literature, we find that the key factor in the
  710. multi-scale segmentation algorithm used by Definiens is the scale
  711. factor f:
  712. f = W.Hcolor + (1 - W).Hshape
  713. Hcolor = sum(b = 1:nbands)(Wb.SigmaB)
  714. Hshape = Ws.Hcompact + (1 - Ws).Hsmooth
  715. Hcompact = PL/sqrt(Npx)
  716. Hsmooth = PL/Pbbox
  717. Where
  718. W is a user-defined weight of importance of object radiometry vs
  719. shape (usually .9 vs .1)
  720. Wb is the weigh given to band B
  721. SigmaB is the std dev of the object for band b
  722. Ws is a user-defined weight giving the importance of compactedness vs smoothness
  723. PL is the perimeter lenght of the object
  724. Npx the number of pixels within the object
  725. Pbbox the perimeter of the bounding box of the object.
  726. */
  727. /* here we calculate a shape index for the new object to be created
  728. * the radiometric index ranges from 0 to 1, 0 = identical
  729. * with the shape index we want to favour compact and smooth opjects
  730. * thus the shape index should range from 0 to 1,
  731. * 0 = maximum compactness and smoothness */
  732. double smooth, compact;
  733. int pl, pbbox, count;
  734. double bboxdiag;
  735. int pl1, pl2, count1, count2;
  736. int e1, n1, s1, w1, e2, n2, s2, w2, ns_extent, ew_extent;
  737. pl = pl1 + pl2 - nshared;
  738. ns_extent = MAX(n1, n2) - MIN(s1, s2);
  739. ew_extent = MAX(e1, e2) - MIN(w1, w2);
  740. pbbox = 2 * (ns_extent + ew_extent);
  741. /* Smoothness Hsmooth = PL / Pbbox
  742. * the smallest possible value would be
  743. * the diagonal divided by the bbox perimeter
  744. * invert such that the largest possible value would be
  745. * the bbox perimeter divided by the diagonal
  746. */
  747. bboxdiag = sqrt(ns_extent * ns_extent + ew_extent * ew_extent);
  748. smooth = 1. - (double)bboxdiag / pl; /* smaller -> smoother */
  749. count = count1 + count2;
  750. /* compactness Hcompact = PL / sqrt(Npx)
  751. * a circle is the most compact form
  752. * Npx = M_PI * r * r;
  753. * r = sqrt(Npx / M_pi)
  754. * pl_circle = 2 * sqrt(count * M_PI);
  755. * compact = 1 - pl_circle / (pl * sqrt(count);
  756. */
  757. /* compact = 1 - 2 * sqrt(M_PI) / pl; */
  758. /* PL max = Npx */
  759. /* Hcompact max = Npx / sqrt(Npx) = sqrt(Npx)
  760. * Hcompact / Hcompact max = (PL / sqrt(Npx)) / sqrt(Npx)
  761. * = PL / Npx
  762. */
  763. compact = (double)pl / count; /* smaller -> more compact */
  764. return globals->smooth_weight * smooth + (1 - globals->smooth_weight) * compact;
  765. }
  766. static int search_neighbors(struct ngbr_stats *Ri,
  767. struct reg_stats *Ri_rs,
  768. struct NB_TREE *Ri_ngbrs,
  769. double *sim,
  770. struct ngbr_stats *Rk,
  771. struct reg_stats *Rk_rs,
  772. struct globals *globals)
  773. {
  774. double tempsim, *dp;
  775. struct NB_TRAV travngbr;
  776. struct ngbr_stats *next;
  777. int cmp;
  778. G_debug(4, "search_neighbors");
  779. nbtree_init_trav(&travngbr, Ri_ngbrs);
  780. Rk->count = globals->ncells + 1;
  781. while ((next = nbtree_traverse(&travngbr))) {
  782. tempsim = (globals->calculate_similarity)(Ri, next, globals);
  783. cmp = compare_double(tempsim, *sim);
  784. if (cmp == -1) {
  785. *sim = tempsim;
  786. dp = Rk->mean;
  787. *Rk = *next;
  788. Rk->mean = dp;
  789. memcpy(Rk->mean, next->mean, globals->datasize);
  790. }
  791. else if (cmp == 0) {
  792. /* resolve ties, prefer smaller regions */
  793. G_debug(4, "resolve ties");
  794. if (Rk->count > next->count) {
  795. dp = Rk->mean;
  796. *Rk = *next;
  797. Rk->mean = dp;
  798. memcpy(Rk->mean, next->mean, globals->datasize);
  799. }
  800. }
  801. }
  802. Rk_rs->id = Rk->id;
  803. /* faster, but with fp error:
  804. * calculate sum from mean and count */
  805. /*
  806. Rk_rs->count = Rk->count;
  807. memcpy(Rk_rs->mean, Rk->mean, globals->datasize);
  808. i = globals->nbands - 1;
  809. do {
  810. Rk_rs->sum[i] = Rk_rs->mean[i] * Rk_rs->count;
  811. } while (i--);
  812. */
  813. /* a bit slower but correct: */
  814. fetch_reg_stats(Rk->row, Rk->col, Rk_rs, globals);
  815. return 1;
  816. }
  817. int update_band_vals(int row, int col, struct reg_stats *rs,
  818. struct globals *globals) {
  819. struct RB_TREE *rc_check_tree; /* cells already checked */
  820. struct rclist rlist;
  821. struct rc next, ngbr_rc;
  822. int neighbors[8][2];
  823. int rid, count, n;
  824. int no_check;
  825. /* update band values with sum */
  826. /* rs->id must be set */
  827. G_debug(4, "update_band_vals()");
  828. if (rs->count >= globals->min_reg_size) {
  829. G_fatal_error(_("Region stats should go in tree, %d >= %d"),
  830. rs->count, globals->min_reg_size);
  831. }
  832. segment_get(&globals->rid_seg, (void *) &rid, row, col);
  833. if (rid != rs->id) {
  834. G_fatal_error(_("Region ids are different"));
  835. }
  836. /* TODO: add fast version for globals->min_reg_size == 3 */
  837. /* go through region, spreading outwards from head */
  838. rclist_init(&rlist);
  839. rc_check_tree = rbtree_create(compare_rc, sizeof(struct rc));
  840. ngbr_rc.row = row;
  841. ngbr_rc.col = col;
  842. rbtree_insert(rc_check_tree, &ngbr_rc);
  843. count = 1;
  844. /* update region stats */
  845. segment_put(&globals->bands_seg, (void *)rs->sum,
  846. ngbr_rc.row, ngbr_rc.col);
  847. next.row = row;
  848. next.col = col;
  849. do {
  850. G_debug(5, "find_pixel_neighbors for row: %d , col %d",
  851. next.row, next.col);
  852. globals->find_neighbors(next.row, next.col, neighbors);
  853. n = globals->nn - 1;
  854. do {
  855. ngbr_rc.row = neighbors[n][0];
  856. ngbr_rc.col = neighbors[n][1];
  857. no_check = (ngbr_rc.row < 0 || ngbr_rc.row >= globals->nrows ||
  858. ngbr_rc.col < 0 || ngbr_rc.col >= globals->ncols);
  859. if (!no_check) {
  860. if ((FLAG_GET(globals->null_flag, ngbr_rc.row, ngbr_rc.col)) == 0) {
  861. /* already checked ? */
  862. if (!rbtree_find(rc_check_tree, &ngbr_rc)) {
  863. /* not yet checked, don't check it again */
  864. rbtree_insert(rc_check_tree, &ngbr_rc);
  865. segment_get(&globals->rid_seg, (void *) &rid,
  866. ngbr_rc.row, ngbr_rc.col);
  867. if (rid == rs->id) {
  868. /* want to check this neighbor's neighbors */
  869. rclist_add(&rlist, ngbr_rc.row, ngbr_rc.col);
  870. /* update region stats */
  871. segment_put(&globals->bands_seg,
  872. (void *)rs->sum,
  873. ngbr_rc.row, ngbr_rc.col);
  874. count++;
  875. }
  876. }
  877. }
  878. }
  879. } while (n--);
  880. } while (rclist_drop(&rlist, &next));
  881. /* clean up */
  882. rbtree_destroy(rc_check_tree);
  883. rclist_destroy(&rlist);
  884. if (count != rs->count) {
  885. G_fatal_error(_("Region size is %d, should be %d"),
  886. count, rs->count);
  887. }
  888. return count;
  889. }
  890. static int merge_regions(struct ngbr_stats *Ri, struct reg_stats *Ri_rs,
  891. struct ngbr_stats *Rk, struct reg_stats *Rk_rs,
  892. int do_cand, struct globals *globals)
  893. {
  894. int n;
  895. int R_id;
  896. struct rc next, ngbr_rc;
  897. struct rclist rlist;
  898. int neighbors[8][2];
  899. struct reg_stats *new_rs;
  900. G_debug(4, "merge_regions");
  901. /* Ri ID must always be positive */
  902. if (Ri_rs->id < 1)
  903. G_fatal_error("Ri id is not positive: %d", Ri_rs->id);
  904. /* if Rk ID is negative (no seed), Rk count must be 1 */
  905. if (Rk_rs->id < 1 && Rk_rs->count > 1)
  906. G_fatal_error("Rk id is not positive: %d, but count is > 1: %d",
  907. Rk_rs->id, Rk_rs->count);
  908. /* update segment id and clear candidate flag */
  909. /* cases
  910. * Ri, Rk are not in the tree
  911. * Ri, Rk are both in the tree
  912. * Ri is in the tree, Rk is not
  913. * Rk is in the tree, Ri is not
  914. */
  915. /* Ri_rs, Rk_rs must always be set */
  916. /* add Rk */
  917. Ri_rs->count += Rk_rs->count;
  918. n = globals->nbands - 1;
  919. do {
  920. Ri_rs->sum[n] += Rk_rs->sum[n];
  921. Ri_rs->mean[n] = Ri_rs->sum[n] / Ri_rs->count;
  922. } while (n--);
  923. if (Ri->count >= Rk->count) {
  924. if (Rk->count >= globals->min_reg_size) {
  925. if (rgtree_find(globals->reg_tree, Rk_rs) == NULL)
  926. G_fatal_error("merge regions: Rk should be in tree");
  927. /* remove from tree */
  928. rgtree_remove(globals->reg_tree, Rk_rs);
  929. }
  930. }
  931. else {
  932. if (Ri->count >= globals->min_reg_size) {
  933. if (rgtree_find(globals->reg_tree, Ri_rs) == NULL)
  934. G_fatal_error("merge regions: Ri should be in tree");
  935. /* remove from tree */
  936. rgtree_remove(globals->reg_tree, Ri_rs);
  937. }
  938. /* magic switch */
  939. Ri_rs->id = Rk->id;
  940. }
  941. if ((new_rs = rgtree_find(globals->reg_tree, Ri_rs)) != NULL) {
  942. /* update stats for tree item */
  943. new_rs->count = Ri_rs->count;
  944. memcpy(new_rs->mean, Ri_rs->mean, globals->datasize);
  945. memcpy(new_rs->sum, Ri_rs->sum, globals->datasize);
  946. }
  947. else if (Ri_rs->count >= globals->min_reg_size) {
  948. /* add to tree */
  949. rgtree_insert(globals->reg_tree, Ri_rs);
  950. }
  951. Ri->count = Ri_rs->count;
  952. memcpy(Ri->mean, Ri_rs->mean, globals->datasize);
  953. if (Ri->id == Ri_rs->id) {
  954. /* Ri is already updated, including candidate flags
  955. * need to clear candidate flag for Rk and set new id */
  956. /* the actual merge: change region id */
  957. segment_put(&globals->rid_seg, (void *) &Ri->id, Rk->row, Rk->col);
  958. if (do_cand) {
  959. do_cand = 0;
  960. if (FLAG_GET(globals->candidate_flag, Rk->row, Rk->col)) {
  961. /* clear candidate flag */
  962. FLAG_UNSET(globals->candidate_flag, Rk->row, Rk->col);
  963. globals->candidate_count--;
  964. do_cand = 1;
  965. }
  966. }
  967. rclist_init(&rlist);
  968. rclist_add(&rlist, Rk->row, Rk->col);
  969. while (rclist_drop(&rlist, &next)) {
  970. if (do_cand) {
  971. /* clear candidate flag */
  972. FLAG_UNSET(globals->candidate_flag, next.row, next.col);
  973. globals->candidate_count--;
  974. }
  975. globals->find_neighbors(next.row, next.col, neighbors);
  976. n = globals->nn - 1;
  977. do {
  978. ngbr_rc.row = neighbors[n][0];
  979. ngbr_rc.col = neighbors[n][1];
  980. if (ngbr_rc.row >= globals->row_min &&
  981. ngbr_rc.row < globals->row_max &&
  982. ngbr_rc.col >= globals->col_min &&
  983. ngbr_rc.col < globals->col_max) {
  984. if (!(FLAG_GET(globals->null_flag, ngbr_rc.row, ngbr_rc.col))) {
  985. segment_get(&globals->rid_seg, (void *) &R_id,
  986. ngbr_rc.row, ngbr_rc.col);
  987. if (R_id == Rk->id) {
  988. /* the actual merge: change region id */
  989. segment_put(&globals->rid_seg, (void *) &Ri->id, ngbr_rc.row, ngbr_rc.col);
  990. /* want to check this neighbor's neighbors */
  991. rclist_add(&rlist, ngbr_rc.row, ngbr_rc.col);
  992. }
  993. }
  994. }
  995. } while (n--);
  996. }
  997. rclist_destroy(&rlist);
  998. }
  999. else {
  1000. /* Rk was larger than Ri */
  1001. /* clear candidate flag for Rk */
  1002. if (do_cand && FLAG_GET(globals->candidate_flag, Rk->row, Rk->col)) {
  1003. set_candidate_flag(Rk, FALSE, globals);
  1004. }
  1005. /* update region id for Ri */
  1006. /* the actual merge: change region id */
  1007. segment_put(&globals->rid_seg, (void *) &Rk->id, Ri->row, Ri->col);
  1008. rclist_init(&rlist);
  1009. rclist_add(&rlist, Ri->row, Ri->col);
  1010. while (rclist_drop(&rlist, &next)) {
  1011. globals->find_neighbors(next.row, next.col, neighbors);
  1012. n = globals->nn - 1;
  1013. do {
  1014. ngbr_rc.row = neighbors[n][0];
  1015. ngbr_rc.col = neighbors[n][1];
  1016. if (ngbr_rc.row >= globals->row_min &&
  1017. ngbr_rc.row < globals->row_max &&
  1018. ngbr_rc.col >= globals->col_min &&
  1019. ngbr_rc.col < globals->col_max) {
  1020. if (!(FLAG_GET(globals->null_flag, ngbr_rc.row, ngbr_rc.col))) {
  1021. segment_get(&globals->rid_seg, (void *) &R_id, ngbr_rc.row, ngbr_rc.col);
  1022. if (R_id == Ri->id) {
  1023. /* the actual merge: change region id */
  1024. segment_put(&globals->rid_seg, (void *) &Rk->id, ngbr_rc.row, ngbr_rc.col);
  1025. /* want to check this neighbor's neighbors */
  1026. rclist_add(&rlist, ngbr_rc.row, ngbr_rc.col);
  1027. }
  1028. }
  1029. }
  1030. } while (n--);
  1031. }
  1032. rclist_destroy(&rlist);
  1033. Ri->id = Ri_rs->id; /* == Rk->id */
  1034. if (Ri->id != Rk->id)
  1035. G_fatal_error("Ri ID should be set to Rk ID");
  1036. }
  1037. if (Rk->id > 0)
  1038. globals->n_regions--;
  1039. /* disable Rk */
  1040. Rk->id = Rk_rs->id = 0;
  1041. Rk->count = Rk_rs->count = 0;
  1042. /* update Ri */
  1043. Ri->id = Ri_rs->id;
  1044. if (Ri_rs->count < globals->min_reg_size) {
  1045. update_band_vals(Ri->row, Ri->col, Ri_rs, globals);
  1046. }
  1047. return TRUE;
  1048. }
  1049. static int set_candidate_flag(struct ngbr_stats *head, int value, struct globals *globals)
  1050. {
  1051. int n, R_id;
  1052. struct rc next, ngbr_rc;
  1053. struct rclist rlist;
  1054. int neighbors[8][2];
  1055. G_debug(4, "set_candidate_flag");
  1056. if (!(FLAG_GET(globals->candidate_flag, head->row, head->col)) != value) {
  1057. G_warning(_("Candidate flag is already %s"), value ? _("set") : _("unset"));
  1058. return FALSE;
  1059. }
  1060. rclist_init(&rlist);
  1061. rclist_add(&rlist, head->row, head->col);
  1062. /* (un)set candidate flag */
  1063. if (value == TRUE) {
  1064. FLAG_SET(globals->candidate_flag, head->row, head->col);
  1065. globals->candidate_count++;
  1066. }
  1067. else {
  1068. FLAG_UNSET(globals->candidate_flag, head->row, head->col);
  1069. globals->candidate_count--;
  1070. }
  1071. while (rclist_drop(&rlist, &next)) {
  1072. globals->find_neighbors(next.row, next.col, neighbors);
  1073. n = globals->nn - 1;
  1074. do {
  1075. ngbr_rc.row = neighbors[n][0];
  1076. ngbr_rc.col = neighbors[n][1];
  1077. if (ngbr_rc.row >= globals->row_min &&
  1078. ngbr_rc.row < globals->row_max &&
  1079. ngbr_rc.col >= globals->col_min &&
  1080. ngbr_rc.col < globals->col_max) {
  1081. if (!(FLAG_GET(globals->null_flag, ngbr_rc.row, ngbr_rc.col))) {
  1082. if (!(FLAG_GET(globals->candidate_flag, ngbr_rc.row, ngbr_rc.col)) == value) {
  1083. segment_get(&globals->rid_seg, (void *) &R_id, ngbr_rc.row, ngbr_rc.col);
  1084. if (R_id == head->id) {
  1085. /* want to check this neighbor's neighbors */
  1086. rclist_add(&rlist, ngbr_rc.row, ngbr_rc.col);
  1087. /* (un)set candidate flag */
  1088. if (value == TRUE) {
  1089. FLAG_SET(globals->candidate_flag, ngbr_rc.row, ngbr_rc.col);
  1090. globals->candidate_count++;
  1091. }
  1092. else {
  1093. FLAG_UNSET(globals->candidate_flag, ngbr_rc.row, ngbr_rc.col);
  1094. globals->candidate_count--;
  1095. }
  1096. }
  1097. }
  1098. }
  1099. }
  1100. } while (n--);
  1101. }
  1102. return TRUE;
  1103. }
  1104. int fetch_reg_stats(int row, int col, struct reg_stats *rs,
  1105. struct globals *globals)
  1106. {
  1107. struct reg_stats *rs_found;
  1108. if (rs->id <= 0)
  1109. G_fatal_error("Invalid region id %d", rs->id);
  1110. if ((rs_found = rgtree_find(globals->reg_tree, rs)) != NULL) {
  1111. memcpy(rs->mean, rs_found->mean, globals->datasize);
  1112. memcpy(rs->sum, rs_found->sum, globals->datasize);
  1113. rs->count = rs_found->count;
  1114. return 1;
  1115. }
  1116. calculate_reg_stats(row, col, rs, globals);
  1117. return 2;
  1118. }
  1119. static int calculate_reg_stats(int row, int col, struct reg_stats *rs,
  1120. struct globals *globals)
  1121. {
  1122. int ret = 0;
  1123. G_debug(4, "calculate_reg_stats()");
  1124. if (rs->id <= 0)
  1125. G_fatal_error("Invalid region id %d", rs->id);
  1126. segment_get(&globals->bands_seg, (void *)globals->bands_val,
  1127. row, col);
  1128. rs->count = 1;
  1129. memcpy(rs->sum, globals->bands_val, globals->datasize);
  1130. if (globals->min_reg_size < 3)
  1131. ret = 1;
  1132. else if (globals->min_reg_size == 3) {
  1133. int n, rid;
  1134. struct rc ngbr_rc;
  1135. int neighbors[8][2];
  1136. globals->find_neighbors(row, col, neighbors);
  1137. n = globals->nn - 1;
  1138. do {
  1139. ngbr_rc.row = neighbors[n][0];
  1140. ngbr_rc.col = neighbors[n][1];
  1141. if (ngbr_rc.row < globals->row_min || ngbr_rc.row >= globals->row_max ||
  1142. ngbr_rc.col < globals->col_min || ngbr_rc.col >= globals->col_max) {
  1143. continue;
  1144. }
  1145. if ((FLAG_GET(globals->null_flag, ngbr_rc.row, ngbr_rc.col)) == 0) {
  1146. segment_get(&globals->rid_seg, (void *) &rid,
  1147. ngbr_rc.row, ngbr_rc.col);
  1148. if (rid == rs->id) {
  1149. /* update region stats */
  1150. rs->count++;
  1151. /* only one other neighbor can have the same ID */
  1152. /* break; */
  1153. }
  1154. }
  1155. } while (n--);
  1156. if (rs->count > 2)
  1157. G_fatal_error(_("Region size is larger than 2: %d"), rs->count);
  1158. ret = 2;
  1159. }
  1160. else if (globals->min_reg_size > 3) {
  1161. /* rs->id must be set */
  1162. struct RB_TREE *rc_check_tree; /* cells already checked */
  1163. int n, rid;
  1164. struct rc ngbr_rc, next;
  1165. struct rclist rilist;
  1166. int neighbors[8][2];
  1167. int no_check;
  1168. /* go through region, spreading outwards from head */
  1169. rclist_init(&rilist);
  1170. rc_check_tree = rbtree_create(compare_rc, sizeof(struct rc));
  1171. ngbr_rc.row = row;
  1172. ngbr_rc.col = col;
  1173. rbtree_insert(rc_check_tree, &ngbr_rc);
  1174. next.row = row;
  1175. next.col = col;
  1176. do {
  1177. G_debug(5, "find_pixel_neighbors for row: %d , col %d",
  1178. next.row, next.col);
  1179. globals->find_neighbors(next.row, next.col, neighbors);
  1180. n = globals->nn - 1;
  1181. do {
  1182. ngbr_rc.row = neighbors[n][0];
  1183. ngbr_rc.col = neighbors[n][1];
  1184. no_check = (ngbr_rc.row < globals->row_min ||
  1185. ngbr_rc.row >= globals->row_max ||
  1186. ngbr_rc.col < globals->col_min ||
  1187. ngbr_rc.col >= globals->col_max);
  1188. if (!no_check) {
  1189. if ((FLAG_GET(globals->null_flag, ngbr_rc.row, ngbr_rc.col)) == 0) {
  1190. /* already checked ? */
  1191. if (!rbtree_find(rc_check_tree, &ngbr_rc)) {
  1192. /* not yet checked, don't check it again */
  1193. rbtree_insert(rc_check_tree, &ngbr_rc);
  1194. segment_get(&globals->rid_seg, (void *) &rid,
  1195. ngbr_rc.row, ngbr_rc.col);
  1196. if (rid == rs->id) {
  1197. /* want to check this neighbor's neighbors */
  1198. rclist_add(&rilist, ngbr_rc.row, ngbr_rc.col);
  1199. /* update region stats */
  1200. rs->count++;
  1201. }
  1202. }
  1203. }
  1204. }
  1205. } while (n--);
  1206. } while (rclist_drop(&rilist, &next));
  1207. /* clean up */
  1208. rbtree_destroy(rc_check_tree);
  1209. rclist_destroy(&rilist);
  1210. ret = 3;
  1211. }
  1212. /* band mean */
  1213. if (rs->count == 1)
  1214. memcpy(rs->mean, rs->sum, globals->datasize);
  1215. else {
  1216. int i = globals->nbands - 1;
  1217. do {
  1218. rs->mean[i] = rs->sum[i] / rs->count;
  1219. } while (i--);
  1220. }
  1221. if (rs->count >= globals->min_reg_size)
  1222. G_fatal_error(_("Region of size %d should be in search tree"),
  1223. rs->count);
  1224. return ret;
  1225. }