123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- /*!
- \file lib/imagery/iclass_statistics.c
- \brief Imagery library - functions for wx.iclass
- Computation based on training areas for supervised classification.
- Based on i.class module (GRASS 6).
- Computing statistical values (mean, min, max, ...) from given area
- perimeters for each band.
- Copyright (C) 1999-2007, 2011 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- \author David Satnik, Central Washington University (original author)
- \author Markus Neteler <neteler itc.it> (i.class module)
- \author Bernhard Reiter <bernhard intevation.de> (i.class module)
- \author Brad Douglas <rez touchofmadness.com>(i.class module)
- \author Glynn Clements <glynn gclements.plus.com> (i.class module)
- \author Hamish Bowman <hamish_b yahoo.com> (i.class module)
- \author Jan-Oliver Wagner <jan intevation.de> (i.class module)
- \author Anna Kratochvilova <kratochanna gmail.com> (rewriting for wx.iclass)
- \author Vaclav Petras <wenzeslaus gmail.com> (rewriting for wx.iclass)
- */
- #include <math.h>
- #include <grass/imagery.h>
- #include <grass/glocale.h>
- #include <grass/colors.h>
- #include "iclass_local_proto.h"
- /*!
- \brief Initialize statistics.
- \param[out] statistics pointer to statistics structure
- \param category category (class)
- \param name class name
- \param color class color
- \param nstd standard deviation
- */
- void I_iclass_init_statistics(IClass_statistics * statistics, int category,
- const char *name, const char *color, float nstd)
- {
- G_debug(4, "init_statistics() category=%d, name=%s, color=%s, nstd=%f",
- category, name, color, nstd);
- statistics->cat = category;
- statistics->name = G_store(name);
- statistics->color = G_store(color);
- statistics->nstd = nstd;
- statistics->ncells = 0;
- statistics->nbands = 0;
- statistics->band_min = NULL;
- statistics->band_max = NULL;
- statistics->band_sum = NULL;
- statistics->band_mean = NULL;
- statistics->band_stddev = NULL;
- statistics->band_product = NULL;
- statistics->band_histo = NULL;
- statistics->band_range_min = NULL;
- statistics->band_range_max = NULL;
- }
- /*!
- \brief Allocate space for statistics.
- \param statistics pointer to statistics structure
- \param nbands number of band files
- */
- void alloc_statistics(IClass_statistics * statistics, int nbands)
- {
- int i;
- G_debug(4, "alloc_statistics()");
- statistics->nbands = nbands;
- statistics->band_min = (int *)G_calloc(nbands, sizeof(int));
- statistics->band_max = (int *)G_calloc(nbands, sizeof(int));
- statistics->band_sum = (float *)G_calloc(nbands, sizeof(float));
- statistics->band_mean = (float *)G_calloc(nbands, sizeof(float));
- statistics->band_stddev = (float *)G_calloc(nbands, sizeof(float));
- statistics->band_product = (float **)G_calloc(nbands, sizeof(float *));
- statistics->band_histo = (int **)G_calloc(nbands, sizeof(int *));
- statistics->band_range_min = (int *)G_calloc(nbands, sizeof(int));
- statistics->band_range_max = (int *)G_calloc(nbands, sizeof(int));
- for (i = 0; i < nbands; i++) {
- statistics->band_product[i] =
- (float *)G_calloc(nbands, sizeof(float));
- statistics->band_histo[i] = (int *)G_calloc(MAX_CATS, sizeof(int));
- }
- }
- /*!
- \brief Free space allocated for statistics attributes.
- Frees all allocated arrays in statistics structure.
- \param statistics pointer to statistics structure
- */
- void I_iclass_free_statistics(IClass_statistics * statistics)
- {
- int i;
- G_debug(4, "free_statistics()");
- G_free((char *) statistics->name);
- G_free((char *) statistics->color);
- G_free(statistics->band_min);
- G_free(statistics->band_max);
- G_free(statistics->band_sum);
- G_free(statistics->band_mean);
- G_free(statistics->band_stddev);
- G_free(statistics->band_range_max);
- G_free(statistics->band_range_min);
- for (i = 0; i < statistics->nbands; i++) {
- G_free(statistics->band_histo[i]);
- G_free(statistics->band_product[i]);
- }
- G_free(statistics->band_histo);
- G_free(statistics->band_product);
- }
- /*!
- \brief Calculate statistics for all training areas.
- \param statistics pointer to statistics structure
- \param perimeters list of all area perimeters
- \param band_buffer buffer to read band rows into
- \param band_fd band files descriptors
- \return 1 on succes
- \return 0 on failure
- */
- int make_all_statistics(IClass_statistics * statistics,
- IClass_perimeter_list * perimeters,
- CELL ** band_buffer, int *band_fd)
- {
- int i, b, b2, nbands;
- float mean_value, stddev_value;
- G_debug(5, "make_all_statistics()");
- nbands = statistics->nbands;
- for (b = 0; b < nbands; b++) {
- statistics->band_sum[b] = 0.0;
- statistics->band_min[b] = MAX_CATS;
- statistics->band_max[b] = 0;
- for (b2 = 0; b2 < nbands; b2++)
- statistics->band_product[b][b2] = 0.0;
- for (b2 = 0; b2 < MAX_CATS; b2++)
- statistics->band_histo[b][b2] = 0;
- }
- for (i = 0; i < perimeters->nperimeters; i++) {
- if (!make_statistics
- (statistics, &perimeters->perimeters[i], band_buffer, band_fd)) {
- return 0;
- }
- }
- for (b = 0; b < statistics->nbands; b++) {
- mean_value = mean(statistics, b);
- stddev_value = stddev(statistics, b);
- statistics->band_stddev[b] = stddev_value;
- statistics->band_mean[b] = mean_value;
- band_range(statistics, b);
- }
- return 1;
- }
- /*!
- \brief Calculate statistics for one training area.
- \param[out] statistics pointer to statistics structure
- \param perimeter area perimeter
- \param band_buffer buffer to read band rows into
- \param band_fd band files descriptors
- \return 1 on succes
- \return 0 on failure
- */
- int make_statistics(IClass_statistics * statistics,
- IClass_perimeter * perimeter, CELL ** band_buffer,
- int *band_fd)
- {
- int b, b2;
- int value;
- int i;
- int x0, x1;
- int x, y;
- int ncells;
- int nbands;
- G_debug(5, "make_statistics()");
- nbands = statistics->nbands;
- if (perimeter->npoints % 2) {
- G_warning(_("prepare_signature: outline has odd number of points."));
- return 0;
- }
- ncells = 0;
- for (i = 1; i < perimeter->npoints; i += 2) {
- y = perimeter->points[i].y;
- if (y != perimeter->points[i - 1].y) {
- G_warning(_("prepare_signature: scan line %d has odd number of points."),
- (i + 1) / 2);
- return 0;
- }
- read_band_row(band_buffer, band_fd, nbands, y);
- x0 = perimeter->points[i - 1].x - 1;
- x1 = perimeter->points[i].x - 1;
- if (x0 > x1) {
- G_warning(_("signature: perimeter points out of order."));
- return 0;
- }
- for (x = x0; x <= x1; x++) {
- ncells++; /* count interior points */
- for (b = 0; b < nbands; b++) {
- value = band_buffer[b][x];
- G_debug(5, "make_statistics() band: %d, read value: %d (max: %d)",
- b, value, MAX_CATS);
- if (value < 0 || value > MAX_CATS - 1) {
- G_warning(_("Data error preparing signatures: value (%d) > num of cats (%d)"),
- value, MAX_CATS);
- return 0;
- }
- statistics->band_sum[b] += value; /* sum for means */
- statistics->band_histo[b][value]++; /* histogram */
- if (statistics->band_min[b] > value)
- statistics->band_min[b] = value; /* absolute min, max */
- if (statistics->band_max[b] < value) {
- statistics->band_max[b] = value;
- G_debug(5,
- "make_statistics() statistics->band_max[%d]: %d",
- b, statistics->band_max[b]);
- }
- for (b2 = 0; b2 <= b; b2++) /* products for variance */
- statistics->band_product[b][b2] +=
- value * band_buffer[b2][x];
- }
- }
- }
- statistics->ncells += ncells;
- return 1;
- }
- /*!
- \brief Create raster map based on statistics.
- \param statistics pointer to statistics structure
- \param band_buffer buffer to read band rows into
- \param band_fd band files descriptors
- \param raster_name name of new raster map
- */
- void create_raster(IClass_statistics * statistics, CELL ** band_buffer,
- int *band_fd, const char *raster_name)
- {
- int fd;
- CELL *buffer;
- int n;
- int col;
- int nbands;
- int row, nrows, ncols;
- struct Colors raster_colors;
- int r, g, b;
- int cell_in_ranges;
- nbands = statistics->nbands;
- /* build new raster based on current signature and Nstd */
- fd = Rast_open_c_new(raster_name);
- buffer = Rast_allocate_c_buf();
- nrows = Rast_window_rows();
- ncols = Rast_window_cols();
- for (row = 0; row < nrows; row++) {
- read_band_row(band_buffer, band_fd, nbands, row);
- for (col = 0; col < ncols; col++) {
- buffer[col] = (CELL) 0;
- cell_in_ranges = 1;
- for (n = 0; n < nbands; n++) {
- if (band_buffer[n][col] < statistics->band_range_min[n] ||
- band_buffer[n][col] > statistics->band_range_max[n]) {
- /* out of at least 1 range */
- cell_in_ranges = 0;
- }
- }
- if (cell_in_ranges) {
- /* if in range do the assignment */
- buffer[col] = (CELL) 1;
- }
- }
- Rast_put_row(fd, buffer, CELL_TYPE);
- }
- Rast_close(fd);
- /* generate and write the color table for the mask */
- Rast_init_colors(&raster_colors);
- G_str_to_color(statistics->color, &r, &g, &b);
- Rast_set_c_color((CELL) 1, r, g, b, &raster_colors);
- Rast_write_colors(raster_name, G_mapset(), &raster_colors);
- }
- /* helpers */
- /*!
- \brief Helper function for computing min and max range in one band.
- Computing min and max range value (distance from mean
- dependent on number od std ddevs).
- \param statistics pointer to statistics structure
- \param band band index
- */
- void band_range(IClass_statistics * statistics, int band)
- {
- float dist;
- dist = statistics->nstd * statistics->band_stddev[band];
- statistics->band_range_min[band] =
- statistics->band_mean[band] - dist + 0.5;
- statistics->band_range_max[band] =
- statistics->band_mean[band] + dist + 0.5;
- }
- /*!
- \brief Helper function for computing mean.
- Computing mean value of cell category values
- in one band within training area.
- \param statistics pointer to statistics structure
- \param band band index
- \return mean value
- */
- float mean(IClass_statistics * statistics, int band)
- {
- return statistics->band_sum[band] / statistics->ncells;
- }
- /*!
- \brief Helper function for standard deviation.
- Computing standard deviation of cell category values
- in one band within training area.
- \param statistics pointer to statistics structure
- \param band band index
- \return standard deviation
- */
- float stddev(IClass_statistics * statistics, int band)
- {
- return sqrt(var(statistics, band, band));
- }
- /*!
- \brief Helper function for computing variance.
- Computing variance of cell category values
- in one band within training area.
- \param statistics pointer to statistics structure
- \param band1 band index
- \param band2 band index
- \return variance
- \see var_signature
- */
- float var(IClass_statistics * statistics, int band1, int band2)
- {
- float product;
- float mean1, mean2;
- int n;
- product = statistics->band_product[band1][band2];
- mean1 = mean(statistics, band1);
- mean2 = mean(statistics, band2);
- n = statistics->ncells;
- return product / n - mean1 * mean2;
- }
- /*!
- \brief Helper function for computing variance for signature file.
- Computing variance of cell category values
- in one band within training area. Variance is computed
- in special way.
- \param statistics pointer to statistics structure
- \param band1 band index
- \param band2 band index
- \return variance
- \see var
- \todo verify the computation
- */
- float var_signature(IClass_statistics * statistics, int band1, int band2)
- {
- float product;
- float sum1, sum2;
- int n;
- product = statistics->band_product[band1][band2];
- sum1 = statistics->band_sum[band1];
- sum2 = statistics->band_sum[band2];
- n = statistics->ncells;
- return (product - sum1 * sum2 / n) / (n - 1);
- }
- /* getters */
- /*!
- \brief Get number of bands.
- \param statistics pointer to statistics structure
- \param[out] nbands number of bands
- */
- void I_iclass_statistics_get_nbands(IClass_statistics * statistics,
- int *nbands)
- {
- *nbands = statistics->nbands;
- }
- /*!
- \brief Get category (class).
- \param statistics pointer to statistics structure
- \param[out] cat category
- */
- void I_iclass_statistics_get_cat(IClass_statistics * statistics, int *cat)
- {
- *cat = statistics->cat;
- }
- /*!
- \brief Get category (class) name.
- \note \a name is pointer to already allocated
- const char * in \a statistics.
- You should not free it.
- \param statistics pointer to statistics structure
- \param[out] name category name
- */
- void I_iclass_statistics_get_name(IClass_statistics * statistics,
- const char **name)
- {
- *name = statistics->name;
- }
- /*!
- \brief Get category (class) color.
- \note \a color is pointer to already allocated
- const char * in \a statistics.
- You should not free it.
- \param statistics pointer to statistics structure
- \param[out] color category color
- */
- void I_iclass_statistics_get_color(IClass_statistics * statistics,
- const char **color)
- {
- *color = statistics->color;
- }
- /*!
- \brief Get number of cells in training areas.
- \param statistics pointer to statistics structure
- \param[out] ncells number of cells
- */
- void I_iclass_statistics_get_ncells(IClass_statistics * statistics,
- int *ncells)
- {
- *ncells = statistics->ncells;
- }
- /*!
- \brief Get the multiplier of standard deviation.
- \param statistics pointer to statistics structure
- \param[out] nstd multiplier of standard deviation
- */
- void I_iclass_statistics_get_nstd(IClass_statistics * statistics, float *nstd)
- {
- *nstd = statistics->nstd;
- }
- /*!
- \brief Set the multiplier of standard deviation.
- \param statistics pointer to statistics structure
- \param nstd multiplier of standard deviation
- */
- void I_iclass_statistics_set_nstd(IClass_statistics * statistics, float nstd)
- {
- statistics->nstd = nstd;
- }
- /*!
- \brief Get minimum value in band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] min minimum value
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_min(IClass_statistics * statistics, int band,
- int *min)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *min = statistics->band_min[band];
- return 1;
- }
- /*!
- \brief Get maximum value in band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] max maximum value
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_max(IClass_statistics * statistics, int band,
- int *max)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *max = statistics->band_max[band];
- return 1;
- }
- /*!
- \brief Get sum of values in band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] sum sum
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_sum(IClass_statistics * statistics, int band,
- float *sum)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *sum = statistics->band_sum[band];
- return 1;
- }
- /*!
- \brief Get mean of cell category values in band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] mean mean
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_mean(IClass_statistics * statistics, int band,
- float *mean)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *mean = statistics->band_mean[band];
- return 1;
- }
- /*!
- \brief Get standard deviation of cell category values in band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] stddev standard deviation
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_stddev(IClass_statistics * statistics, int band,
- float *stddev)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *stddev = statistics->band_stddev[band];
- return 1;
- }
- /*!
- \brief Get histogram value in band.
- Each band has one value for each raster cell category.
- Value is number of cells in category.
- \param statistics pointer to statistics structure
- \param band band index
- \param cat raster cell category
- \param[out] value number of cells in category
- \return 1 on success
- \return 0 band index or cell category value out of range
- */
- int I_iclass_statistics_get_histo(IClass_statistics * statistics, int band,
- int cat, int *value)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- if (cat >= MAX_CATS) {
- G_warning(_("Cell category value out of range"));
- return 0;
- }
- *value = statistics->band_histo[band][cat];
- return 1;
- }
- /*!
- \brief Get product value
- Product value of two bands is sum of products
- of cell category values of two bands.
- Only cells from training areas are taken into account.
- \param statistics statistics object
- \param band1 index of first band
- \param band2 index of second band
- \param[out] value product value
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_product(IClass_statistics * statistics, int band1,
- int band2, float *value)
- {
- if (band1 >= statistics->nbands || band2 >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *value = statistics->band_product[band1][band2];
- return 1;
- }
- /*!
- \brief Get minimum cell value based on mean and standard deviation for band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] min minimum value
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_range_min(IClass_statistics * statistics,
- int band, int *min)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *min = statistics->band_range_min[band];
- return 1;
- }
- /*!
- \brief Get maximum cell value based on mean and standard deviation for band.
- \param statistics pointer to statistics structure
- \param band band index
- \param[out] max maximum value
- \return 1 on success
- \return 0 band index out of range
- */
- int I_iclass_statistics_get_range_max(IClass_statistics * statistics,
- int band, int *max)
- {
- if (band >= statistics->nbands) {
- G_warning(_("Band index out of range"));
- return 0;
- }
- *max = statistics->band_range_max[band];
- return 1;
- }
|