create_isegs.c 43 KB

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