gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 9e2397a 094/113: Imported recent work in maste


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 9e2397a 094/113: Imported recent work in master, no conflicts
Date: Fri, 16 Apr 2021 10:33:57 -0400 (EDT)

branch: master
commit 9e2397a814f7db1de6a52da91e4fa61b78b41cd9
Merge: b5385f7 55e3617
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Imported recent work in master, no conflicts
    
    There weren't any conflicts in this merge.
---
 NEWS                          |   9 +
 bin/convertt/Makefile.am      |   4 +-
 bin/convertt/args.h           |  28 +++
 bin/convertt/astconvertt.conf |   1 +
 bin/convertt/color.c          | 526 ++++++++++++++++++++++++++++++++++++++++++
 bin/convertt/color.h          |  35 +++
 bin/convertt/convertt.c       |  24 +-
 bin/convertt/main.h           |  13 ++
 bin/convertt/ui.c             | 110 ++++++++-
 bin/convertt/ui.h             |   2 +
 bin/statistics/statistics.c   |  11 +-
 doc/gnuastro.en.html          |   6 +-
 doc/gnuastro.fr.html          |   2 +-
 doc/gnuastro.texi             | 267 ++++++++++++++-------
 lib/convolve.c                |   4 +
 15 files changed, 940 insertions(+), 102 deletions(-)

diff --git a/NEWS b/NEWS
index a46813a..bf2af0a 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,15 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   Arithmetic:
     --onedasimage: write output as an image if it has one dimension, not table.
 
+  ConvertType:
+    --colormap: color map to display a single-channel dataset (for example
+      FITS image) with a range of colors in formats that support color
+      (like JPEG, or PDF). Until now, the only available mapping was
+      grayscale. Now "Hue, Saturation, Value" (HSV) and "SLS" (from SAO
+      DS9) colormaps are also supported.
+    --rgbtohsv: Convert the RGB input channels to HSV (when the output is
+      in FITS format).
+
   Convolve:
     - Convolves 1D arrays (table columns, for example spectra)
       also. Therefore two new options have been added to it: `--column'
diff --git a/bin/convertt/Makefile.am b/bin/convertt/Makefile.am
index 964ae87..2199202 100644
--- a/bin/convertt/Makefile.am
+++ b/bin/convertt/Makefile.am
@@ -31,9 +31,9 @@ bin_PROGRAMS = astconvertt
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
 astconvertt_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
 
-astconvertt_SOURCES = main.c ui.c convertt.c
+astconvertt_SOURCES = main.c ui.c convertt.c color.c
 
-EXTRA_DIST = main.h authors-cite.h args.h ui.h convertt.h
+EXTRA_DIST = main.h authors-cite.h args.h ui.h convertt.h color.h
 
 
 
diff --git a/bin/convertt/args.h b/bin/convertt/args.h
index dbabc4b..39fedda 100644
--- a/bin/convertt/args.h
+++ b/bin/convertt/args.h
@@ -83,6 +83,34 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "colormap",
+      UI_KEY_COLORMAP,
+      "STR[,FLT]",
+      0,
+      "Color map when only a single channel is given.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->colormap,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_strings
+    },
+    {
+      "rgbtohsv",
+      UI_KEY_RGBTOHSV,
+      0,
+      0,
+      "Convert RGB input into HSV (in FITS output)",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->rgbtohsv,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+
 
 
 
diff --git a/bin/convertt/astconvertt.conf b/bin/convertt/astconvertt.conf
index fc3ba04..493bb6a 100644
--- a/bin/convertt/astconvertt.conf
+++ b/bin/convertt/astconvertt.conf
@@ -24,6 +24,7 @@
  widthincm            10.0
  borderwidth          1
  output               jpg
+ colormap             gray
 
 # Flux:
  invert               0
diff --git a/bin/convertt/color.c b/bin/convertt/color.c
new file mode 100644
index 0000000..ac23269
--- /dev/null
+++ b/bin/convertt/color.c
@@ -0,0 +1,526 @@
+/*********************************************************************
+ConvertType - Convert between various types of files.
+ConvertType is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <mohammad@akhlaghi.org>
+Contributing author(s):
+Copyright (C) 2015-2018, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+
+#include <gnuastro/data.h>
+
+#include "main.h"
+
+
+
+
+
+
+
+/***********************************************************************/
+/**************            From mono-channel           *****************/
+/***********************************************************************/
+/* This algorithm is a translation of the primary algorithm in this page:
+https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
 */
+void
+color_from_mono_hsv(struct converttparams *p)
+{
+  int i;
+  gal_data_t *R, *G, *B, *channel;
+  float *r, *g, *b, *f, *fp, min, max;
+  float *params=p->colormap->next->array;
+  float h, s=1, v, hh, ff, P, q, t, h_min, h_max;
+
+  /* Set the input values. */
+  h_min = params[0];
+  h_max = params[1];
+
+  /* Sanity checks. */
+  if(h_min>h_max)
+    error(EXIT_FAILURE, 0, "the minimum angle value (%g) is not smaller "
+          "than the maximum (%f)", h_min, h_max);
+  if(h_min<0)
+    error(EXIT_FAILURE, 0, "the minimum angle (%g) must be larger than 0",
+          h_min);
+  if(h_max>360)
+    error(EXIT_FAILURE, 0, "the maximum angle (%g) must be smaller than "
+          "360", h_max);
+
+  /* Convert the dataset to floating point, then change its range to the
+     given angle values. */
+  gal_type_min(GAL_TYPE_FLOAT32, &max);
+  gal_type_max(GAL_TYPE_FLOAT32, &min);
+  channel=gal_data_copy_to_new_type_free(p->chll, GAL_TYPE_FLOAT32);
+  fp=(f=channel->array)+channel->size;
+  do {if(*f<min) min=*f; if(*f>max) max=*f;} while(++f<fp);
+
+  /* Allocate the three datasets to keep the RGB colors. */
+  R=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   "RED", NULL, "Red color channel.");
+  G=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   "GREEN", NULL, "Green color channel.");
+  B=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   "BLUE", NULL, "Blue color channel.");
+
+  /* Start the conversion. Note that the "Choroma" (`C') is fixed by our
+     definition. */
+  r=R->array;
+  g=G->array;
+  b=B->array;
+  fp=(f=channel->array)+channel->size;
+  do
+    {
+      if(isnan(*f))
+        *r=*g=*b=0.0;
+      else
+        {
+          /* Shift all the values to start from the desired angle. We'll
+             set the "value" (brightness: 0: dark, 1: bright) using the
+             pixel value, then scale it to fix the color. */
+          v=(*f-min) / (max-min);
+          h = v * (h_max-h_min) + h_min;
+          if(h==360) h=0;
+
+          /* Prepare the intermediate values. */
+          hh=h/60;
+          i  = (int)hh;
+          ff = hh - i;
+          P  = v * ( 1.0 -  s );
+          q  = v * ( 1.0 - (s * ff) );
+          t  = v * ( 1.0 - (s * (1.0 - ff) ));
+
+          /* Based on the integer phase, set the r,g,b values. */
+          switch(i)
+            {
+            case 0:          *r=v; *g=t; *b=P; break;
+            case 1:          *r=q; *g=v; *b=P; break;
+            case 2:          *r=P; *g=v; *b=t; break;
+            case 3:          *r=P; *g=q; *b=v; break;
+            case 4:          *r=t; *g=P; *b=v; break;
+            case 5: default: *r=v; *g=P; *b=q; break;
+            }
+        }
+
+      /* Convert the RGB values to 0 and 255.  With the steps above, they
+         are between 0 and 1. */
+      *r++ *= 255;
+      *g++ *= 255;
+      *b++ *= 255;
+    }
+  while(++f<fp);
+
+  /* Convert the type to unsigned char. */
+  R=gal_data_copy_to_new_type_free(R, GAL_TYPE_UINT8);
+  G=gal_data_copy_to_new_type_free(G, GAL_TYPE_UINT8);
+  B=gal_data_copy_to_new_type_free(B, GAL_TYPE_UINT8);
+  p->chll=R;
+  p->chll->next=G;
+  p->chll->next->next=B;
+
+  /* Clean up. */
+  gal_data_free(channel);
+}
+
+
+
+
+
+/* From SAO DS9: */
+void
+color_from_mono_sls(struct converttparams *p)
+{
+  gal_data_t *R, *G, *B, *channel;
+  float *r, *g, *b, *f, *fp, min, max;
+
+  /* Convert the dataset to floating point, then find its minimum and
+     maximum values. */
+  gal_type_min(GAL_TYPE_FLOAT32, &max);
+  gal_type_max(GAL_TYPE_FLOAT32, &min);
+  channel=gal_data_copy_to_new_type_free(p->chll, GAL_TYPE_FLOAT32);
+  fp=(f=channel->array)+channel->size;
+  do {if(*f<min) min=*f; if(*f>max) max=*f;} while(++f<fp);
+
+  /* Allocate the three datasets to keep the RGB colors. */
+  R=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   "RED", NULL, "Red color channel.");
+  G=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   "GREEN", NULL, "Green color channel.");
+  B=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   "BLUE", NULL, "Blue color channel.");
+
+  /* Start the conversion. Note that the "Choroma" (`C') is fixed by our
+     definition. */
+  r=R->array;
+  g=G->array;
+  b=B->array;
+  fp=(f=channel->array)+channel->size;
+  do
+    {
+      if(isnan(*f))
+        *r=*g=*b=0.0;
+      else
+        switch( (int)((*f-min)/(max-min)*200) )
+          {
+          case 0:   *r=0.000000; *g=0.000000; *b=0.000000; break;
+          case 1:   *r=0.043442; *g=0.000000; *b=0.052883; break;
+          case 2:   *r=0.086883; *g=0.000000; *b=0.105767; break;
+          case 3:   *r=0.130325; *g=0.000000; *b=0.158650; break;
+          case 4:   *r=0.173767; *g=0.000000; *b=0.211533; break;
+          case 5:   *r=0.217208; *g=0.000000; *b=0.264417; break;
+          case 6:   *r=0.260650; *g=0.000000; *b=0.317300; break;
+          case 7:   *r=0.304092; *g=0.000000; *b=0.370183; break;
+          case 8:   *r=0.347533; *g=0.000000; *b=0.423067; break;
+          case 9:   *r=0.390975; *g=0.000000; *b=0.475950; break;
+          case 10:  *r=0.434417; *g=0.000000; *b=0.528833; break;
+          case 11:  *r=0.477858; *g=0.000000; *b=0.581717; break;
+          case 12:  *r=0.521300; *g=0.000000; *b=0.634600; break;
+          case 13:  *r=0.506742; *g=0.000000; *b=0.640217; break;
+          case 14:  *r=0.492183; *g=0.000000; *b=0.645833; break;
+          case 15:  *r=0.477625; *g=0.000000; *b=0.651450; break;
+          case 16:  *r=0.463067; *g=0.000000; *b=0.657067; break;
+          case 17:  *r=0.448508; *g=0.000000; *b=0.662683; break;
+          case 18:  *r=0.433950; *g=0.000000; *b=0.668300; break;
+          case 19:  *r=0.419392; *g=0.000000; *b=0.673917; break;
+          case 20:  *r=0.404833; *g=0.000000; *b=0.679533; break;
+          case 21:  *r=0.390275; *g=0.000000; *b=0.685150; break;
+          case 22:  *r=0.375717; *g=0.000000; *b=0.690767; break;
+          case 23:  *r=0.361158; *g=0.000000; *b=0.696383; break;
+          case 24:  *r=0.346600; *g=0.000000; *b=0.702000; break;
+          case 25:  *r=0.317717; *g=0.000000; *b=0.712192; break;
+          case 26:  *r=0.288833; *g=0.000000; *b=0.722383; break;
+          case 27:  *r=0.259950; *g=0.000000; *b=0.732575; break;
+          case 28:  *r=0.231067; *g=0.000000; *b=0.742767; break;
+          case 29:  *r=0.202183; *g=0.000000; *b=0.752958; break;
+          case 30:  *r=0.173300; *g=0.000000; *b=0.763150; break;
+          case 31:  *r=0.144417; *g=0.000000; *b=0.773342; break;
+          case 32:  *r=0.115533; *g=0.000000; *b=0.783533; break;
+          case 33:  *r=0.086650; *g=0.000000; *b=0.793725; break;
+          case 34:  *r=0.057767; *g=0.000000; *b=0.803917; break;
+          case 35:  *r=0.028883; *g=0.000000; *b=0.814108; break;
+          case 36:  *r=0.000000; *g=0.000000; *b=0.824300; break;
+          case 37:  *r=0.000000; *g=0.019817; *b=0.838942; break;
+          case 38:  *r=0.000000; *g=0.039633; *b=0.853583; break;
+          case 39:  *r=0.000000; *g=0.059450; *b=0.868225; break;
+          case 40:  *r=0.000000; *g=0.079267; *b=0.882867; break;
+          case 41:  *r=0.000000; *g=0.099083; *b=0.897508; break;
+          case 42:  *r=0.000000; *g=0.118900; *b=0.912150; break;
+          case 43:  *r=0.000000; *g=0.138717; *b=0.926792; break;
+          case 44:  *r=0.000000; *g=0.158533; *b=0.941433; break;
+          case 45:  *r=0.000000; *g=0.178350; *b=0.956075; break;
+          case 46:  *r=0.000000; *g=0.198167; *b=0.970717; break;
+          case 47:  *r=0.000000; *g=0.217983; *b=0.985358; break;
+          case 48:  *r=0.000000; *g=0.237800; *b=1.000000; break;
+          case 49:  *r=0.000000; *g=0.268533; *b=1.000000; break;
+          case 50:  *r=0.000000; *g=0.299267; *b=1.000000; break;
+          case 51:  *r=0.000000; *g=0.330000; *b=1.000000; break;
+          case 52:  *r=0.000000; *g=0.360733; *b=1.000000; break;
+          case 53:  *r=0.000000; *g=0.391467; *b=1.000000; break;
+          case 54:  *r=0.000000; *g=0.422200; *b=1.000000; break;
+          case 55:  *r=0.000000; *g=0.452933; *b=1.000000; break;
+          case 56:  *r=0.000000; *g=0.483667; *b=1.000000; break;
+          case 57:  *r=0.000000; *g=0.514400; *b=1.000000; break;
+          case 58:  *r=0.000000; *g=0.545133; *b=1.000000; break;
+          case 59:  *r=0.000000; *g=0.575867; *b=1.000000; break;
+          case 60:  *r=0.000000; *g=0.606600; *b=1.000000; break;
+          case 61:  *r=0.000000; *g=0.631733; *b=0.975300; break;
+          case 62:  *r=0.000000; *g=0.656867; *b=0.950600; break;
+          case 63:  *r=0.000000; *g=0.682000; *b=0.925900; break;
+          case 64:  *r=0.000000; *g=0.707133; *b=0.901200; break;
+          case 65:  *r=0.000000; *g=0.732267; *b=0.876500; break;
+          case 66:  *r=0.000000; *g=0.757400; *b=0.851800; break;
+          case 67:  *r=0.000000; *g=0.782533; *b=0.827100; break;
+          case 68:  *r=0.000000; *g=0.807667; *b=0.802400; break;
+          case 69:  *r=0.000000; *g=0.832800; *b=0.777700; break;
+          case 70:  *r=0.000000; *g=0.857933; *b=0.753000; break;
+          case 71:  *r=0.000000; *g=0.883067; *b=0.728300; break;
+          case 72:  *r=0.000000; *g=0.908200; *b=0.703600; break;
+          case 73:  *r=0.000000; *g=0.901908; *b=0.676675; break;
+          case 74:  *r=0.000000; *g=0.895617; *b=0.649750; break;
+          case 75:  *r=0.000000; *g=0.889325; *b=0.622825; break;
+          case 76:  *r=0.000000; *g=0.883033; *b=0.595900; break;
+          case 77:  *r=0.000000; *g=0.876742; *b=0.568975; break;
+          case 78:  *r=0.000000; *g=0.870450; *b=0.542050; break;
+          case 79:  *r=0.000000; *g=0.864158; *b=0.515125; break;
+          case 80:  *r=0.000000; *g=0.857867; *b=0.488200; break;
+          case 81:  *r=0.000000; *g=0.851575; *b=0.461275; break;
+          case 82:  *r=0.000000; *g=0.845283; *b=0.434350; break;
+          case 83:  *r=0.000000; *g=0.838992; *b=0.407425; break;
+          case 84:  *r=0.000000; *g=0.832700; *b=0.380500; break;
+          case 85:  *r=0.000000; *g=0.832308; *b=0.354858; break;
+          case 86:  *r=0.000000; *g=0.831917; *b=0.329217; break;
+          case 87:  *r=0.000000; *g=0.831525; *b=0.303575; break;
+          case 88:  *r=0.000000; *g=0.831133; *b=0.277933; break;
+          case 89:  *r=0.000000; *g=0.830742; *b=0.252292; break;
+          case 90:  *r=0.000000; *g=0.830350; *b=0.226650; break;
+          case 91:  *r=0.000000; *g=0.829958; *b=0.201008; break;
+          case 92:  *r=0.000000; *g=0.829567; *b=0.175367; break;
+          case 93:  *r=0.000000; *g=0.829175; *b=0.149725; break;
+          case 94:  *r=0.000000; *g=0.828783; *b=0.124083; break;
+          case 95:  *r=0.000000; *g=0.828392; *b=0.098442; break;
+          case 96:  *r=0.000000; *g=0.828000; *b=0.072800; break;
+          case 97:  *r=0.033167; *g=0.834167; *b=0.066733; break;
+          case 98:  *r=0.066333; *g=0.840333; *b=0.060667; break;
+          case 99:  *r=0.099500; *g=0.846500; *b=0.054600; break;
+          case 100: *r=0.132667; *g=0.852667; *b=0.048533; break;
+          case 101: *r=0.165833; *g=0.858833; *b=0.042467; break;
+          case 102: *r=0.199000; *g=0.865000; *b=0.036400; break;
+          case 103: *r=0.232167; *g=0.871167; *b=0.030333; break;
+          case 104: *r=0.265333; *g=0.877333; *b=0.024267; break;
+          case 105: *r=0.298500; *g=0.883500; *b=0.018200; break;
+          case 106: *r=0.331667; *g=0.889667; *b=0.012133; break;
+          case 107: *r=0.364833; *g=0.895833; *b=0.006067; break;
+          case 108: *r=0.398000; *g=0.902000; *b=0.000000; break;
+          case 109: *r=0.430950; *g=0.902000; *b=0.000000; break;
+          case 110: *r=0.463900; *g=0.902000; *b=0.000000; break;
+          case 111: *r=0.496850; *g=0.902000; *b=0.000000; break;
+          case 112: *r=0.529800; *g=0.902000; *b=0.000000; break;
+          case 113: *r=0.562750; *g=0.902000; *b=0.000000; break;
+          case 114: *r=0.595700; *g=0.902000; *b=0.000000; break;
+          case 115: *r=0.628650; *g=0.902000; *b=0.000000; break;
+          case 116: *r=0.661600; *g=0.902000; *b=0.000000; break;
+          case 117: *r=0.694550; *g=0.902000; *b=0.000000; break;
+          case 118: *r=0.727500; *g=0.902000; *b=0.000000; break;
+          case 119: *r=0.760450; *g=0.902000; *b=0.000000; break;
+          case 120: *r=0.793400; *g=0.902000; *b=0.000000; break;
+          case 121: *r=0.810617; *g=0.897133; *b=0.003983; break;
+          case 122: *r=0.827833; *g=0.892267; *b=0.007967; break;
+          case 123: *r=0.845050; *g=0.887400; *b=0.011950; break;
+          case 124: *r=0.862267; *g=0.882533; *b=0.015933; break;
+          case 125: *r=0.879483; *g=0.877667; *b=0.019917; break;
+          case 126: *r=0.896700; *g=0.872800; *b=0.023900; break;
+          case 127: *r=0.913917; *g=0.867933; *b=0.027883; break;
+          case 128: *r=0.931133; *g=0.863067; *b=0.031867; break;
+          case 129: *r=0.948350; *g=0.858200; *b=0.035850; break;
+          case 130: *r=0.965567; *g=0.853333; *b=0.039833; break;
+          case 131: *r=0.982783; *g=0.848467; *b=0.043817; break;
+          case 132: *r=1.000000; *g=0.843600; *b=0.047800; break;
+          case 133: *r=0.995725; *g=0.824892; *b=0.051600; break;
+          case 134: *r=0.991450; *g=0.806183; *b=0.055400; break;
+          case 135: *r=0.987175; *g=0.787475; *b=0.059200; break;
+          case 136: *r=0.982900; *g=0.768767; *b=0.063000; break;
+          case 137: *r=0.978625; *g=0.750058; *b=0.066800; break;
+          case 138: *r=0.974350; *g=0.731350; *b=0.070600; break;
+          case 139: *r=0.970075; *g=0.712642; *b=0.074400; break;
+          case 140: *r=0.965800; *g=0.693933; *b=0.078200; break;
+          case 141: *r=0.961525; *g=0.675225; *b=0.082000; break;
+          case 142: *r=0.957250; *g=0.656517; *b=0.085800; break;
+          case 143: *r=0.952975; *g=0.637808; *b=0.089600; break;
+          case 144: *r=0.948700; *g=0.619100; *b=0.093400; break;
+          case 145: *r=0.952975; *g=0.600408; *b=0.085617; break;
+          case 146: *r=0.957250; *g=0.581717; *b=0.077833; break;
+          case 147: *r=0.961525; *g=0.563025; *b=0.070050; break;
+          case 148: *r=0.965800; *g=0.544333; *b=0.062267; break;
+          case 149: *r=0.970075; *g=0.525642; *b=0.054483; break;
+          case 150: *r=0.974350; *g=0.506950; *b=0.046700; break;
+          case 151: *r=0.978625; *g=0.488258; *b=0.038917; break;
+          case 152: *r=0.982900; *g=0.469567; *b=0.031133; break;
+          case 153: *r=0.987175; *g=0.450875; *b=0.023350; break;
+          case 154: *r=0.991450; *g=0.432183; *b=0.015567; break;
+          case 155: *r=0.995725; *g=0.413492; *b=0.007783; break;
+          case 156: *r=1.000000; *g=0.394800; *b=0.000000; break;
+          case 157: *r=0.998342; *g=0.361900; *b=0.000000; break;
+          case 158: *r=0.996683; *g=0.329000; *b=0.000000; break;
+          case 160: *r=0.995025; *g=0.296100; *b=0.000000; break;
+          case 161: *r=0.993367; *g=0.263200; *b=0.000000; break;
+          case 162: *r=0.991708; *g=0.230300; *b=0.000000; break;
+          case 163: *r=0.990050; *g=0.197400; *b=0.000000; break;
+          case 164: *r=0.988392; *g=0.164500; *b=0.000000; break;
+          case 165: *r=0.986733; *g=0.131600; *b=0.000000; break;
+          case 166: *r=0.985075; *g=0.098700; *b=0.000000; break;
+          case 167: *r=0.983417; *g=0.065800; *b=0.000000; break;
+          case 168: *r=0.981758; *g=0.032900; *b=0.000000; break;
+          case 169: *r=0.980100; *g=0.000000; *b=0.000000; break;
+          case 170: *r=0.955925; *g=0.000000; *b=0.000000; break;
+          case 171: *r=0.931750; *g=0.000000; *b=0.000000; break;
+          case 172: *r=0.907575; *g=0.000000; *b=0.000000; break;
+          case 173: *r=0.883400; *g=0.000000; *b=0.000000; break;
+          case 174: *r=0.859225; *g=0.000000; *b=0.000000; break;
+          case 175: *r=0.835050; *g=0.000000; *b=0.000000; break;
+          case 176: *r=0.810875; *g=0.000000; *b=0.000000; break;
+          case 177: *r=0.786700; *g=0.000000; *b=0.000000; break;
+          case 178: *r=0.762525; *g=0.000000; *b=0.000000; break;
+          case 179: *r=0.738350; *g=0.000000; *b=0.000000; break;
+          case 180: *r=0.714175; *g=0.000000; *b=0.000000; break;
+          case 181: *r=0.690000; *g=0.000000; *b=0.000000; break;
+          case 182: *r=0.715833; *g=0.083333; *b=0.083333; break;
+          case 183: *r=0.741667; *g=0.166667; *b=0.166667; break;
+          case 184: *r=0.767500; *g=0.250000; *b=0.250000; break;
+          case 185: *r=0.793333; *g=0.333333; *b=0.333333; break;
+          case 186: *r=0.819167; *g=0.416667; *b=0.416667; break;
+          case 187: *r=0.845000; *g=0.500000; *b=0.500000; break;
+          case 188: *r=0.870833; *g=0.583333; *b=0.583333; break;
+          case 189: *r=0.896667; *g=0.666667; *b=0.666667; break;
+          case 190: *r=0.922500; *g=0.750000; *b=0.750000; break;
+          case 191: *r=0.948333; *g=0.833333; *b=0.833333; break;
+          case 192: *r=0.974167; *g=0.916667; *b=0.916667; break;
+          case 193: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 194: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 195: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 196: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 197: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 198: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 199: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          case 200: *r=1.000000; *g=1.000000; *b=1.000000; break;
+          }
+
+      /* Convert the RGB values to 0 and 255.  With the steps above, they
+         are between 0 and 1. */
+      *r++ *= 255;
+      *g++ *= 255;
+      *b++ *= 255;
+    }
+  while(++f<fp);
+
+  /* Convert the type to unsigned char. */
+  R=gal_data_copy_to_new_type_free(R, GAL_TYPE_UINT8);
+  G=gal_data_copy_to_new_type_free(G, GAL_TYPE_UINT8);
+  B=gal_data_copy_to_new_type_free(B, GAL_TYPE_UINT8);
+  p->chll=R;
+  p->chll->next=G;
+  p->chll->next->next=B;
+
+  /* Clean up. */
+  gal_data_free(channel);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/***********************************************************************/
+/**************            From mono-channel           *****************/
+/***********************************************************************/
+/* This algorithm is a translation of the primary algorithm in this page:
+https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
 */
+void
+color_rgb_to_hsv(struct converttparams *p)
+{
+  float *h, *s, *v;
+  gal_data_t *H, *S, *V;
+  uint8_t *r, *g, *b, *rr, min, max, delta;
+
+  /* Basic sanity checks. */
+  if(gal_list_data_number(p->chll)!=3)
+    error(EXIT_FAILURE, 0, "%s: three color channels must be input",
+          __func__);
+  if( p->chll->type!=GAL_TYPE_UINT8
+      || p->chll->next->type!=GAL_TYPE_UINT8
+      || p->chll->next->next->type!=GAL_TYPE_UINT8 )
+    error(EXIT_FAILURE, 0, "when converting RGB to HSV, all three input "
+          "color channels must have an 8-bit unsigned integer type");
+
+  /* Allocate the three datasets to keep the RGB colors. */
+  H=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, p->chll->ndim,
+                   p->chll->dsize, p->chll->wcs, 0, p->cp.minmapsize,
+                   "HUE", NULL, NULL);
+  S=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, p->chll->ndim,
+                   p->chll->dsize, p->chll->wcs, 0, p->cp.minmapsize,
+                   "SATURATION", NULL, NULL);
+  V=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, p->chll->ndim,
+                   p->chll->dsize, p->chll->wcs, 0, p->cp.minmapsize,
+                   "VALUE", NULL, NULL);
+
+  /* Initiate the pointer arrays. */
+  h=H->array;
+  s=S->array;
+  v=V->array;
+  r=p->chll->array;
+  g=p->chll->next->array;
+  b=p->chll->next->next->array;
+
+  /* Parse the dataset and do the conversion. */
+  rr=r+p->chll->size;
+  do
+    {
+      /* Get the minimum and maximum RGB values. */
+      min = *r  < *g ? *r  : *g;
+      min = min < *b ? min : *b;
+      max = *r  > *g ? *r  : *g;
+      max = max > *b ? max : *b;
+
+      /* The "value" is the maximum. */
+      *v = (float)(max)/255.0;
+
+      /* See what the difference between the minimum and maximum are. */
+      delta=max-min;
+      if(delta)
+        {
+          if(max)
+            {
+              /* Set the Saturation and hue. */
+              *s = (float)(delta)/(float)(max);
+              *h = ( *r==max
+                     /* Between yellow and magenta. */
+                     ? ((float)(*g-*b)/(float)(delta))
+                     : ( *g==max
+                         /* Between cyan & yellow. */
+                         ? (2.0+(float)(*b-*r)/(float)(delta))
+                         /* Between magenta & cyan. */
+                         : (4.0+(float)(*r-*g)/(float)(delta)) ) );
+
+              /* Correct the hue: */
+              *h *= 60.0;
+              if( *h<0.0 ) *h += 360.0;
+            }
+          else
+            /* When `max==0', then *r=*g=*b=0, so s=h=0. */
+            *s=*h=0.0;
+        }
+      else
+        /* When there is no difference, then its actually a grayscale
+           dataset, so `*v' is the only parameter that matters. */
+        *s=*h=0.0;
+
+
+      /* Increment all the pointers. */
+      ++g; ++b; ++h; ++s; ++v;
+    }
+  while(++r<rr);
+
+  /* Free the old channels linked list and replace it with the new ones. */
+  gal_list_data_free(p->chll);
+  p->chll=H;
+  p->chll->next=S;
+  p->chll->next->next=V;
+}
diff --git a/bin/convertt/color.h b/bin/convertt/color.h
new file mode 100644
index 0000000..252724b
--- /dev/null
+++ b/bin/convertt/color.h
@@ -0,0 +1,35 @@
+/*********************************************************************
+ConvertType - Convert between various types of files.
+ConvertType is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <mohammad@akhlaghi.org>
+Contributing author(s):
+Copyright (C) 2015-2018, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef COLOR_H
+#define COLOR_H
+
+void
+color_from_mono_hsv(struct converttparams *p);
+
+void
+color_from_mono_sls(struct converttparams *p);
+
+void
+color_rgb_to_hsv(struct converttparams *p);
+
+#endif
diff --git a/bin/convertt/convertt.c b/bin/convertt/convertt.c
index be79d20..692351c 100644
--- a/bin/convertt/convertt.c
+++ b/bin/convertt/convertt.c
@@ -40,6 +40,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro-internal/checkset.h>
 
 #include "main.h"
+#include "color.h"
 
 
 
@@ -175,7 +176,6 @@ convertt_scale_to_uchar(struct converttparams *p)
   gal_data_t *channel, *prev, *copied, *mind, *maxd;
   float *f, *ff, m, tmin, tmax, min=FLT_MAX, max=-FLT_MAX;
 
-
   /* Convert everything to single precision floating point type and find
      the minimum and maximum values of all the channels in the process. */
   prev=NULL;
@@ -304,6 +304,7 @@ convertt_scale_to_uchar(struct converttparams *p)
 
 
 
+
 /**************************************************************/
 /**************           Main function         ***************/
 /**************************************************************/
@@ -324,11 +325,26 @@ convertt(struct converttparams *p)
       convertt_truncate(p);
     }
 
+  /* Convert a mono/single color channel to a color format. */
+  if(p->colormap)
+    switch(p->colormap->status)
+      {
+      case COLOR_HSV:  color_from_mono_hsv(p);     break;
+      case COLOR_SLS:  color_from_mono_sls(p);     break;
+      case COLOR_GRAY: convertt_scale_to_uchar(p); break;
+      default:
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+              "the problem. The value %d is not a recognized color-space "
+              "code", __func__, PACKAGE_BUGREPORT, p->colormap->status);
+      }
+
   /* Save the outputs: */
   switch(p->outformat)
     {
     /* FITS: a FITS file can have many extensions (channels). */
     case OUT_FORMAT_FITS:
+      if(p->numch==3 && p->rgbtohsv)
+        color_rgb_to_hsv(p);
       for(channel=p->chll; channel!=NULL; channel=channel->next)
         gal_fits_img_write(channel, p->cp.output, NULL, PROGRAM_NAME);
       break;
@@ -341,20 +357,20 @@ convertt(struct converttparams *p)
 
     /* JPEG: */
     case OUT_FORMAT_JPEG:
-      convertt_scale_to_uchar(p);
+      if(!p->colormap) convertt_scale_to_uchar(p);
       gal_jpeg_write(p->chll, p->cp.output, p->quality, p->widthincm);
       break;
 
     /* EPS. */
     case OUT_FORMAT_EPS:
-      convertt_scale_to_uchar(p);
+      if(!p->colormap) convertt_scale_to_uchar(p);
       gal_eps_write(p->chll, p->cp.output, p->widthincm, p->borderwidth,
                     p->hex, 0);
       break;
 
     /* PDF */
     case OUT_FORMAT_PDF:
-      convertt_scale_to_uchar(p);
+      if(!p->colormap) convertt_scale_to_uchar(p);
       gal_pdf_write(p->chll, p->cp.output, p->widthincm, p->borderwidth);
       break;
 
diff --git a/bin/convertt/main.h b/bin/convertt/main.h
index 35b9aa9..cb462a0 100644
--- a/bin/convertt/main.h
+++ b/bin/convertt/main.h
@@ -37,6 +37,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /* Constants/macros. */
 #define BLANK_CHANNEL_NAME "blank"
 
+
 enum output_formats
 {
   OUT_FORMAT_INVALID,           /* ==0 by C standard */
@@ -48,6 +49,16 @@ enum output_formats
   OUT_FORMAT_JPEG,
 };
 
+enum colorspace_names
+{
+  COLOR_INVALID,           /* ==0 by C standard */
+
+  COLOR_RGB,
+  COLOR_HSV,
+  COLOR_SLS,
+  COLOR_GRAY,
+};
+
 
 
 
@@ -74,6 +85,8 @@ struct converttparams
   float           widthincm;  /* Width in centimeters.                 */
   uint32_t      borderwidth;  /* Width of border in PostScript points. */
   uint8_t               hex;  /* Use hexadecimal not ASCII85 encoding. */
+  gal_data_t      *colormap;  /* Color space to use for single/mono.   */
+  uint8_t          rgbtohsv;  /* Convert input RGB channels to HSV.    */
   char          *fluxlowstr;  /* Lower flux truncation value.          */
   char         *fluxhighstr;  /* Higher flux truncation value.         */
   uint8_t           maxbyte;  /* Maximum byte value.                   */
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index e9a3afd..e2ca180 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -226,6 +226,85 @@ parse_opt(int key, char *arg, struct argp_state *state)
 /**************************************************************/
 /***************       Sanity Check         *******************/
 /**************************************************************/
+static void
+ui_colormap_sanity_check(struct converttparams *p)
+{
+  char **strarr;
+  float *farray;
+  size_t nparams=0;
+  int ccode=COLOR_INVALID;
+
+  /* See how many parameters are necessary. */
+  strarr=p->colormap->array;
+  if     ( !strcmp(strarr[0],"hsv" )) { ccode=COLOR_HSV;  nparams=2; }
+  else if( !strcmp(strarr[0],"sls" )) { ccode=COLOR_SLS;  nparams=0; }
+  else if( !strcmp(strarr[0],"gray") || !strcmp(strarr[0],"grey"))
+                                      { ccode=COLOR_GRAY; nparams=0; }
+  else
+    error(EXIT_FAILURE, 0, "`%s' not recognized as a color-space given "
+          "to `--monotocolor'", strarr[0]);
+  p->colormap->status=ccode;
+
+  /* Check if the proper number of parameters are given for this color
+     space. Note that the actual colorspace name is the first element in
+     `monotocolor'. */
+  if(p->colormap->size!=1 && p->colormap->size != (nparams+1) )
+    error(EXIT_FAILURE, 0, "%zu parameters given to `--monotocolor' for "
+          "the `%s' color space (which needs %zu)",
+          p->colormap->size-1, strarr[0], nparams);
+
+  /* Allocate the necessary space for the parameters (when
+     necessary). */
+  if(nparams>0)
+    {
+      /* If no parameters were given, put the full range. */
+      if(p->colormap->size==1)
+        {
+          p->colormap->next=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1,
+                                            &nparams, NULL, 0,
+                                            p->cp.minmapsize, NULL,NULL,NULL);
+          farray=p->colormap->next->array;
+          switch(p->colormap->status)
+            {
+            case COLOR_HSV: farray[0]=0; farray[1]=360; break;
+            default:
+              error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at "
+                    "%s to fix the problem. The value `%d' is not "
+                    "recognized for a color space that needs default "
+                    "parameters", __func__, PACKAGE_BUGREPORT,
+                    p->colormap->status);
+            }
+        }
+      else
+        {
+          /* Increment the array pointer (temporarily) so we can read
+             the rest of the parameters as float32. Note that we can't
+             use `+=' because it is a `void *' pointer. We'll have to
+             use `strarry', because its type is defined. */
+          p->colormap->size-=1;
+          p->colormap->array = strarr + 1;
+          p->colormap->next=gal_data_copy_to_new_type(p->colormap,
+                                                       GAL_TYPE_FLOAT32);
+          p->colormap->array = strarr;
+          p->colormap->size+=1;
+
+          /* For a check
+             {
+               size_t i;
+               farray=p->monotocolor->next->array;
+               for(i=0;i<p->monotocolor->next->size;++i)
+               printf("%f\n", farray[i]);
+               exit(1);
+             }
+          */
+        }
+    }
+}
+
+
+
+
+
 /* Read and check ONLY the options. When arguments are involved, do the
    check in `ui_check_options_and_arguments'. */
 static void
@@ -262,6 +341,10 @@ ui_read_check_only_options(struct converttparams *p)
 
       gal_data_free(cond);
     }
+
+  /* Check the colormap. */
+  if(p->colormap)
+    ui_colormap_sanity_check(p);
 }
 
 
@@ -546,6 +629,27 @@ ui_prepare_input_channels(struct converttparams *p)
           "contain more than one color channel", p->numch);
 
 
+  /* If there are multiple color channels, then ignore the monotocolor
+     option if it is given. But if there is only one, make sure that the
+     `colormap' option is actually given.*/
+  if( p->numch==1 )
+    {
+      if( p->colormap==NULL )
+        error(EXIT_FAILURE, 0, "no colormap! When there is only one input "
+              "channel, it is necessary to specify a color map. For "
+              "example `gray', `hsv', or `sls'.\n\n"
+              "For more on ConvertType's color mapping, see the "
+              "description under `--colormap' in the Gnuastro book:\n\n"
+              "   $ info astconvertt");
+    }
+  else if( p->numch>1 && p->colormap )
+    {
+      if(p->colormap->next) gal_data_free(p->colormap->next);
+      gal_data_free(p->colormap);
+      p->colormap=NULL;
+    }
+
+
   /* Go over the channels and make the proper checks/corrections. We won't
      be checking blank channels here, recall that blank channels had a
      dimension of zero. */
@@ -880,7 +984,11 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
converttparams *p)
 void
 ui_free_report(struct converttparams *p)
 {
-  /* Free the allocated spaces */
+  if(p->colormap)
+    {
+      if(p->colormap->next) gal_data_free(p->colormap->next);
+      gal_data_free(p->colormap);
+    }
   gal_data_free(p->fluxlow);
   gal_data_free(p->fluxhigh);
   gal_list_str_free(p->hdus, 1);
diff --git a/bin/convertt/ui.h b/bin/convertt/ui.h
index 08c1e42..5e91622 100644
--- a/bin/convertt/ui.h
+++ b/bin/convertt/ui.h
@@ -63,6 +63,8 @@ enum option_keys_enum
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
+  UI_KEY_COLORMAP            = 1000,
+  UI_KEY_RGBTOHSV,
 };
 
 
diff --git a/bin/statistics/statistics.c b/bin/statistics/statistics.c
index 9871220..f54dea5 100644
--- a/bin/statistics/statistics.c
+++ b/bin/statistics/statistics.c
@@ -92,9 +92,9 @@ statistics_print_one_row(struct statisticsparams *p)
 {
   int mustfree;
   char *toprint;
-  size_t dsize=1;
   double arg, *d;
   gal_list_i32_t *tmp;
+  size_t dsize=1, counter;
   gal_data_t *tmpv, *out=NULL, *num=NULL, *min=NULL, *max=NULL;
   gal_data_t *sum=NULL, *med=NULL, *meanstd=NULL, *modearr=NULL;
 
@@ -145,6 +145,7 @@ statistics_print_one_row(struct statisticsparams *p)
 
 
   /* Print every requested number. */
+  counter=0;
   for(tmp=p->singlevalue; tmp!=NULL; tmp=tmp->next)
     {
       /* By default don't free anything. */
@@ -188,12 +189,16 @@ statistics_print_one_row(struct statisticsparams *p)
           break;
         }
 
-      /* Print the number. */
+      /* Print the number. Note that we don't want any extra white space
+         characters before or after the printed outputs. So we have defined
+         `counter' to add a single white space character before any element
+         except the first one. */
       toprint=gal_type_to_string(out->array, out->type, 0);
-      printf("%s ", toprint);
+      printf("%s%s", counter ? " " : "", toprint);
       free(toprint);
 
       /* Clean up (if necessary). */
+      ++counter;
       if(mustfree) gal_data_free(out);
     }
 
diff --git a/doc/gnuastro.en.html b/doc/gnuastro.en.html
index 300e89f..3edb537 100644
--- a/doc/gnuastro.en.html
+++ b/doc/gnuastro.en.html
@@ -39,8 +39,8 @@ h3 { clear: both; }
   <li><a href="#introduction">Introduction</a></li>
   <li><a href="#download">Download</a></li>
   <li><a href="#installation">Installation</a></li>
-  <li><a href="#documentation">Book (documentation)</a></li>
-  <li><a href="#mail">Gnuastro mailing lists</a></li>
+  <li><a href="#documentation">Documentation</a></li>
+  <li><a href="#mail">Mailing lists</a></li>
   <li><a href="#bug">Report a Bug</a></li>
   <li><a href="#contribute">Getting involved</a></li>
   <li><a href="#cite">How to cite</a></li>
@@ -177,7 +177,7 @@ to any major part of the book on the command-line:</p>
 
 
 
-<h3 id="mail">Gnuastro mailing lists</h3>
+<h3 id="mail">Mailing lists</h3>
 
 <p>Gnuastro has the following mailing lists:</p>
 
diff --git a/doc/gnuastro.fr.html b/doc/gnuastro.fr.html
index 04fd936..7982329 100644
--- a/doc/gnuastro.fr.html
+++ b/doc/gnuastro.fr.html
@@ -41,7 +41,7 @@ h3 { clear: both; }
   <li><a href="#introduction">Introduction</a></li>
   <li><a href="#download">Téléchargement</a></li>
   <li><a href="#installation">Installation</a></li>
-  <li><a href="#documentation">Documentation – le Livre</a></li>
+  <li><a href="#documentation">Documentation</a></li>
   <li><a href="#mail">Listes de diffusion</a></li>
   <li><a href="#bug">Signalement de bogues</a></li>
   <li><a href="#contribute">Participer</a></li>
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 73aae45..fc91c2a 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -10331,21 +10331,22 @@ continue with the rest of actions.
 @pindex @r{ConvertType (}astconvertt@r{)}
 The FITS format used in astronomy was defined mainly for archiving,
 transmission, and processing. In other situations, the data might be useful
-in other formats. For example, when you are writing a paper or report or if
-you are making slides for a talk, you can't use a FITS image. Other image
-formats should be used. In other cases you might want your pixel values in
-a table format as plain text for input to other programs that don't
-recognize FITS, or to include as a table in your report. ConvertType is
-created for such situations. The various types will increase with future
-updates and based on need.
+in other formats. For example, when you are writing a paper or report, or
+if you are making slides for a talk, you can't use a FITS image. Other
+image formats should be used. In other cases you might want your pixel
+values in a table format as plain text for input to other programs that
+don't recognize FITS. ConvertType is created for such situations. The
+various types will increase with future updates and based on need.
 
 The conversion is not only one way (from FITS to other formats), but two
-ways (except the EPS and PDF formats). So you can convert a JPEG image or
-text file into a FITS image. Basically, other than EPS, you can use any of
-the recognized formats as different color channel inputs to get any of the
-recognized outputs. So before explaining the options and arguments, first a
-short description of the recognized files types will be given followed a
-short introduction to digital color.
+ways (except the EPS and PDF formats@footnote{Because EPS and PDF are
+vector, not raster/pixelated formats}). So you can also convert a JPEG
+image or text file into a FITS image. Basically, other than EPS/PDF, you
+can use any of the recognized formats as different color channel inputs to
+get any of the recognized outputs. So before explaining the options and
+arguments (in @ref{Invoking astconvertt}), we'll start with a short
+description of the recognized files types in @ref{Recognized file formats},
+followed a short introduction to digital color in @ref{Color}.
 
 @menu
 * Recognized file formats::     Recognized file formats
@@ -10357,22 +10358,23 @@ short introduction to digital color.
 @subsection Recognized file formats
 
 The various standards and the file name extensions recognized by
-ConvertType are listed below.
+ConvertType are listed below. Currently Gnuastro uses the file name's
+suffix to identify the format.
 
 @table @asis
 @item FITS or IMH
+@cindex IRAF
 @cindex Astronomical data format
-Astronomical data are commonly stored in the FITS format (and in older
-data sets in IRAF @file{.imh} format), a list of file name suffixes
-which indicate that the file is in this format is given in
-@ref{Arguments}.
-
-Each extension of a FITS image only has one value per pixel, so when
-used as input, each input FITS image contributes as one color
-channel. If you want multiple extensions in one FITS file for
-different color channels, you have to repeat the file name multiple
-times and use the @option{--hdu}, @option{--hdu2}, @option{--hdu3} or
-@option{--hdu4} options to specify the different extensions.
+Astronomical data are commonly stored in the FITS format (or the older data
+IRAF @file{.imh} format), a list of file name suffixes which indicate that
+the file is in this format is given in @ref{Arguments}.
+
+Each image extension of a FITS file only has one value per
+pixel/element. Therefore, when used as input, each input FITS image
+contributes as one color channel. If you want multiple extensions in one
+FITS file for different color channels, you have to repeat the file name
+multiple times and use the @option{--hdu}, @option{--hdu2}, @option{--hdu3}
+or @option{--hdu4} options to specify the different extensions.
 
 @item JPEG
 @cindex JPEG format
@@ -10544,39 +10546,68 @@ comment line). To print to the standard output, set 
the output name to
 @cindex RGB
 @cindex CMYK
 @cindex Image
+@cindex Color
 @cindex Pixels
-@cindex Grayscale
 @cindex Colorspace
 @cindex Primary colors
+Color is defined by mixing various measurements/filters. In digital
+monitors or common digital cameras, colors are displayed/stored by mixing
+the three basic colors of red, green and blue (RGB) with various
+proportions. When printing on paper, standard printers use the cyan,
+magenta, yellow and key (CMYK, key=black) color space. In other words, for
+each displayed/printed pixel of a color image, the dataset/image has three
+or four values.
+
+@cindex Color channel
+@cindex Channel, color
+To store/show the three values for each pixel, cameras and monitors
+allocate a certain fraction of each pixel's area to red, green and blue
+filters. These three filters are thus built into the hardware at the pixel
+level. However, because measurement accuracy is very important in
+scientific instruments, and we want to do measurements (take images) with
+various/custom filters (without having to order a new expensive detector!),
+scientific detectors use the full area of the pixel to store one value for
+it in a single/mono channel dataset. To make measurements in different
+filters, we just place a filter in the light path before the
+detector. Therefore, the FITS format that is used to store astronomical
+datasets is inherently a mono-channel format (see @ref{Recognized file
+formats} or @ref{Fits}).
+
+When a subject has been imaged in multiple filters, you can feed each
+different filter into the red, green and blue channels and obtain a colored
+visualizion. In ConvertType, you can do this by giving each separate
+single-channel dataset (for example in the FITS image format) as an
+argument (in the proper order), then asking for the output in a format that
+supports multi-channel datasets (for example JPEG or PDF, see the examples
+in @ref{Invoking astconvertt}).
+
+@cindex Grayscale
+@cindex Visualization
+@cindex Colorspace, HSV
 @cindex Colorspace, gray-scale
-An image is a two dimensional array of 2 dimensional elements called
-pixels. If each pixel only has one value, the image is known as a
-gray-scale image and no color is defined. The range of values in the
-image can be interpreted as shades of any color, it is customary to
-use shades of black or gray-scale. However, to produce the color
-spectrum in the digital world, several primary colors must be
-mixed. Therefore in a color image, each pixel has several values
-depending on how many primary colors were chosen. For example on the
-digital monitor or color digital cameras, all colors are built by
-mixing the three colors of Red-Green-Blue (RGB) with various
-proportions. However, for printing on paper, standard printers use the
-Cyan-Magenta-Yellow-Key (CMYK, Key=black) color space. Therefore when
-printing an RGB image, usually a transformation of color spaces will
-be necessary.
-
-In a colored digital camera, a color image is produced by dividing the
-pixel's area between three colors (filters). However in astronomy due
-to the intrinsic faintness of most of the targets, the collecting area
-of the pixel is very important for us. Hence the full area of the
-pixel is used and one value is stored for that pixel in the end. One
-color filter is used for the whole image. Thus a FITS image is
-inherently a gray-scale image and no color can be defined for it.
-
-@cindex Colorspace, transformation
-One way to represent a gray-scale image in different color spaces is to
-use the same proportions of the primary colors in each pixel. This is
-the common way most FITS image converters work: they fill all the
-channels with the same values. The downside is two fold:
+@cindex HSV: Hue Saturation Value
+As discussed above, color is not defined when a dataset/image contains a
+single value for each pixel. However, we interact with scientific datasets
+through monitors or printers (which allow multiple values per pixel and
+produce color with them). As a result, there is a lot of freedom in
+visualizing a single-channel dataset. The most basic is to use shades of
+black (because of its strong contrast with white). This scheme is called
+grayscale. To help in visualization, more complex mappings can be
+defined. For example, the values can be scaled to a range of 0 to 360 and
+used as the ``Hue'' term of the
+@url{https://en.wikipedia.org/wiki/HSL_and_HSV, Hue-Saturation-Value} (HSV)
+color space (while fixing the ``Saturation'' and ``Value'' terms). In
+ConvertType, you can use the @option{--colormap} option to choose between
+different mappings of mono-channel inputs, see @ref{Invoking astconvertt}.
+
+Since grayscale is a commonly used mapping of single-valued datasets, we'll
+continue with a closer look at how it is stored. One way to represent a
+gray-scale image in different color spaces is to use the same proportions
+of the primary colors in each pixel. This is the common way most FITS image
+displayer work: for each pixel, they fill all the channels with the single
+value. While this is necessary for displaying a dataset, there are
+downsides when storing/saving this type of grayscale visualization (for
+example in a paper).
 
 @itemize
 
@@ -10592,23 +10623,20 @@ printed image slightly more blurred than it actually 
is.
 
 @cindex PNG standard
 @cindex Single channel CMYK
-To solve both these problems, the best way is to save the FITS image
-into the black channel of the CMYK color space. In the RGB color space
-all three channels have to be used. The JPEG standard is the only
-common standard that accepts CMYK color space, that is why currently
-only the JPEG standard is included and not the PNG standard for
-example.
-
-The JPEG and EPS standards set two sizes for the number of bits in
-each channel: 8-bit and 12-bit. The former is by far the most common
-and is what is used in ConvertType. Therefore, each channel should
-have values between 0 to @math{2^8-1=255}. From this we see how each
-pixel in a gray-scale image is one byte (8 bits) long, in an RGB image,
-it is 3bytes long and in CMYK it is 4bytes long. But thanks to the
-JPEG compression algorithms, when all the pixels of one channel have
-the same value, that channel is compressed to one pixel. Therefore a
-Grayscale image and a CMYK image that has only the K-channel filled
-are approximately the same file size.
+To solve both these problems when storing grayscale visualization, the best
+way is to save a single-channel dataset into the black channel of the CMYK
+color space. The JPEG standard is the only common standard that accepts
+CMYK color space.
+
+The JPEG and EPS standards set two sizes for the number of bits in each
+channel: 8-bit and 12-bit. The former is by far the most common and is what
+is used in ConvertType. Therefore, each channel should have values between
+0 to @math{2^8-1=255}. From this we see how each pixel in a gray-scale
+image is one byte (8 bits) long, in an RGB image, it is 3 bytes long and in
+CMYK it is 4 bytes long. But thanks to the JPEG compression algorithms,
+when all the pixels of one channel have the same value, that channel is
+compressed to one pixel. Therefore a Grayscale image and a CMYK image that
+has only the K-channel filled are approximately the same file size.
 
 
 @node Invoking astconvertt,  , Color, ConvertType
@@ -10629,8 +10657,12 @@ One line examples:
 ## Convert an image in FITS to PDF:
 $ astconvertt image.fits --output=pdf
 
-## Convert an image in JPEG to FITS:
-$ astconvertt image.jpg -ogalaxy.fits
+## Similar to before, but use the SLS color map:
+$ astconvertt image.fits --colormap=sls --output=pdf
+
+## Convert an image in JPEG to FITS (with multiple extensions
+## if its color):
+$ astconvertt image.jpg -oimage.fits
 
 ## Use three plain text 2D arrays to create an RGB JPEG output:
 $ astconvertt f1.txt f2.txt f3.fits -o.jpg
@@ -10767,6 +10799,62 @@ actually be the exact quality (each pixel will 
correspond to one input
 value). If it is in color mode, some degradation will occur. While the JPEG
 standard does support loss-less graphics, it is not commonly supported.
 
+@item --colormap=STR[,FLT,...]
+The color map to visualize a single channel. The first value given to this
+option is the name of the color map, which is shown below. Some color maps
+can be configured. In this case, the configuration parameters are
+optionally given as numbers following the name of the color map for example
+see @option{hsv}. The table below contains the usable names of the color
+maps that are currently supported:
+
+@table @option
+@item gray
+@itemx grey
+@cindex Colorspace, gray-scale
+Grayscale color map. This color map doesn't have any parameters. The full
+dataset range will be scaled to 0 and @mymath{2^8-1=255} to be stored in
+the requested format.
+
+@item hsv
+@cindex Colorspace, HSV
+@cindex Hue, saturation, value
+@cindex HSV: Hue Saturation Value
+Hue, Saturation,
+Value@footnote{@url{https://en.wikipedia.org/wiki/HSL_and_HSV}} color
+map. If no values are given after the name (@option{--colormap=hsv}), the
+dataset will be scaled to 0 and 360 for hue covering the full spectrum of
+colors. However, you can limit the range of hue (to show only a special
+color range) by explicity requesting them after the name (for example
+@option{--colormap=hsv,20,240}).
+
+The mapping of a single-channel dataset to HSV is done through the Hue and
+Value elements: Lower dataset elements have lower ``value'' @emph{and}
+lower ``hue''. This creates darker colors for fainter parts, while also
+respecting the range of colors.
+
+@item sls
+@cindex DS9
+@cindex SAO DS9
+@cindex SLS Color
+@cindex Colorspace: SLS
+The SLS color range, taken from the commonly used
+@url{http://ds9.si.edu,SAO DS9}. The advantage of this color range is that
+it ranges from black to dark blue, and finishes with red and white. So
+unlike the HSV color range, it includes black and white and brighter colors
+(like yellow, red and white) show the larger values.
+@end table
+
+@item --rgbtohsv
+When there are three input channels and the output is in the FITS format,
+interpret the three input channels as red, green and blue channels (RGB)
+and convert them to the hue, saturation, value (HSV) color space.
+
+The currently supported output formats of ConvertType don't have native
+support for HSV. Therefore this option is only supported when the output is
+in FITS format and each of the hue, saturation and value arrays can be
+saved as one FITS extension in the output for further analysis (for example
+to select a certain color).
+
 @end table
 
 @noindent
@@ -11541,7 +11629,7 @@ $ astcrop --mode=wcs desired-filter-image(s).fits       
    \
    --polygon="53.187414,-27.779152 : 53.159507,-27.759633 : \
               53.134517,-27.787144 : 53.161906,-27.807208"
 @end example
-@cindex SAO ds9
+@cindex SAO DS9
 In other cases, you have an image and want to define the polygon yourself
 (it isn't already published like the example above). As the number of
 vertices increases, checking the vertex coordinates on a FITS viewer (for
@@ -28930,19 +29018,22 @@ in the Convolve program@footnote{Hence any help would 
be greatly
 appreciated.}.
 
 @deftypefun {gal_data_t *} gal_convolve_spatial (gal_data_t @code{*tiles}, 
gal_data_t @code{*kernel}, size_t @code{numthreads}, int @code{edgecorrection}, 
int @code{convoverch})
-Convolve each node of the list of @code{tiles} (see @ref{List of
-gal_data_t} and @ref{Tessellation library}) with @code{kernel} using
-@code{numthreads}. When @code{edgecorrection} is non-zero, it will correct
-for the edge dimming effects as discussed in @ref{Edges in the spatial
-domain}.
-
-To create a tessellation that fully covers an input image, you may use
-@code{gal_tile_full}, or @code{gal_tile_full_two_layers} to also define
-channels over your input dataset. These functions are discussed in
-@ref{Tile grid}. You may then pass the list of tiles to this function. This
-is the recommended way to call this function because spatial domain
-convolution is slow and breaking the job into many small tiles and working
-on simultaneously on several threads can greatly speed up the processing.
+Convolve the given @code{tiles} dataset (possibly a list of tiles, see
+@ref{List of gal_data_t} and @ref{Tessellation library}) with @code{kernel}
+on @code{numthreads} threads. When @code{edgecorrection} is non-zero, it
+will correct for the edge dimming effects as discussed in @ref{Edges in the
+spatial domain}.
+
+@code{tiles} can be a single/complete dataset, but in that case the speed
+will be very slow. Therefore, for larger images, it is recommended to give
+a list of tiles covering a dataset. To create a tessellation that fully
+covers an input image, you may use @code{gal_tile_full}, or
+@code{gal_tile_full_two_layers} to also define channels over your input
+dataset. These functions are discussed in @ref{Tile grid}. You may then
+pass the list of tiles to this function. This is the recommended way to
+call this function because spatial domain convolution is slow and breaking
+the job into many small tiles and working on simultaneously on several
+threads can greatly speed up the processing.
 
 If the tiles are defined within a channel (a larger tile), by default
 convolution will be done within the channel, so pixels on the edge of a
@@ -31434,7 +31525,7 @@ useful for working with Gnuastro.
 @node SAO ds9, PGPLOT, Other useful software, Other useful software
 @section SAO ds9
 
-@cindex SAO ds9
+@cindex SAO DS9
 @cindex FITS image viewer
 SAO ds9@footnote{@url{http://ds9.si.edu/}} is not a requirement of
 Gnuastro, it is a FITS image viewer. So to check your inputs and
diff --git a/lib/convolve.c b/lib/convolve.c
index 1f558b4..5fd9b62 100644
--- a/lib/convolve.c
+++ b/lib/convolve.c
@@ -559,6 +559,10 @@ gal_data_t *
 gal_convolve_spatial(gal_data_t *tiles, gal_data_t *kernel,
                      size_t numthreads, int edgecorrection, int convoverch)
 {
+  /* When there isn't any tile structure, `convoverch' must be set to
+     one. Recall that the input can be a single full dataset also. */
+  if(tiles->block==NULL) convoverch=1;
+
   /* Call the general function. */
   return gal_convolve_spatial_general(tiles, kernel, numthreads,
                                       edgecorrection, convoverch, NULL);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]