123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- /*
- ****************************************************************************
- *
- * MODULE: r.composite
- * AUTHOR(S): Glynn Clements - glynn.clements@virgin.net
- * PURPOSE: Combine red, green and blue layers into a single
- * layer using a quantisation of the RGB color space.
- * Using Floyd-Steinberg dithering
- *
- * COPYRIGHT: (C) 2001-2008 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.
- *
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- struct band
- {
- struct Option *opt_name;
- struct Option *opt_levels;
- char *name;
- int levels;
- int maxlev;
- int offset;
- int file;
- int type;
- int size;
- unsigned char *array[3];
- short *floyd[2];
- struct Colors colors;
- };
- static char *const color_names[3] = { "red", "green", "blue" };
- static struct band B[3];
- static int closest;
- static void make_color_cube(struct Colors *colors);
- static int quantize(int c, int x);
- int main(int argc, char **argv)
- {
- struct GModule *module;
- struct Option *opt_out;
- struct Option *opt_lev;
- struct Flag *flg_d;
- struct Flag *flg_c;
- int dither;
- char *out_name;
- int out_file;
- CELL *out_array;
- struct Colors out_colors;
- int levels;
- int atrow, atcol;
- struct Cell_head window;
- unsigned char *dummy, *nulls;
- int i, j;
- struct History history;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("composite"));
- G_add_keyword("RGB");
- module->description =
- _("Combines red, green and blue raster maps into "
- "a single composite raster map.");
- for (i = 0; i < 3; i++) {
- struct Option *opt;
- char buff[80];
- B[i].opt_name = opt = G_define_standard_option(G_OPT_R_INPUT);
- sprintf(buff, "%s", color_names[i]);
- opt->key = G_store(buff);
- opt->answer = NULL;
- sprintf(buff, _("Name of raster map to be used for <%s>"),
- color_names[i]);
- opt->description = G_store(buff);
- }
- opt_lev = G_define_option();
- opt_lev->key = "levels";
- opt_lev->type = TYPE_INTEGER;
- opt_lev->required = NO;
- opt_lev->options = "1-256";
- opt_lev->answer = "32";
- opt_lev->description =
- _("Number of levels to be used for each component");
- opt_lev->guisection = _("Levels");
- for (i = 0; i < 3; i++) {
- struct Option *opt;
- char buff[80];
- B[i].opt_levels = opt = G_define_option();
- sprintf(buff, "level_%s", color_names[i]);
- opt->key = G_store(buff);
- opt->type = TYPE_INTEGER;
- opt->required = NO;
- opt->options = "1-256";
- sprintf(buff, _("Number of levels to be used for <%s>"),
- color_names[i]);
- opt->description = G_store(buff);
- opt->guisection = _("Levels");
- }
- opt_out = G_define_standard_option(G_OPT_R_OUTPUT);
- flg_d = G_define_flag();
- flg_d->key = 'd';
- flg_d->description = _("Dither");
- flg_c = G_define_flag();
- flg_c->key = 'c';
- flg_c->description = _("Use closest color");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- levels = atoi(opt_lev->answer);
- dither = flg_d->answer;
- closest = flg_c->answer;
- /* read in current window */
- G_get_window(&window);
- dummy = G_malloc(window.cols);
- nulls = G_malloc(window.cols);
- for (i = 0; i < 3; i++) {
- struct band *b = &B[i];
- /* Get name of layer to be used */
- b->name = b->opt_name->answer;
- /* Make sure map is available */
- b->file = Rast_open_old(b->name, "");
- b->type = Rast_get_map_type(b->file);
- b->size = Rast_cell_size(b->type);
- /* Reading color lookup table */
- if (Rast_read_colors(b->name, "", &b->colors) == -1)
- G_fatal_error(_("Unable to read color file of raster map <%s>"), b->name);
- for (j = 0; j < 3; j++)
- b->array[j] = (i == j)
- ? G_malloc(window.cols)
- : dummy;
- b->levels = b->opt_levels->answer ? atoi(b->opt_levels->answer)
- : levels;
- b->maxlev = b->levels - 1;
- b->offset = 128 / b->maxlev;
- if (dither)
- for (j = 0; j < 2; j++)
- b->floyd[j] = G_calloc(window.cols + 2, sizeof(short));
- }
- /* open output files */
- out_name = opt_out->answer;
- out_file = Rast_open_c_new(out_name);
- out_array = Rast_allocate_c_buf();
- /* Make color table */
- make_color_cube(&out_colors);
- G_message(_("Writing raster map <%s>..."), out_name);
- for (atrow = 0; atrow < window.rows; atrow++) {
- G_percent(atrow, window.rows, 2);
- for (i = 0; i < 3; i++) {
- struct band *b = &B[i];
- Rast_get_row_colors(b->file, atrow, &b->colors,
- b->array[0],
- b->array[1], b->array[2], nulls);
- if (dither) {
- short *tmp = b->floyd[0];
- b->floyd[0] = b->floyd[1];
- for (atcol = 0; atcol < window.cols + 2; atcol++)
- tmp[atcol] = 0;
- b->floyd[1] = tmp;
- }
- }
- for (atcol = 0; atcol < window.cols; atcol++) {
- int val[3];
- if (nulls[atcol]) {
- Rast_set_c_null_value(&out_array[atcol], 1);
- continue;
- }
- for (i = 0; i < 3; i++) {
- struct band *b = &B[i];
- int v = b->array[i][atcol];
- if (dither) {
- int r, w, d;
- v += b->floyd[0][atcol + 1] / 16;
- v = (v < 0) ? 0 : (v > 255) ? 255 : v;
- r = quantize(i, v);
- w = r * 255 / b->maxlev;
- d = v - w;
- b->floyd[0][atcol + 2] += 7 * d;
- b->floyd[1][atcol + 0] += 3 * d;
- b->floyd[1][atcol + 1] += 5 * d;
- b->floyd[1][atcol + 2] += 1 * d;
- val[i] = r;
- }
- else
- val[i] = quantize(i, v);
- }
- out_array[atcol] = (CELL)
- (val[2] * B[1].levels + val[1]) * B[0].levels + val[0];
- }
- Rast_put_row(out_file, out_array, CELL_TYPE);
- }
- G_percent(window.rows, window.rows, 1);
- /* Close the input files */
- for (i = 0; i < 3; i++)
- Rast_close(B[i].file);
- /* Close the output file */
- Rast_close(out_file);
- Rast_write_colors(out_name, G_mapset(), &out_colors);
- Rast_short_history(out_name, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(out_name, &history);
- G_done_msg(_("Raster map <%s> created."), out_name);
- exit(EXIT_SUCCESS);
- }
- static int quantize(int c, int x)
- {
- return closest
- ? (x + B[c].offset) * B[c].maxlev / 256 : x * B[c].levels / 256;
- }
- static void make_color_cube(struct Colors *colors)
- {
- int nr = B[0].levels;
- int ng = B[1].levels;
- int nb = B[2].levels;
- int mr = B[0].maxlev;
- int mg = B[1].maxlev;
- int mb = B[2].maxlev;
- int g, b;
- int i = 0;
- Rast_init_colors(colors);
- G_message(_("Creating color table for output raster map..."));
- for (b = 0; b < nb; b++) {
- G_percent(b, nb, 5);
- for (g = 0; g < ng; g++) {
- int blu = b * 255 / mb;
- int grn = g * 255 / mg;
- CELL i0 = i;
- CELL i1 = i + mr;
- Rast_add_c_color_rule(&i0, 0, grn, blu,
- &i1, 255, grn, blu, colors);
- i += nr;
- }
- }
- G_percent(nb, nb, 1);
- }
|