1 /**********************************************************
2 * Version $Id$
3 *********************************************************/
4
5 ///////////////////////////////////////////////////////////
6 // //
7 // SAGA //
8 // //
9 // System for Automated Geoscientific Analyses //
10 // //
11 // Tool Library //
12 // Grid_Filter //
13 // //
14 //-------------------------------------------------------//
15 // //
16 // connect_analysis.c //
17 // //
18 // Copyright (C) 2013 by //
19 // HfT Stuttgart //
20 // //
21 //-------------------------------------------------------//
22 // //
23 // This file is part of 'SAGA - System for Automated //
24 // Geoscientific Analyses'. SAGA is free software; you //
25 // can redistribute it and/or modify it under the terms //
26 // of the GNU General Public License as published by the //
27 // Free Software Foundation, either version 2 of the //
28 // License, or (at your option) any later version. //
29 // //
30 // SAGA is distributed in the hope that it will be //
31 // useful, but WITHOUT ANY WARRANTY; without even the //
32 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
33 // PARTICULAR PURPOSE. See the GNU General Public //
34 // License for more details. //
35 // //
36 // You should have received a copy of the GNU General //
37 // Public License along with this program; if not, see //
38 // <http://www.gnu.org/licenses/>. //
39 // //
40 //-------------------------------------------------------//
41 // //
42 // e-mail: johannes.engels@hft-stuttgart.de //
43 // //
44 // contact: Johannes Engels //
45 // Hochschule fuer Technik Stuttgart //
46 // Schellingstr. 24 //
47 // 70174 Stuttgart //
48 // Germany //
49 // //
50 ///////////////////////////////////////////////////////////
51
52 //---------------------------------------------------------
53
54
55 ///////////////////////////////////////////////////////////
56 // //
57 // //
58 // //
59 ///////////////////////////////////////////////////////////
60
61 //---------------------------------------------------------
62 #include "connect_analysis.h"
63
64 extern "C" {
65 #include "geodesic_morph_rec/storeorg.h"
66 #include "geodesic_morph_rec/combcontour.h"
67 }
68
69 //---------------------------------------------------------
70 #define RUN_TOOL(LIBRARY, TOOL, CONDITION) {\
71 bool bResult;\
72 SG_RUN_TOOL(bResult, LIBRARY, TOOL, CONDITION)\
73 if( !bResult ) return( false );\
74 }
75
76 #define SET_PARAMETER(IDENTIFIER, VALUE) pTool->Get_Parameters()->Set_Parameter(SG_T(IDENTIFIER), VALUE)
77
78 ///////////////////////////////////////////////////////////
79 // //
80 // //
81 // //
82 ///////////////////////////////////////////////////////////
83
84 //---------------------------------------------------------
Cconnectivity_analysis(void)85 Cconnectivity_analysis::Cconnectivity_analysis(void)
86 {
87 Set_Name (_TL("Connectivity Analysis"));
88
89 Set_Author (SG_T("HfT Stuttgart (c) 2013"));
90
91 Set_Description (_TW(
92 "Connectivity analysis of a binary input image according to \n"
93 "Burger, W., Burge, M.: Digitale Bildverarbeitung. "
94 "Springer Verlag 2006, p.208.\n"
95 "Output consists in a symbolic image of the connected foreground regions "
96 "and a shape of the borders of the foreground regions (outer and inner "
97 "borders). The shape may contain alternatively the centers or the corners "
98 "of the border pixels. Optionally, the regions which have contact with "
99 "the image borders can be removed together with their border shapes. \n"
100 "In addition, an optional morphological filter (erosion-binary reconstruction) "
101 "can be applied to the input image first. \n\n"
102 ));
103
104 Parameters.Add_Grid (NULL,
105 "INPUT_GRID",
106 _TL ("Input Binary Grid"),
107 _TL ("Binary input image for the connectivity analysis"),
108 PARAMETER_INPUT);
109
110 Parameters.Add_Grid (NULL,
111 "FILTERED_MASK",
112 _TL("Filtered Image"),
113 _TL("Morphologically filtered binary mask"),
114 PARAMETER_OUTPUT_OPTIONAL,
115 true,
116 SG_DATATYPE_Char);
117
118 Parameters.Add_Value (NULL,
119 "FILTER",
120 _TL ("Apply Filter?"),
121 _TL ("Apply a filter (erosion - binary reconstruction) to the input image "),
122 PARAMETER_TYPE_Bool,
123 true);
124
125 Parameters.Add_Value (Parameters("FILTER"),
126 "SIZE",
127 _TL ("Filter Size (Radius)"),
128 _TL ("Filter size (radius in grid cells)"),
129 PARAMETER_TYPE_Int,
130 3);
131
132 // Parameters.Add_Grid_Output(NULL, "SYMBOLIC_IMAGE", _TL("Symbolic Image"), _TL("The final symbolic image"));
133
134 Parameters.Add_Grid (NULL,
135 "SYMBOLIC_IMAGE",
136 _TL("Symbolic Image"),
137 _TL("The final symbolic image"),
138 PARAMETER_OUTPUT);
139
140 Parameters.Add_Shapes (NULL,
141 "OUTLINES",
142 _TL("Outlines"),
143 _TL("Polygon outlines of object regions"),
144 PARAMETER_OUTPUT,
145 SHAPE_TYPE_Polygon);
146
147 Parameters.Add_Value (NULL,
148 "BORDER_PIXEL_CENTERS",
149 _TL ("Pixel Centers?"),
150 _TL ("Should the output shapes contain the centers of the border pixels instead of the corners?"),
151 PARAMETER_TYPE_Bool,
152 false);
153
154 Parameters.Add_Value (NULL,
155 "REMOVE_MARGINAL_REGIONS",
156 _TL ("Remove Border Regions?"),
157 _TL ("Remove regions which have contact with (are adjacent to) the image borders?"),
158 PARAMETER_TYPE_Bool,
159 false);
160
161 }
162
163 ///////////////////////////////////////////////////////////
164 // //
165 // //
166 // //
167 ///////////////////////////////////////////////////////////
168
On_Execute(void)169 bool Cconnectivity_analysis::On_Execute(void)
170 {
171 CSG_Grid *pinpgrid, *bingrid, *symb_grid, *hgrid;
172 CSG_Shapes *pOutlines;
173
174 bool filter, corners_centers, remove_marginal_regions;
175 unsigned short numrows;
176 unsigned short numcols;
177 unsigned char center;
178 double xmin;
179 double ymin;
180 short interm_grid_created;
181 simple_REGIONC_list *reg_first;
182 simple_REGIONC_list *reg_last;
183 simple_REGIONC_list *reg_curr;
184
185 pinpgrid = Parameters ("INPUT_GRID")->asGrid();
186 bingrid = Parameters ("FILTERED_MASK")->asGrid();
187 filter = Parameters ("FILTER")->asBool();
188 corners_centers = Parameters ("BORDER_PIXEL_CENTERS")->asBool();
189 remove_marginal_regions = Parameters ("REMOVE_MARGINAL_REGIONS")->asBool();
190 pOutlines = Parameters("OUTLINES")->asShapes();
191 symb_grid = Parameters ("SYMBOLIC_IMAGE")->asGrid();
192 CSG_String sName = pOutlines->Get_Name();
193 pOutlines->Destroy();
194 pOutlines->Set_Name(sName);
195 pOutlines->Add_Field(SG_T("ID"), SG_DATATYPE_Int);
196
197 numrows=pinpgrid->Get_NY()+2;
198 numcols=pinpgrid->Get_NX()+2;
199 // xmin=pinpgrid->Get_XMin()-2*pinpgrid->Get_Cellsize();
200 // ymin=pinpgrid->Get_YMin()-2*pinpgrid->Get_Cellsize();
201
202 xmin=pinpgrid->Get_XMin();
203 ymin=pinpgrid->Get_YMin();
204
205 unsigned char **bin_image;
206 long **symb_image;
207
208 if (corners_centers)
209 center = 1;
210 else
211 center = 0;
212
213 bin_image = (unsigned char **) matrix_all_alloc (numrows, numcols, 'U', 0);
214 symb_image = (long **) matrix_all_alloc (numrows, numcols, 'L', 0);
215
216 interm_grid_created = 0;
217
218 //SG_Free(bin_image);
219 //CSG_Grid *pTmp = new CSG_Grid();
220 //delete pTmp;
221
222 if (filter)
223 {
224 if (bingrid == NULL)
225 {
226 SG_UI_Msg_Add(_TL("Filtered mask will be created automatically ..."), true);
227
228 bingrid = SG_Create_Grid(SG_DATATYPE_Char,
229 pinpgrid->Get_NX(),
230 pinpgrid->Get_NY(),
231 pinpgrid->Get_Cellsize(),
232 pinpgrid->Get_XMin(),
233 pinpgrid->Get_YMin());
234
235 if (bingrid == NULL)
236 {
237 SG_UI_Msg_Add_Error(_TL("Unable to create filtered mask grid!"));
238 matrix_all_free ((void **) bin_image);
239 matrix_all_free ((void **) symb_image);
240
241 return (false);
242 }
243
244 Parameters("FILTERED_MASK")->Set_Value(bingrid);
245 interm_grid_created = 1;
246 }
247
248
249 //-----------------------------------------------------
250 RUN_TOOL("grid_filter" , 13,
251 SET_PARAMETER("INPUT_GRID" , pinpgrid)
252 && SET_PARAMETER("OUTPUT_GRID" , bingrid)
253 && SET_PARAMETER("RADIUS" , Parameters ("SIZE")->asInt())
254 )
255
256 hgrid = bingrid;
257 }
258 else
259 {
260 hgrid = pinpgrid;
261 }
262
263 for (int y = 0; y < hgrid->Get_NY () && Set_Progress(y, hgrid->Get_NY()); y++)
264 {
265 for (int x = 0; x < hgrid->Get_NX(); x++)
266 {
267 if (hgrid->is_NoData(x,y))
268 bin_image[y+1][x+1] = 0;
269 else
270 bin_image[y+1][x+1] = hgrid->asChar(x,y);
271 }
272 }
273
274
275 // Here the regions are removed which have contact with the image margins;
276 // this is achieved by a region growing
277
278 if (remove_marginal_regions)
279 {
280 for (int y = 1; y < numrows - 1; y++)
281 {
282 if (bin_image [y][1] != 0)
283 background_region_growing (bin_image, numrows, numcols, y, 1);
284
285 if (bin_image [y][numcols - 2] != 0)
286 background_region_growing (bin_image, numrows, numcols, y, numcols-2);
287 }
288
289 for (int x = 1; x < numcols - 1; x++)
290 {
291 if (bin_image [1][x] != 0)
292 background_region_growing (bin_image, numrows, numcols, 1, x);
293
294 if (bin_image [numrows-2][x] != 0)
295 background_region_growing (bin_image, numrows, numcols, numrows-2, x);
296 }
297
298 if (filter)
299 {
300 for (int y = 0; y < bingrid->Get_NY (); y++)
301 {
302 #pragma omp parallel for
303 for (int x = 0; x < bingrid->Get_NX(); x++)
304 {
305 bingrid->Set_Value(x, y, bin_image[y+1][x+1]);
306 }
307 }
308 }
309 }
310
311 if (interm_grid_created)
312 bingrid->Destroy();
313
314
315 // The function which does the proper work:
316 // computation of the symbolic image, construction of the border chains (shapes)
317
318 comb_contour_region_marking (numrows,
319 numcols,
320 bin_image,
321 symb_image,
322 ®_first,
323 ®_last,
324 center);
325
326
327 for (int y = 0; y < symb_grid->Get_NY () && Set_Progress(y, symb_grid->Get_NY()); y++)
328 {
329 #pragma omp parallel for
330 for (int x = 0; x < symb_grid->Get_NX(); x++)
331 {
332 symb_grid->Set_Value(x, y, symb_image[y+1][x+1]);
333 }
334 }
335
336
337 // Here the shapes are generated
338
339 int iPolygon;
340
341 for (iPolygon = 0, reg_curr = reg_first; reg_curr != NULL; reg_curr = reg_curr -> next, iPolygon++)
342 {
343 CSG_Shape *pShape = pOutlines->Add_Shape();
344
345 pShape->Set_Value(0, iPolygon); // set ID field (= first field in table) to polygon ID
346
347 for (simple_PIXELC_list *pix_curr = reg_curr->first_pix; pix_curr != NULL; pix_curr = pix_curr->next)
348 {
349 TSG_Point point = symb_grid->Get_System().Get_Grid_to_World(pix_curr->col - 1, pix_curr->row - 1);
350 pShape->Add_Point(point, 0);
351 }
352
353 int iHoles;
354 simple_INNER_REGION_list *inner_curr;
355
356 for (iHoles=0, inner_curr = reg_curr->inner_first;
357 iHoles < reg_curr->num_holes;
358 iHoles++, inner_curr = inner_curr->next)
359 {
360 for (simple_PIXELC_list *pix_curr = inner_curr->first_pix; pix_curr != NULL; pix_curr = pix_curr->next)
361 {
362 TSG_Point point = symb_grid->Get_System().Get_Grid_to_World(pix_curr->col - 1, pix_curr->row - 1);
363 pShape->Add_Point(point, iHoles+1);
364 }
365 }
366
367 if (!corners_centers)
368 shift_shape (pShape, -Get_Cellsize()/2.0, -Get_Cellsize()/2.0);
369 }
370
371 matrix_all_free ((void **) bin_image);
372 matrix_all_free ((void **) symb_image);
373 free_regions (®_first, ®_last);
374
375 return( true );
376 }
377
378
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)379 int Cconnectivity_analysis::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
380 {
381 if ( pParameter->Cmp_Identifier(SG_T("FILTER")) )
382 {
383 pParameters->Get_Parameter("SIZE")->Set_Enabled(pParameter->asBool());
384 pParameters->Get_Parameter("FILTERED_MASK")->Set_Enabled(pParameter->asBool());
385 }
386
387 return (1);
388 }
389
390
shift_shape(CSG_Shape * pShape,double dx,double dy)391 void Cconnectivity_analysis::shift_shape (CSG_Shape *pShape, double dx, double dy)
392 {
393 for (int iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
394 {
395 for (int iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
396 {
397 TSG_Point point = pShape->Get_Point(iPoint, iPart);
398 point.x = point.x + dx;
399 point.y = point.y + dy;
400 pShape->Set_Point(point, iPoint, iPart);
401 } // iPoint
402 } // iPart
403 }
404
405
406 ///////////////////////////////////////////////////////////
407 // //
408 // //
409 // //
410 ///////////////////////////////////////////////////////////
411
412 //---------------------------------------------------------
413