GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-87d2d42d3b
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 *Signature to initialize
12  * \param nbands band (imagery group member) count
13  */
14 int 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 
30 int I_new_signature(struct Signature *S)
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  sprintf(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 *Signature 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;
77  S->semantic_labels = 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  */
88 int I_read_one_signature(FILE *fd, struct Signature *S)
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 pointer to FILE*
143  * \param pointer to struct Signature *S
144  *
145  * \return 1 on success, -1 on failure
146  */
147 int I_read_signatures(FILE *fd, struct Signature *S)
148 {
149  int ver, n, pos;
150  char c, prev;
151  char semantic_label[GNAME_MAX];
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';
182  S->semantic_labels[n] = G_store(semantic_label);
183  n++;
184  }
185  S->nbands = n;
186  break;
187  }
188  if (c == ' ') {
189  semantic_label[pos] = '\0';
190  S->semantic_labels[n] = G_store(semantic_label);
191  n++;
192  /* [n] is 0 based thus: (n + 1) */
193  S->semantic_labels = (char **)G_realloc(S->semantic_labels,
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 pointer to FILE*
241  * \param pointer to struct Signature *S
242  *
243  * \return always 1
244  */
245 int I_write_signatures(FILE *fd, struct Signature *S)
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 *Signature existing signatures to check & sort
318  * \param *Ref 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;
329  char **group_semantic_labels, **mismatches, **new_semantic_labels;
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--;) {
340  group_semantic_labels[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--;) {
367  if (S->semantic_labels[i] && group_semantic_labels[j] &&
368  !strcmp(S->semantic_labels[i], group_semantic_labels[j])) {
369  if (complete) {
370  /* Reorder pointers to existing strings only */
371  new_semantic_labels[j] = S->semantic_labels[i];
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])
401  strcat(mismatches[0], 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]) {
411  if (group_semantic_labels[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';
421  if (group_semantic_labels[j])
422  strcat(mismatches[1], group_semantic_labels[j]);
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]) {
437  new_vars[c][new_order[b1]][new_order[b2]] =
438  S->sig[c].var[b1][b2];
439  }
440  else {
441  new_vars[c][new_order[b2]][new_order[b1]] =
442  S->sig[c].var[b1][b2];
443  }
444  }
445  }
446  }
447 
448  /* Replace values in struct with ordered ones */
449  memcpy(S->semantic_labels, new_semantic_labels,
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--;)
461  free(group_semantic_labels[j]);
462  free(group_semantic_labels);
463  free(new_order);
464  free(match1);
465  free(match2);
466  free(new_semantic_labels);
467  for (unsigned int c = S->nsigs; c--;) {
468  free(new_means[c]);
469  for (unsigned int i = S->nbands; i--;)
470  free(new_vars[c][i]);
471  free(new_vars[c]);
472  }
473  free(new_means);
474  free(new_vars);
475 
476  if (mc1 || mc2) {
477  return mismatches;
478  }
479  free(mismatches);
480  return NULL;
481 }
#define NULL
Definition: ccmath.h:32
#define G_realloc(p, n)
Definition: defs/gis.h:96
#define G_calloc(m, n)
Definition: defs/gis.h:95
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:94
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:191
#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
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_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
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
char name[INAME_LEN]
Definition: imagery.h:20
char mapset[INAME_LEN]
Definition: imagery.h:21
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