GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
sig.c
Go to the documentation of this file.
1#include <stdlib.h>
2#include <string.h>
3#include <grass/imagery.h>
4#include <grass/glocale.h>
5
6/*!
7 * \brief Initialize struct Signature before use
8 *
9 * No need to call before calling I_read_signatures.
10 *
11 * \param S *Signature to initialize
12 * \param nbands band (imagery group member) count
13 */
14int I_init_signatures(struct Signature *S, int nbands)
15{
16 S->nbands = nbands;
17 S->semantic_labels = (char **)G_malloc(nbands * sizeof(char **));
18 for (int i = 0; i < nbands; i++)
19 S->semantic_labels[i] = NULL;
20 S->nsigs = 0;
21 S->have_oclass = 0;
22 S->sig = NULL;
23 S->title[0] = 0;
24
25 return 0;
26}
27
28#define SIG struct One_Sig
29
31{
32 int n;
33 int i;
34
35 i = S->nsigs++;
36 S->sig = (SIG *)G_realloc(S->sig, S->nsigs * sizeof(SIG));
37
38 S->sig[i].mean = (double *)G_calloc(S->nbands, sizeof(double));
39 S->sig[i].var = (double **)G_calloc(S->nbands, sizeof(double *));
40
41 for (n = 0; n < S->nbands; n++)
42 S->sig[i].var[n] = (double *)G_calloc(S->nbands, sizeof(double));
43
44 S->sig[i].status = 0;
45 S->sig[i].have_color = 0;
46 snprintf(S->sig[i].desc, sizeof(S->sig[i].desc), "Class %d", i + 1);
47 return S->nsigs;
48}
49
50/*!
51 * \brief Free memory allocated for struct Signature
52 *
53 * One must call I_init_signatures() to re-use struct after it has been
54 * passed to this function.
55 *
56 * \param S Signature struct to free
57 *
58 * \return always 0
59 */
61{
62 int n;
63 int i;
64
65 for (i = 0; i < S->nsigs; i++) {
66 for (n = 0; n < S->nbands; n++)
67 free(S->sig[i].var[n]);
68 free(S->sig[i].var);
69 free(S->sig[i].mean);
70 }
71 free(S->sig);
72 for (n = 0; n < S->nbands; n++)
73 free(S->semantic_labels[n]);
75
76 S->sig = NULL;
78 S->nbands = 0;
79 S->nsigs = 0;
80 S->title[0] = '\0';
81
82 return 0;
83}
84
85/*!
86 * \brief Internal function for I_read_signatures
87 */
89{
90 int n;
91 int i;
92 struct One_Sig *s;
93
94 while ((i = fgetc(fd)) != EOF)
95 if (i == '#')
96 break;
97 if (i != '#')
98 return 0;
99
100 i = I_new_signature(S);
101 s = &S->sig[i - 1];
102
103 I_get_to_eol(s->desc, sizeof(s->desc), fd);
104 G_strip(s->desc);
105
106 if (fscanf(fd, "%d", &s->npoints) != 1)
107 return -1;
108
109 if (S->have_oclass && fscanf(fd, "%d", &s->oclass) != 1)
110 return -1;
111
112 for (i = 0; i < S->nbands; i++) {
113 if (fscanf(fd, "%lf", &s->mean[i]) != 1)
114 return -1;
115 }
116
117 for (i = 0; i < S->nbands; i++) {
118 for (n = 0; n <= i; n++) {
119 if (fscanf(fd, "%lf", &s->var[i][n]) != 1)
120 return -1;
121 s->var[n][i] = s->var[i][n]; /* added 28 aug 91 */
122 }
123 }
124 if (fscanf(fd, "%f%f%f", &s->r, &s->g, &s->b) == 3 && s->r >= 0.0 &&
125 s->r <= 1.0 && s->g >= 0.0 && s->g <= 1.0 && s->b >= 0.0 && s->b <= 1.0)
126 s->have_color = 1;
127
128 s->status = 1;
129 return 1;
130}
131
132/*!
133 * \brief Read signatures from file
134 *
135 * File stream should be opened in advance by call to
136 * I_fopen_signature_file_old()
137 * It is up to caller to fclose the file stream afterwards.
138 *
139 * There is no need to initialize struct Signature in advance, as this
140 * function internally calls I_init_signatures.
141 *
142 * \param fd pointer to FILE*
143 * \param S pointer to struct Signature *S
144 *
145 * \return 1 on success, -1 on failure
146 */
148{
149 int ver, n, pos;
150 char c, prev;
152
153 I_init_signatures(S, 0);
154 S->title[0] = 0;
155 /* File of signatures must start with its version number */
156 if (fscanf(fd, "%d", &ver) != 1) {
157 G_warning(_("Invalid signature file"));
158 return -1;
159 }
160 /* Current version number is 2 */
161 if (!(ver == 1 || ver == 2)) {
162 G_warning(_("Invalid signature file version"));
163 return -1;
164 }
165
166 /* Goto title line and strip initial # */
167 while ((c = (char)fgetc(fd)) != EOF)
168 if (c == '#')
169 break;
170 I_get_to_eol(S->title, sizeof(S->title), fd);
171 G_strip(S->title);
172
173 /* Read semantic labels and count them to set nbands */
174 n = 0;
175 pos = 0;
176 S->semantic_labels =
177 (char **)G_realloc(S->semantic_labels, (n + 1) * sizeof(char **));
178 while ((c = (char)fgetc(fd)) != EOF) {
179 if (c == '\n') {
180 if (prev != ' ') {
181 semantic_label[pos] = '\0';
183 n++;
184 }
185 S->nbands = n;
186 break;
187 }
188 if (c == ' ') {
189 semantic_label[pos] = '\0';
191 n++;
192 /* [n] is 0 based thus: (n + 1) */
194 (n + 1) * sizeof(char **));
195 pos = 0;
196 prev = c;
197 continue;
198 }
199 /* Semantic labels are limited to GNAME_MAX - 1 + \0 in length;
200 * n is 0-based */
201 if (pos == (GNAME_MAX - 2)) {
202 G_warning(_("Invalid signature file: semantic label length limit "
203 "exceeded"));
204 return -1;
205 }
206 semantic_label[pos] = c;
207 pos++;
208 prev = c;
209 }
210
211 if (!(S->nbands > 0)) {
212 G_warning(_("Signature file does not contain bands"));
213 return -1;
214 }
215
216 /* Read marker of original class value presence */
217 if (ver >= 2 && fscanf(fd, "%d", &S->have_oclass) != 1) {
218 G_warning(_("Invalid signature file: Original class value presence not "
219 "readable"));
220 return -1;
221 }
222
223 while ((n = I_read_one_signature(fd, S)) == 1)
224 ;
225
226 if (n < 0)
227 return -1;
228 if (S->nsigs == 0)
229 return -1;
230 return 1;
231}
232
233/*!
234 * \brief Write signatures to file
235 *
236 * File stream should be opened in advance by call to
237 * I_fopen_signature_file_new()
238 * It is up to caller to fclose the file stream afterwards.
239 *
240 * \param fd to FILE*
241 * \param S to struct Signature *S
242 *
243 * \return always 1
244 */
246{
247 int k;
248 int n;
249 int i;
250 struct One_Sig *s;
251
252 /* Version of signatures file structure.
253 * Increment if file structure changes.
254 */
255 fprintf(fd, "2\n");
256 /* Title of signatures */
257 fprintf(fd, "#%s\n", S->title);
258 /* A list of space separated semantic labels for each
259 * raster map used to generate sigs. */
260 for (k = 0; k < S->nbands; k++) {
261 fprintf(fd, "%s ", S->semantic_labels[k]);
262 }
263 fprintf(fd, "\n");
264 /* Should reader look for original class values? */
265 fprintf(fd, "%d\n", S->have_oclass);
266 /* A signature for each target class */
267 for (k = 0; k < S->nsigs; k++) {
268 s = &S->sig[k];
269 if (s->status != 1)
270 continue;
271 /* Label for each class represented by this signature */
272 fprintf(fd, "#%s\n", s->desc);
273 /* Point count used to generate signature */
274 fprintf(fd, "%d\n", s->npoints);
275 /* The original value used for this class */
276 if (S->have_oclass)
277 fprintf(fd, "%d\n", s->oclass);
278 /* Values are in the same order as semantic labels */
279 for (i = 0; i < S->nbands; i++)
280 fprintf(fd, "%g ", s->mean[i]);
281 fprintf(fd, "\n");
282 for (i = 0; i < S->nbands; i++) {
283 for (n = 0; n <= i; n++)
284 fprintf(fd, "%g ", s->var[i][n]);
285 fprintf(fd, "\n");
286 }
287 if (s->have_color)
288 fprintf(fd, "%g %g %g\n", s->r, s->g, s->b);
289 }
290 return 1;
291}
292
293/*!
294 * \brief Reorder struct Signature to match imagery group member order
295 *
296 * The function will check for semantic label match between signature struct
297 * and imagery group.
298 *
299 * In the case of a complete semantic label match, values of passed in
300 * struct Signature are reordered to match the order of imagery group items.
301 *
302 * If all semantic labels are not identical (in
303 * arbitrary order), function will return two dimensional array with
304 * comma separated list of:
305 * - [0] semantic labels present in the signature struct but
306 * absent in the imagery group
307 * - [1] semantic labels present in the imagery group but
308 * absent in the signature struct
309 *
310 * If no mismatch of simantic labels for signatures or imagery group are
311 * detected (== all are present in the other list), a NULL value will be
312 * returned in the particular list of mismatches (not an empty string).
313 * For example:
314 * \code if (ret && ret[1]) printf("List of imagery group bands without
315 * signatures: %s\n, ret[1]); \endcode
316 *
317 * \param S existing signatures to check & sort
318 * \param R group reference
319 *
320 * \return NULL successfully sorted
321 * \return err_array two comma separated lists of mismatches
322 */
324 const struct Ref *R)
325{
326 unsigned int total, complete;
327 unsigned int *match1, *match2, mc1, mc2, *new_order;
328 double **new_means, ***new_vars;
330
331 /* Safety measure. Untranslated as this should not happen in production! */
332 if (S->nbands < 1 || R->nfiles < 1)
333 G_fatal_error("Programming error. Invalid length structs passed to "
334 "I_sort_signatures_by_semantic_label(%d, %d);",
335 S->nbands, R->nfiles);
336
337 /* Obtain group semantic labels */
338 group_semantic_labels = (char **)G_malloc(R->nfiles * sizeof(char *));
339 for (unsigned int j = R->nfiles; j--;) {
342 }
343
344 /* If lengths are not equal, there will be a mismatch */
345 complete = S->nbands == R->nfiles;
346
347 /* Initialize match tracker */
348 new_order = (unsigned int *)G_malloc(S->nbands * sizeof(unsigned int));
349 match1 = (unsigned int *)G_calloc(S->nbands, sizeof(unsigned int));
350 match2 = (unsigned int *)G_calloc(R->nfiles, sizeof(unsigned int));
351
352 /* Allocate memory for temporary storage of sorted values */
353 new_semantic_labels = (char **)G_malloc(S->nbands * sizeof(char *));
354 new_means = (double **)G_malloc(S->nsigs * sizeof(double *));
355 // new_vars[S.sig[x]][band1][band1]
356 new_vars = (double ***)G_malloc(S->nsigs * sizeof(double **));
357 for (unsigned int c = S->nsigs; c--;) {
358 new_means[c] = (double *)G_malloc(S->nbands * sizeof(double));
359 new_vars[c] = (double **)G_malloc(S->nbands * sizeof(double *));
360 for (unsigned int i = S->nbands; i--;)
361 new_vars[c][i] = (double *)G_malloc(S->nbands * sizeof(double));
362 }
363
364 /* Obtain order of matching items */
365 for (unsigned int j = R->nfiles; j--;) {
366 for (unsigned int i = S->nbands; i--;) {
369 if (complete) {
370 /* Reorder pointers to existing strings only */
372 new_order[i] = j;
373 }
374 /* Keep a track of matching items for error reporting */
375 match1[i] = 1;
376 match2[j] = 1;
377 break;
378 }
379 }
380 }
381
382 /* Check for semantic label mismatch */
383 mc1 = mc2 = 0;
384 mismatches = (char **)G_malloc(2 * sizeof(char **));
385 mismatches[0] = NULL;
386 mismatches[1] = NULL;
387 total = 1;
388 for (unsigned int i = 0; i < (unsigned int)S->nbands; i++) {
389 if (!match1[i]) {
390 if (S->semantic_labels[i])
391 total = total + strlen(S->semantic_labels[i]);
392 else
393 total = total + 24;
394 mismatches[0] =
395 (char *)G_realloc(mismatches[0], total * sizeof(char *));
396 if (mc1)
397 strcat(mismatches[0], ",");
398 else
399 mismatches[0][0] = '\0';
400 if (S->semantic_labels[i])
402 else
403 strcat(mismatches[0], "<semantic label missing>");
404 mc1++;
405 total = total + 1;
406 }
407 }
408 total = 1;
409 for (unsigned int j = 0; j < (unsigned int)R->nfiles; j++) {
410 if (!match2[j]) {
412 total = total + strlen(group_semantic_labels[j]);
413 else
414 total = total + 24;
415 mismatches[1] =
416 (char *)G_realloc(mismatches[1], total * sizeof(char *));
417 if (mc2)
418 strcat(mismatches[1], ",");
419 else
420 mismatches[1][0] = '\0';
423 else
424 strcat(mismatches[1], "<semantic label missing>");
425 mc2++;
426 total = total + 1;
427 }
428 }
429
430 /* Swap var matrix values in each of classes */
431 if (!mc1 && !mc2) {
432 for (unsigned int c = S->nsigs; c--;) {
433 for (unsigned int b1 = 0; b1 < (unsigned int)S->nbands; b1++) {
434 new_means[c][new_order[b1]] = S->sig[c].mean[b1];
435 for (unsigned int b2 = 0; b2 <= b1; b2++) {
436 if (new_order[b1] > new_order[b2]) {
438 S->sig[c].var[b1][b2];
439 }
440 else {
442 S->sig[c].var[b1][b2];
443 }
444 }
445 }
446 }
447
448 /* Replace values in struct with ordered ones */
450 S->nbands * sizeof(char **));
451 for (unsigned int c = S->nsigs; c--;) {
452 memcpy(S->sig[c].mean, new_means[c], S->nbands * sizeof(double));
453 for (unsigned int i = S->nbands; i--;)
454 memcpy(S->sig[c].var[i], new_vars[c][i],
455 S->nbands * sizeof(double));
456 }
457 }
458
459 /* Clean up */
460 for (unsigned int j = R->nfiles; j--;)
464 G_free(match1);
465 G_free(match2);
467 for (unsigned int c = S->nsigs; c--;) {
468 G_free(new_means[c]);
469 for (unsigned int i = S->nbands; i--;)
470 G_free(new_vars[c][i]);
471 G_free(new_vars[c]);
472 }
475
476 if (mc1 || mc2) {
477 return mismatches;
478 }
480 return NULL;
481}
#define NULL
Definition ccmath.h:32
AMI_err name(char **stream_name)
Definition ami_stream.h:426
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
#define G_realloc(p, n)
Definition defs/gis.h:141
#define G_calloc(m, n)
Definition defs/gis.h:140
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:139
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition strings.c:300
char * G_store(const char *)
Copy string to allocated memory.
Definition strings.c:87
int I_get_to_eol(char *, int, FILE *)
Definition eol.c:13
char * Rast_get_semantic_label_or_name(const char *, const char *)
Get a raster map semantic label or fall back to its name.
#define GNAME_MAX
Definition gis.h:196
#define _(str)
Definition glocale.h:10
int I_write_signatures(FILE *fd, struct Signature *S)
Write signatures to file.
Definition sig.c:245
int I_read_signatures(FILE *fd, struct Signature *S)
Read signatures from file.
Definition sig.c:147
int I_new_signature(struct Signature *S)
Definition sig.c:30
int I_init_signatures(struct Signature *S, int nbands)
Initialize struct Signature before use.
Definition sig.c:14
int I_read_one_signature(FILE *fd, struct Signature *S)
Internal function for I_read_signatures.
Definition sig.c:88
char ** I_sort_signatures_by_semantic_label(struct Signature *S, const struct Ref *R)
Reorder struct Signature to match imagery group member order.
Definition sig.c:323
int I_free_signatures(struct Signature *S)
Free memory allocated for struct Signature.
Definition sig.c:60
#define SIG
Definition sig.c:28
void free(void *)
int status
Definition imagery.h:52
char desc[256]
Definition imagery.h:48
int npoints
Definition imagery.h:49
double * mean
Definition imagery.h:50
double ** var
Definition imagery.h:51
float g
Definition imagery.h:53
float b
Definition imagery.h:53
float r
Definition imagery.h:53
int oclass
Definition imagery.h:55
int have_color
Definition imagery.h:54
Definition imagery.h:24
int nfiles
Definition imagery.h:25
struct Ref_Files * file
Definition imagery.h:26
int have_oclass
Definition imagery.h:62
int nsigs
Definition imagery.h:61
struct One_Sig * sig
Definition imagery.h:64
char ** semantic_labels
Definition imagery.h:60
char title[100]
Definition imagery.h:63
int nbands
Definition imagery.h:59