Skip to content

Commit

Permalink
Make band references optional to simplify generation of signatures (#…
Browse files Browse the repository at this point in the history
…1866)

Bandrefs: make band references optional to simplify generation of signature files. This brings back pre GRASS 8 like functionality by allowing to classify only the same imagery group if band references are missing.
  • Loading branch information
marisn committed Sep 23, 2021
1 parent 6e63699 commit e41c3e9
Show file tree
Hide file tree
Showing 14 changed files with 62 additions and 62 deletions.
30 changes: 11 additions & 19 deletions imagery/i.cluster/i.cluster.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,15 @@ <h2>DESCRIPTION</h2>
set to their default values.

<p>
All raster maps used to generate signature file must have band reference
set. Use <em><a href="r.support.html">r.support</a></em> to set
For all raster maps used to generate signature file it is recommended
to have band reference set.
Use <em><a href="r.support.html">r.support</a></em> to set
band references of each member of the imagery group.
Signatures generated for one scene are suitable for classification
of other scenes as long as they consist of same raster bands
(band references match).
(band references match). If band references are not set, it will be
possible to use obtained signature file to classify only the same
imagery group used for generating signatures.

<h3>Parameters:</h3>

Expand Down Expand Up @@ -263,22 +266,11 @@ <h2>EXAMPLE</h2>
a LANDSAT subscene in North Carolina:

<div class="code"><pre>
## Prepare imagery for classification
# Skip this step if your rasters already have band references defined
# Define band references for all LANDSAT bands in mapset PERMANENT
g.mapset mapset=PERMANENT
r.support map=lsat7_2002_10 bandref=TM7_1
r.support map=lsat7_2002_20 bandref=TM7_2
r.support map=lsat7_2002_30 bandref=TM7_3
r.support map=lsat7_2002_40 bandref=TM7_4
r.support map=lsat7_2002_50 bandref=TM7_5
r.support map=lsat7_2002_61 bandref=TM7_61
r.support map=lsat7_2002_62 bandref=TM7_62
r.support map=lsat7_2002_70 bandref=TM7_7
r.support map=lsat7_2002_80 bandref=TM7_8
g.mapset mapset=user1 # replace user1 with your mapset name

## Real work starts here
# To use signature file for classification of a different group, set
# band references for each group member. In this example we'll create
# signature file suitable only for the same group and thus band
# references are not mandatory.

# Set computational region to match the scene
g.region raster=lsat7_2002_10 -p

Expand Down
5 changes: 1 addition & 4 deletions imagery/i.cluster/open_files.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ int open_files(void)
G_warning(_("Raster map <%s> do not exists in subgroup <%s>"),
G_fully_qualified_name(name, mapset), subgroup);
}
bandref = Rast_read_bandref(ref.file[n].name, ref.file[n].mapset);
if (!bandref)
G_fatal_error(_("Raster map <%s@%s> lacks band reference"),
ref.file[n].name, ref.file[n].mapset);
bandref = Rast_get_bandref_or_name(ref.file[n].name, ref.file[n].mapset);
bandrefs[n] = G_store(bandref);
}
if (missing)
Expand Down
5 changes: 1 addition & 4 deletions imagery/i.gensig/openfiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ int openfiles(struct parms *parms, struct files *files, struct Signature *S)
files->band_fd[n] =
Rast_open_old(Ref.file[n].name, Ref.file[n].mapset);
files->band_cell[n] = Rast_allocate_d_buf();
bandref = Rast_read_bandref(Ref.file[n].name, Ref.file[n].mapset);
if (!bandref)
G_fatal_error(_("Raster map <%s@%s> lacks band reference"),
Ref.file[n].name, Ref.file[n].mapset);
bandref = Rast_get_bandref_or_name(Ref.file[n].name, Ref.file[n].mapset);
S->bandrefs[n] = G_store(bandref);
}

Expand Down
9 changes: 6 additions & 3 deletions imagery/i.gensigset/i.gensigset.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ <h2>DESCRIPTION</h2>
final classified map.

<p>
All raster maps used to generate signature file must have band reference
set. Use <em><a href="r.support.html">r.support</a></em> to set
For all raster maps used to generate signature file it is recommended
to have band reference set.
Use <em><a href="r.support.html">r.support</a></em> to set
band references of each member of the imagery group.
Signatures generated for one scene are suitable for classification
of other scenes as long as they consist of same raster bands
(band references match).
(band references match). If band references are not set, it will be
possible to use obtained signature file to classify only the same
imagery group used for generating signatures.

<p>
An usage example can be found in <a href="i.smap.html">i.smap</a>
Expand Down
5 changes: 1 addition & 4 deletions imagery/i.gensigset/openfiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ int openfiles(struct parms *parms, struct files *files, struct SigSet *S)
files->band_fd[n] =
Rast_open_old(Ref.file[n].name, Ref.file[n].mapset);
files->band_cell[n] = Rast_allocate_d_buf();
bandref = Rast_read_bandref(Ref.file[n].name, Ref.file[n].mapset);
if (!bandref)
G_fatal_error(_("Raster map <%s@%s> lacks band reference"),
Ref.file[n].name, Ref.file[n].mapset);
bandref = Rast_get_bandref_or_name(Ref.file[n].name, Ref.file[n].mapset);
S->bandrefs[n] = G_store(bandref);
}

Expand Down
21 changes: 5 additions & 16 deletions imagery/i.smap/i.smap.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,11 @@ <h2>EXAMPLE</h2>
Supervised classification of LANDSAT scene (complete NC location)

<div class="code"><pre>
## Prepare imagery for classification
# Skip this step if your rasters already have band references defined
# Define band references for all LANDSAT bands in mapset PERMANENT
g.mapset mapset=PERMANENT
r.support map=lsat7_2002_10 bandref=TM7_1
r.support map=lsat7_2002_20 bandref=TM7_2
r.support map=lsat7_2002_30 bandref=TM7_3
r.support map=lsat7_2002_40 bandref=TM7_4
r.support map=lsat7_2002_50 bandref=TM7_5
r.support map=lsat7_2002_61 bandref=TM7_61
r.support map=lsat7_2002_62 bandref=TM7_62
r.support map=lsat7_2002_70 bandref=TM7_7
r.support map=lsat7_2002_80 bandref=TM7_8
g.mapset mapset=user1 # replace user1 with your mapset name

## Real work starts here
# To use signature file for classification of a different group, set
# band references for each group member. In this example we'll create
# signature file suitable only for the same group and thus band
# references are not mandatory.

# Align computation region to the scene
g.region raster=lsat7_2002_10 -p

Expand Down
1 change: 1 addition & 0 deletions include/grass/defs/raster.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ DCELL Rast_get_d_value(const void *, RASTER_MAP_TYPE);
char *Rast_read_units(const char *, const char *);
char *Rast_read_vdatum(const char *, const char *);
char *Rast_read_bandref(const char *, const char *);
char *Rast_get_bandref_or_name(const char *, const char *);
void Rast_write_units(const char *, const char *);
void Rast_write_vdatum(const char *, const char *);
void Rast_write_bandref(const char *, const char *);
Expand Down
7 changes: 1 addition & 6 deletions lib/imagery/iclass_signatures.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,7 @@ int I_iclass_init_signatures(struct Signature *sigs, struct Ref *refer)

I_init_signatures(sigs, refer->nfiles);
for (unsigned int i = refer->nfiles; i--;) {
sigs->bandrefs[i] = Rast_read_bandref(refer->file[i].name, refer->file[i].mapset);
if (!sigs->bandrefs[i]) {
G_warning(_("Raster map <%s@%s> lacks band reference"),
refer->file[i].name, refer->file[i].mapset);
return 0;
}
sigs->bandrefs[i] = Rast_get_bandref_or_name(refer->file[i].name, refer->file[i].mapset);
}

return 1;
Expand Down
2 changes: 1 addition & 1 deletion lib/imagery/sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ char **I_sort_signatures_by_bandref(struct Signature *S, const struct Ref *R) {
/* Obtain group band references */
group_bandrefs = (char **)G_malloc(R->nfiles * sizeof(char *));
for (unsigned int j = R->nfiles; j--;) {
group_bandrefs[j] = Rast_read_bandref(R->file[j].name, R->file[j].mapset);
group_bandrefs[j] = Rast_get_bandref_or_name(R->file[j].name, R->file[j].mapset);
}

/* If lengths are not equal, there will be a mismatch */
Expand Down
3 changes: 1 addition & 2 deletions lib/imagery/sigset.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,7 @@ char **I_SortSigSetByBandref(struct SigSet *S, const struct Ref *R)
/* Obtain group band references */
group_bandrefs = (char **)G_malloc(R->nfiles * sizeof(char *));
for (unsigned int j = R->nfiles; j--;) {
group_bandrefs[j] =
Rast_read_bandref(R->file[j].name, R->file[j].mapset);
group_bandrefs[j] = Rast_get_bandref_or_name(R->file[j].name, R->file[j].mapset);
}

/* If lengths are not equal, there will be a mismatch */
Expand Down
2 changes: 1 addition & 1 deletion lib/imagery/testsuite/test_imagery_sigfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ def test_missing_bandref(self):
+ "<band reference missing>,<band reference missing>,"
+ "<band reference missing>",
)
self.assertEqual(ref_err, "The_Doors,<band reference missing>")
self.assertEqual(ref_err, f"The_Doors,{self.map3}")

# Clean up memory to help track memory leaks when run by valgrind
S.bandrefs[0] = None
Expand Down
2 changes: 1 addition & 1 deletion lib/imagery/testsuite/test_imagery_sigsetfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def test_missing_bandref(self):
+ "<band reference missing>,<band reference missing>,"
+ "<band reference missing>",
)
self.assertEqual(ref_err, "The_Doors,<band reference missing>")
self.assertEqual(ref_err, f"The_Doors,{self.map3}")

# Clean up memory to help track memory leaks when run by valgrind
I_free_group_ref(ctypes.byref(R))
Expand Down
17 changes: 17 additions & 0 deletions lib/raster/raster_metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ char *Rast_read_bandref(const char *name, const char *mapset)
return misc_read_line("bandref", name, mapset);
}

/*!
* \brief Get a raster map band reference or fall back to its name
*
* Use this function if a band reference is needed but not mandated.
*
* \param name raster map name
* \param mapset mapset name
*
* \return string representing band reference or map name
*/
char *Rast_get_bandref_or_name(const char *name, const char *mapset) {
char *buff;

buff = Rast_read_bandref(name, mapset);
return buff ? buff : G_store(name);
}

/*!
* \brief Write a string into a raster's band reference metadata file
*
Expand Down
15 changes: 14 additions & 1 deletion lib/raster/testsuite/test_raster_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
from grass.pygrass import utils

from grass.lib.gis import G_remove_misc
from grass.lib.raster import Rast_legal_bandref, Rast_read_bandref, Rast_write_bandref
from grass.lib.raster import (
Rast_legal_bandref,
Rast_read_bandref,
Rast_get_bandref_or_name,
Rast_write_bandref,
)


class RastLegalBandIdTestCase(TestCase):
Expand Down Expand Up @@ -95,6 +100,14 @@ def test_write_bandref(self):
ret = utils.decode(Rast_read_bandref(self.map, self.mapset))
self.assertEqual(ret, self.bandref)

def test_get_bandref_or_name(self):
G_remove_misc("cell_misc", "bandref", self.map)
ret = utils.decode(Rast_get_bandref_or_name(self.map, self.mapset))
self.assertEqual(ret, self.map)
Rast_write_bandref(self.map, self.bandref)
ret = utils.decode(Rast_get_bandref_or_name(self.map, self.mapset))
self.assertEqual(ret, self.bandref)


if __name__ == "__main__":
test()

0 comments on commit e41c3e9

Please sign in to comment.