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