commit f217010d2574b20cf993cc4732f4b3d31d5707f4
parent a3745d801d12c711356615bb311dcae18982a396
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 1 Oct 2018 11:03:56 +0200
Handle the format upd, add -u, and fix tonemap operator
The -u option dump the standard errors of the computed image rather than
its luminance.
Remove the empirical factor in the computation of normalization factor
since it can be handled in the exposure parameter.
Diffstat:
2 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/README.md b/README.md
@@ -6,9 +6,9 @@ space, as generated by the [HTRDR](https://gitlab.com/meso-star/htcp/) program.
The input images are simple ASCII files where empty lines are ignored. The text
behind the `#` char is considered as comments. The first valid line of the file
must list 2 integers defining the width and the height of the image. Then, each
-subsequent line must list 3 floating point data, representing the X, Y and Z
-component of a pixel. The pixels are row major ordered, i.e. they are listed
-row by row.
+subsequent line must list 3 pairs of floating point data, each pair
+representing the estimation and the uncertainty of the X, Y and Z component of
+a pixel. The pixels are row major ordered, i.e. they are listed row by row.
## How to build
diff --git a/src/htpp.c b/src/htpp.c
@@ -32,10 +32,11 @@ struct args {
const char* input;
const char* output;
double exposure;
+ int uncertainties;
int force_overwrite;
int quit;
};
-#define ARGS_DEFAULT__ {NULL,NULL,1.0,0,0}
+#define ARGS_DEFAULT__ {NULL,NULL,1.0,0,0,0}
static const struct args ARGS_DEFAULT = ARGS_DEFAULT__;
struct img {
@@ -69,6 +70,9 @@ print_help(const char* cmd)
printf(
" -o OUTPUT write PPM image to OUTPUT. If not defined, write results\n"
" to standard output.\n");
+ printf(
+" -u dump per channel uncertainties rather than luminance.\n");
+
printf("\n");
printf(
"%s (C) 2018 |Meso|Star>. This is free software released under the GNU GPL\n"
@@ -90,7 +94,7 @@ args_init(struct args* args, const int argc, char** argv)
res_T res = RES_OK;
ASSERT(args && argc && argv);
- while((opt = getopt(argc, argv, "e:fho:")) != -1) {
+ while((opt = getopt(argc, argv, "e:fho:u")) != -1) {
switch(opt) {
case 'e': res = cstr_to_double(optarg, &args->exposure); break;
case 'f': args->force_overwrite = 1; break;
@@ -100,6 +104,7 @@ args_init(struct args* args, const int argc, char** argv)
args->quit = 1;
goto exit;
case 'o': args->output = optarg; break;
+ case 'u': args->uncertainties = 1; break;
default: res = RES_BAD_ARG; break;
}
if(res != RES_OK) {
@@ -196,8 +201,9 @@ error:
goto exit;
}
+/* http://filmicworlds.com/blog/filmic-tonemapping-operators/ */
static double*
-tone_mapping(double pixel[3])
+filmic_tone_mapping(double pixel[3])
{
const double A = 0.15;
const double B = 0.50;
@@ -279,7 +285,11 @@ img_release(struct img* img)
}
static res_T
-img_load(struct img* img, FILE* stream, const char* stream_name)
+img_load
+ (struct img* img,
+ const int uncertainties, /* Load uncertainties rather than color */
+ FILE* stream,
+ const char* stream_name)
{
char* b = NULL; /* Temporary buffer used to read the stream */
size_t x, y;
@@ -320,6 +330,7 @@ img_load(struct img* img, FILE* stream, const char* stream_name)
FOR_EACH(y, 0, img->height) {
double* row = (double*)(img->pixels + y*img->pitch);
FOR_EACH(x, 0, img->width) {
+ double tmp[6];
double* pixel = row + x*3;
if(!read_line(&b, stream)) {
fprintf(stderr,
@@ -328,12 +339,15 @@ img_load(struct img* img, FILE* stream, const char* stream_name)
res = RES_IO_ERR;
goto error;
}
- if(cstr_to_list_double(b, ' ', pixel, 0, 3) != RES_OK) {
+ if(cstr_to_list_double(b, ' ', tmp, 0, 6) != RES_OK) {
fprintf(stderr, "%s: invalid XYZ value for the (%lu, %lu) pixel.\n",
stream_name, (unsigned long)x, (unsigned long)y);
res = RES_BAD_ARG;
goto error;
}
+ pixel[0] = tmp[uncertainties+0];
+ pixel[1] = tmp[uncertainties+2];
+ pixel[2] = tmp[uncertainties+4];
img->Yrange[0] = MMIN(img->Yrange[0], pixel[1]);
img->Yrange[1] = MMAX(img->Yrange[1], pixel[1]);
}
@@ -355,7 +369,7 @@ img_write_ppm(const struct img* img, FILE* stream, const char* stream_name)
ASSERT(img && stream && stream_name);
/* Write LDR image */
- i = fprintf(stream, "P3 %lu %lu\n255\n",
+ i = fprintf(stream, "P3 %lu %lu\n255\n",
(unsigned long)img->width, (unsigned long)img->height);
if(i < 0) {
fprintf(stderr, "%s: could not write the PPM header.\n", stream_name);
@@ -427,12 +441,11 @@ compute_img_normalization_factor(const struct img* img)
Ydelta = (img->Yrange[1] - img->Yrange[0]) / (double)histo_len;
/* Compute the upper bound luminance value of the found histogram entry */
- Ymax = img->Yrange[0]
+ Ymax = img->Yrange[0]
+ (double)(i+1/*Upper bound of the histogram entry*/)*Ydelta;
- /* Use the previously value as the normalization factor scaled by an
- * emperical factor arbitrarly set to 1.8 */
- return Ymax * 1.8;
+ /* Use the previous value as the normalization factor */
+ return Ymax;
}
/*******************************************************************************
@@ -468,7 +481,7 @@ main(int argc, char** argv)
stream_in_name = args.input;
}
- res = img_load(&img, stream_in, stream_in_name);
+ res = img_load(&img, args.uncertainties, stream_in, stream_in_name);
if(res != RES_OK) goto error;
Yscale = args.exposure / compute_img_normalization_factor(&img);
@@ -487,9 +500,11 @@ main(int argc, char** argv)
pixel[1] = pixel[1] * Yscale;
pixel[2] = pixel[2] * Yscale;
- XYZ_to_RGB(pixel); /* Convert in RGB color space */
- tone_mapping(pixel); /* Tone map the RGB pixel */
- RGB_to_sRGB(pixel); /* Convert in sRGB color space (i.e. gamma correction) */
+ if(!args.uncertainties) {
+ XYZ_to_RGB(pixel); /* Convert in RGB color space */
+ filmic_tone_mapping(pixel); /* Tone map the RGB pixel */
+ RGB_to_sRGB(pixel); /* Convert in sRGB color space (i.e. gamma correction) */
+ }
}
res = img_write_ppm(&img, stream_out, stream_out_name);