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                                  &reg_first,
323                                  &reg_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 (&reg_first, &reg_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