1 /**
2  * @brief Contrast mapping TMO
3  *
4  * From:
5  *
6  * Rafal Mantiuk, Karol Myszkowski, Hans-Peter Seidel.
7  * A Perceptual Framework for Contrast Processing of High Dynamic Range Images
8  * In: ACM Transactions on Applied Perception 3 (3), pp. 286-308, 2006
9  * http://www.mpi-inf.mpg.de/~mantiuk/contrast_domain/
10  *
11  * This file is a part of PFSTMO package.
12  * ----------------------------------------------------------------------
13  * Copyright (C) 2007 Grzegorz Krawczyk
14  *
15  *  This program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  This program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with this program; if not, write to the Free Software
27  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  * ----------------------------------------------------------------------
29  *
30  * @author Radoslaw Mantiuk, <radoslaw.mantiuk@gmail.com>
31  * @author Rafal Mantiuk, <mantiuk@gmail.com>
32  * Updated 2007/12/17 by Ed Brambley <E.J.Brambley@damtp.cam.ac.uk>
33  *
34  * $Id: pfstmo_mantiuk06.cpp,v 1.10 2009/09/02 01:11:39 rafm Exp $
35  */
36 
37 #include <config.h>
38 
39 #include <iostream>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <math.h>
43 #include <getopt.h>
44 #include <fcntl.h>
45 #include <iostream>
46 
47 #include <pfs.h>
48 
49 #include "contrast_domain.h"
50 
51 
52 #define PROG_NAME "pfstmo_mantiuk06"
53 
54 class QuietException
55 {
56 };
57 
58 using namespace std;
59 
printHelp()60 void printHelp()
61 {
62   fprintf( stderr, PROG_NAME " (" PACKAGE_STRING ") : \n"
63     "\t[--factor <val>] [--saturation <val>] [--equalize-contrast <val>]\n"
64     "\t[--help] [--quiet] [--verbose]\n"
65     "See man page for more information.\n" );
66 }
67 
68 
69 bool verbose = false;
70 bool quiet = false;
71 
progress_report(int progress)72 int progress_report( int progress )
73 {
74   if( !quiet ) {
75     fprintf( stderr, "\rcompleted %d%%", progress );
76     if( progress == 100 )
77       fprintf( stderr, "\n" );
78   }
79 
80   return PFSTMO_CB_CONTINUE;
81 }
82 
83 
84 
tmo_mantiuk06(int argc,char * argv[])85 void tmo_mantiuk06(int argc, char * argv[])
86 {
87 
88   //--- default tone mapping parameters;
89   float scaleFactor = 0.1f;
90   float saturationFactor = 0.8f;
91   bool cont_map = false, cont_eq = false, bcg = false;
92   int itmax = 200;
93   float tol = 1e-3;
94 
95   //--- process command line args
96 
97   static struct option cmdLineOptions[] = {
98     { "help", no_argument, NULL, 'h' },
99     { "verbose", no_argument, NULL, 'v' },
100 //    { "bcg", no_argument, NULL, 'b' },
101     { "factor", required_argument, NULL, 'f' },
102     { "saturation", required_argument, NULL, 's' },
103 //    { "itmax", required_argument, NULL, 'm' },
104 //    { "tol", required_argument, NULL, 't' },
105     { "quiet", no_argument, NULL, 'q' },
106     { "equalize-contrast", required_argument, NULL, 'e' },
107     { NULL, 0, NULL, 0 }
108   };
109 
110   int optionIndex = 0;
111   while( 1 ) {
112     int c = getopt_long (argc, argv, "vhf:s:e:q", cmdLineOptions, &optionIndex);
113     if( c == -1 ) break;
114     switch( c ) {
115     case 'h':
116       printHelp();
117       throw QuietException();
118     case 'q':
119       quiet = true;
120       break;
121     case 'v':
122       verbose = true;
123       break;
124     case 'b':
125       bcg = true;
126       break;
127     case 'e':
128       cont_eq = true;
129       scaleFactor = 0.0f - (float)strtod( optarg, NULL );
130       if( scaleFactor > 0.0f )
131         throw pfs::Exception("incorrect contrast scale factor, accepted range is any positive number");
132       break;
133     case 's':
134       saturationFactor = (float)strtod( optarg, NULL );
135       if( saturationFactor < 0.0f || saturationFactor > 2.0f )
136         throw pfs::Exception("incorrect saturation factor, accepted range is (0..2)");
137       break;
138     case 'f':
139       cont_map = true;
140       scaleFactor = (float)strtod( optarg, NULL );
141       if( scaleFactor < 0.0f || scaleFactor > 1.0f )
142         throw pfs::Exception("incorrect contrast scale factor, accepted range is (0..1)");
143       break;
144 //     case 'i':
145 //       interpolate_method = atoi( optarg );
146 //       if (interpolate_method < 1 || interpolate_method > 3)
147 //         throw pfs::Exception("incorrect interpolation method, accepted values are 1, 2 or 3.");
148 //       break;
149 //     case 'm':
150 //       itmax = atoi( optarg );
151 //       if (itmax < 1)
152 //         throw pfs::Exception("incorrect maximum number of iterations.");
153 //       break;
154 //     case 't':
155 //       tol = (float)strtod( optarg, NULL );
156 //       if( tol < 0.0f || tol > 1.0f )
157 //         throw pfs::Exception("incorrect convergence tolerance, accepted range is (0..1)");
158 //      break;
159     case '?':
160       throw QuietException();
161     case ':':
162       throw QuietException();
163     }
164   }
165 
166   if( cont_eq && cont_map )
167     throw pfs::Exception( "the 'factor' parameter cannot be used in combination with contrast equalization" );
168 
169   if( scaleFactor < 0 ) {
170     VERBOSE_STR << "algorithm: contrast equalization" << endl;
171     VERBOSE_STR << "contrast scale factor = " << -scaleFactor << endl;
172   } else {
173     VERBOSE_STR << "algorithm: contrast mapping" << endl;
174     VERBOSE_STR << "contrast scale factor = " << scaleFactor << endl;
175   }
176 
177   VERBOSE_STR << "saturation factor = " << saturationFactor << endl;
178 
179   if (bcg)
180     {
181       VERBOSE_STR << "using biconjugate gradients (itmax = " << itmax << ", tol = " << tol << ")." << endl;
182     }
183   else
184     {
185       VERBOSE_STR << "using conjugate gradients (itmax = " << itmax << ", tol = " << tol << ")." << endl;
186     }
187 
188   pfs::DOMIO pfsio;
189 
190   while( true ) {
191     pfs::Frame *frame = pfsio.readFrame( stdin );
192     if( frame == NULL )
193       break;
194 
195     pfs::Channel *inX, *inY, *inZ;
196 
197     frame->getXYZChannels(inX, inY, inZ);
198     int cols = frame->getWidth();
199     int rows = frame->getHeight();
200 
201     pfs::Array2DImpl R( cols, rows );
202 
203     pfs::transformColorSpace( pfs::CS_XYZ, inX, inY, inZ, pfs::CS_RGB, inX, &R, inZ );
204 
205     tmo_mantiuk06_contmap( cols, rows, inX->getRawData(), R.getRawData(), inZ->getRawData(), inY->getRawData(),
206       scaleFactor, saturationFactor, bcg, itmax, tol, progress_report );
207 
208     pfs::transformColorSpace( pfs::CS_RGB, inX, &R, inZ, pfs::CS_XYZ, inX, inY, inZ );
209     frame->getTags()->setString("LUMINANCE", "RELATIVE");
210 
211     pfsio.writeFrame( frame, stdout );
212     pfsio.freeFrame(frame);
213   }
214 }
215 
216 
main(int argc,char * argv[])217 int main( int argc, char* argv[] )
218 {
219   try {
220     tmo_mantiuk06( argc, argv );
221   }
222   catch( pfs::Exception ex ) {
223     fprintf( stderr, PROG_NAME " error: %s\n", ex.getMessage() );
224     return EXIT_FAILURE;
225   }
226   catch( QuietException  ex ) {
227     return EXIT_FAILURE;
228   }
229   return EXIT_SUCCESS;
230 }
231 
232