commit 4ad8cdc25b5449b000982fd4ca757b37dca634c1
parent bb81f0f60505bcf7902532537545ae56a6d72dbb
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 5 Jun 2020 11:49:32 +0200
Merge branch 'release_0.4'
Diffstat:
4 files changed, 149 insertions(+), 35 deletions(-)
diff --git a/README.md b/README.md
@@ -29,6 +29,15 @@ informations on CMake.
## Release notes
+### Version 0.4
+
+- Add the `gnuplot` parameter to the `-m` option. Once set, the result image is
+ written as a gnuplot script rather than a PPM image. This script generates a
+ PNG image with an embedded color ramp.
+- Fix the tone map operator: the exposure term is now also applied to the white
+ radiance to ensure that it effectively corresponds to the white color in the
+ output image.
+
### Version 0.3
- Add the `-i` option that regroups all the options controlling the
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -37,7 +37,7 @@ include_directories(${RSys_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
# Configure and define targets
################################################################################
set(VERSION_MAJOR 0)
-set(VERSION_MINOR 3)
+set(VERSION_MINOR 4)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
diff --git a/doc/htpp.1.txt b/doc/htpp.1.txt
@@ -30,9 +30,9 @@ htpp [_option_] ... [_input_]
DESCRIPTION
-----------
-*htpp* post-processes a *htrdr-image*(5) and converts it to a regular PPM
-image [1]. If _input_ is not defined, the *htrdr-image*(5) is read from
-standard input. Two post-processing procedures are provided: the
+*htpp* post-processes a *htrdr-image*(5) and converts it to a PPM image [1] or
+to a *gnuplot*(1) script. If _input_ is not defined, the *htrdr-image*(5) is
+read from standard input. Two post-processing procedures are provided: the
post-processing of the image colors (option *-i*), and the mapping of a given
pixel component onto a color ramp (option "*-m*). By default, *htpp*
post-processes the image color.
@@ -42,7 +42,7 @@ the third and the fifth components of each *htrdr-image*(5) pixel encode a
color with respect to the CIE 1931 XYZ color space. *htpp* first tone maps
these colors with the following filmic tone mapping operator [2]:
- out-color = f(in-color * exposure) / f(white-scale)
+ out-color = f(in-color * exposure) / f(white-value * exposure)
with:
@@ -57,11 +57,11 @@ with:
The _exposure_ term is an user-defined parameter provided as the _exposure_
image option. If not defined, a default _exposure_ of 1 is used. The
-_white-scale_ factor is either defined by the user through the _white_ image
-option or automatically computed as the luminance that is such that 99.5% of
-pixel radiances are less than _white-scale_. Once tone mapped, the pixels are
+_white-value_ is either defined by the user through the _white_ image option
+or automatically computed as the radiance that is such that 99.5% of pixel
+radiances are less than _white-value. Once tone mapped, the pixels are
transformed from the CIE 1931 XYZ color space into the sRGB linear color space
-before being gamma corrected. Finally, the resulting pixel components are
+before being gamma corrected. Finally, the resulting pixel components are
clamped to [0, 1] and encoded on 8-bits.
The mapping of a pixel component onto a color ramp is controlled by the *-m*
@@ -90,9 +90,10 @@ OPTIONS
**exposure**=__real__;;
Pixel exposure. By default its value is 1.
- **white**=__white-scale__;;
- Factor used to normalize input colors. If not defined, the white scale is
- automatically computed from the luminance of the _input_ image.
+ **white**=__radiance__;;
+ Radiance in the _input_ image that will represent the white color in
+ _output_. If not defined, the white value is automatically computed from
+ the radiance of the _input_ image.
*-m* <__sub-option__>[:<__sub-option__> ...]::
Map a pixel component to a regular color. Available sub options are:
@@ -114,9 +115,15 @@ OPTIONS
selected pixel component over the whole image. This is the default
comportment.
+ **gnuplot**;;
+ The _output_ image is formatted as a gnuplot script rather than a PPM
+ image. Once executed, the script generates a PNG image with an embedded
+ color ramp. Note that this script can be edited in order to adjust the
+ generated image to any requirements.
+
*-o* _output_::
- File where the PPM image is written. If not defined, write _output_ to
- standard output.
+ File where the result is written. If not defined, write _output_ to standard
+ output.
*-t* _threads-count_::
Hint on the number of threads to use. By default use as many threads as CPU
@@ -124,13 +131,9 @@ OPTIONS
*-v*::
Make *htpp* verbose. When used in post-processing of the pixel color (*-i*
- option), this option displays the __white-scale__ factor used to normalize
- the colors. In pixel component mapping mode (*-m* option), this option
- displays the color ramp and its associated values.
-
-*-w _white-scale_*::
- Factor used to normalize input colors. If not defined, _white-scale_ is
- automatically computed from the luminance of the _input_ image.
+ option), this option displays the radiance corresponding to the __white__
+ color in the output image. In pixel component mapping mode (*-m* option),
+ this option displays the color ramp and its associated values.
*--version*::
Display version information and exit.
@@ -145,15 +148,22 @@ already exists:
$ htpp -f -o img.ppm img.htrdr
Convert *img.htrdr* and visualise the resulting image by redirecting the
-standard output to the *feh*(1) image viewer. Use an _exposure_ of *0.5* and
-explicitly define the normalization factor to *0.0025*:
+standard output to the *feh*(1) image viewer. Use an _exposure_ of *0.2* and
+explicitly define the white color to *31.2* W/sr/m^2:
- $ htpp -i exposure=0.5:white=0.0025 img.htrdr | feh -
+ $ htpp -i exposure=0.2:white=31.2 img.htrdr | feh -
Use the *-m* option to map the values of the second pixel component clamped in
[0, 2] to the color ramp _magma_.
- $ htpp -m pixcpnt=1:palette=magma:range=0 img.htrdr | feh -
+ $ htpp -v -m pixcpnt=1:palette=magma:range=0,2 img.htrdr | feh -
+
+Use the *-m* option to map the values of the sixth pixel component and write
+it as a gnuplot script. Run *gnuplot*(1) to generate a PNG of the result and
+visualise the resulting image with *feh*(1).
+
+ $ htpp -m pixcpnt=6:gnuplot -o img.gp img.htrdr
+ $ gnuplot img.gp | feh -
NOTES
-----
@@ -174,4 +184,5 @@ it. There is NO WARRANTY, to the extent permitted by law.
SEE ALSO
--------
*feh*(1),
+*gnuplot*(1)
*htrdr-image*(5)
diff --git a/src/htpp.c b/src/htpp.c
@@ -68,6 +68,7 @@ struct args {
const struct scmap_palette* palette;
unsigned pixcpnt; /* In [0, PIXCPNTS_COUNT__[ */
double range[2];
+ int gnuplot;
} map;
int verbose;
@@ -86,6 +87,7 @@ struct args {
&scmap_palette_inferno, /* Map palette */ \
0, /* Map channel */ \
{DBL_MAX,-DBL_MAX}, /* Range */ \
+ 0 /* Gnuplot */ \
}, \
0, /* Verbosity level */ \
0, /* Force overwrite? */ \
@@ -116,8 +118,8 @@ print_help(const char* cmd)
printf(
"Usage: %s [options] [image]\n"
"Post process a htrdr-image(5) and convert the result in a regular PPM\n"
-"image. If no image name is defined, read the image data from\n"
-"standard input.\n",
+"image or in a gnuplot script. If no image name is defined, read the \n"
+"image data from standard input.\n",
cmd);
printf("\n");
printf(
@@ -279,7 +281,8 @@ parse_map_option(struct args* args, const char* str)
goto error;
}
args->map = ARGS_DEFAULT.map;
-
+ } else if(!strcmp(key, "gnuplot")) {
+ args->map.gnuplot = 1;
} else {
if(!val) {
fprintf(stderr, "Missing value to the map option `%s'.\n", key);
@@ -491,7 +494,7 @@ filmic_tone_mapping
const double F = 0.30;
const double W = Ymax;
#define TONE_MAP(X) ((((X)*(A*(X)+C*B)+D*E)/((X)*(A*(X)+B)+D*F))-E/F)
- const double white_scale = TONE_MAP(W);
+ const double white_scale = TONE_MAP(W*exposure);
ASSERT(pixel);
pixel[PIXCPNT_X] = TONE_MAP(pixel[PIXCPNT_X]*exposure) / white_scale;
@@ -683,6 +686,86 @@ error:
goto exit;
}
+static res_T
+img_write_gnuplot
+ (const struct img* img,
+ const struct args* args,
+ FILE* stream,
+ const char* stream_name)
+{
+ double cbox_width = 0.8;
+ double cbox_height = 0.08;
+ double cbox_tmargin = 0.02;
+ size_t icol;
+ size_t x, y;
+ res_T res = RES_OK;
+ ASSERT(img && args && stream && stream_name);
+
+ #define CHKWR(FPrintf) { \
+ const int i = FPrintf; \
+ if(i < 0) { \
+ fprintf(stderr, "%s: could not write the gnuplot map.\n", stream_name); \
+ res = RES_IO_ERR; \
+ goto error; \
+ } \
+ } (void)0
+ CHKWR(fprintf(stream, "unset xtics\n"));
+ CHKWR(fprintf(stream, "unset ytics\n"));
+ CHKWR(fprintf(stream, "unset key\n"));
+ CHKWR(fprintf(stream, "unset colorbox\n"));
+ CHKWR(fprintf(stream, "unset origin\n"));
+ CHKWR(fprintf(stream, "unset border\n"));
+ CHKWR(fprintf(stream, "unset title\n"));
+ CHKWR(fprintf(stream, "unset margin\n"));
+ CHKWR(fprintf(stream, "set margins 0,0,0,0\n"));
+ CHKWR(fprintf(stream, "set xrange[0:%lu]\n", (unsigned long)img->width-1));
+ CHKWR(fprintf(stream, "set yrange[%lu:0]\n", (unsigned long)img->height-1));
+ if(args->map.range[0] < args->map.range[1]) {
+ CHKWR(fprintf(stream, "set cbrange[%g:%g]\n",
+ args->map.range[0], args->map.range[1]));
+ }
+ CHKWR(fprintf(stream, "set terminal png size %lu,%lu*(1+%g+%g)\n",
+ img->width, img->height, cbox_height, cbox_tmargin));
+ CHKWR(fprintf(stream, "set origin 0, %g\n", (cbox_height+cbox_tmargin)*0.5));
+ CHKWR(fprintf(stream, "set size ratio %g\n",
+ (double)img->height/(double)img->width));
+ CHKWR(fprintf(stream, "set colorbox horiz user origin %g,%g size %g,%g\n",
+ (1.0-cbox_width)*0.5, cbox_height*0.5, cbox_width, cbox_height*0.5));
+
+ CHKWR(fprintf(stream, "set palette defined (\\\n"));
+ FOR_EACH(icol, 0, args->map.palette->ncolors) {
+ double col[3];
+ args->map.palette->get_color(icol, col, args->map.palette->context);
+ CHKWR(fprintf(stream, " %lu %g %g %g",
+ (unsigned long)icol, col[0], col[1], col[2]));
+ if(icol < args->map.palette->ncolors-1) {
+ CHKWR(fprintf(stream, ",\\\n"));
+ } else {
+ CHKWR(fprintf(stream, ")\n"));
+ }
+ }
+
+ CHKWR(fprintf(stream, "$map2 << EOD\n"));
+ FOR_EACH(y, 0, img->height) {
+ FOR_EACH(x, 0, img->width) {
+ double* row = (double*)(img->pixels + img->pitch*y);
+ double* pixel = row + x*PIXCPNTS_COUNT__;
+ CHKWR(fprintf(stream, "%lu %lu %g\n", y, x, pixel[args->map.pixcpnt]));
+ }
+ if(y != img->height-1) {
+ CHKWR(fprintf(stream, "\n"));
+ }
+ }
+ CHKWR(fprintf(stream, "EOD\n"));
+ CHKWR(fprintf(stream, "plot '$map2' using 2:1:3 with image pixels\n"));
+ #undef CHKWR
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
static double
compute_XYZ_normalization_factor(const struct img* img)
{
@@ -915,14 +998,25 @@ main(int argc, char** argv)
img_is_loaded = 1;
switch(args.pp_type) {
- case PP_IMAGE: res = pp_image(&img, &args); break;
- case PP_MAP: res = pp_map(&img, &args); break;
+ case PP_IMAGE:
+ res = pp_image(&img, &args);
+ if(res != RES_OK) goto error;
+ res = img_write_ppm(&img, stream_out, stream_out_name);
+ if(res != RES_OK) goto error;
+ break;
+ case PP_MAP:
+ if(args.map.gnuplot) {
+ img_write_gnuplot(&img, &args, stream_out, stream_out_name);
+ if(res != RES_OK) goto error;
+ } else {
+ res = pp_map(&img, &args);
+ if(res != RES_OK) goto error;
+ res = img_write_ppm(&img, stream_out, stream_out_name);
+ if(res != RES_OK) goto error;
+ }
+ break;
default: FATAL("Unreachable code.\n"); break;
}
- if(res != RES_OK) goto error;
-
- res = img_write_ppm(&img, stream_out, stream_out_name);
- if(res != RES_OK) goto error;
exit:
if(stream_out && stream_out != stdout) fclose(stream_out);