30
30
* @author Radoslaw Mantiuk, <radoslaw.mantiuk@gmail.com>
32
* $Id: contrast_domain.cpp,v 1.5 2007/06/16 19:23:08 rafm Exp $
32
* $Id: contrast_domain.cpp,v 1.6 2007/10/17 10:03:21 rafm Exp $
117
119
float matrix_median(int n, float* m);
118
120
void pyramid_gradient_multiply(PYRAMID* pyramid, float val);
122
void dump_matrix_to_file(int width, int height, float* m, const char *file_name);
120
123
void matrix_show(char* text, int rows, int cols, float* data);
121
124
void pyramid_show(PYRAMID* pyramid);
193
196
// upsampled matrix is twice bigger in each direction than data[]
194
197
// res should be a pointer to allocated memory for bigger matrix
195
198
// nearest neighborhood method - should be changed!
199
// cols and rows are the dimmensions of the output matrix
196
200
void ContrastDomain::matrix_upsample(int cols, int rows, float* in, float* out){
198
float dx = (float)cols / (float)(cols*2);
199
float dy = (float)rows / (float)(rows*2);
201
const int outRows = rows * 2;
202
const int outCols = cols * 2;
204
const float inRows = rows;
205
const float inCols = cols;
202
const int inRows = (rows)/2;
203
const int inCols = (cols)/2;
205
const int outRows = rows;
206
const int outCols = cols;
208
const float dx = (float)inCols / ((float)outCols);
209
const float dy = (float)inRows / ((float)outRows);
207
211
const float filterSize = 1;
241
// void ContrastDomain::matrix_upsample(int cols, int rows, float* in, float* out)
243
// const int inRows = rows/2;
244
// const int inCols = cols/2;
246
// const int outRows = rows;
247
// const int outCols = cols;
251
// for( y = 0, sy = 0; sy < inRows; y+=2, sy++ ) {
252
// float *inLine = in + sy*inCols;
253
// float *outLine = out + y*outCols;
254
// for( x = 0, sx = 0; sx < inCols; x += 2, sx++ ) {
255
// float &v = inLine[sx];
258
// outLine[x+outCols] = v;
259
// outLine[x+outCols+1] = v;
262
// // odd output size
264
// for( y = 0; y < (outRows& ~1); y++ )
265
// out[y*outCols+outCols-1] = out[y*outCols+outCols-2];
268
// for( x = 0; x < outCols; x++ ) {
269
// out[outCols*(outCols-1)+x] = out[outCols*(outCols-1)+x];
236
276
// downsample the matrix
237
277
void ContrastDomain::matrix_downsample(int cols, int rows, float* data, float* res){
239
const float inRows = rows;
240
const float inCols = cols;
242
const int outRows = rows / 2;
243
const int outCols = cols / 2;
245
const float dx = (float)inCols / (float)outCols;
246
const float dy = (float)inRows / (float)outRows;
280
const int inRows = rows;
281
const int inCols = cols;
283
const int outRows = (rows) / 2;
284
const int outCols = (cols) / 2;
286
const float dx = (float)inCols / ((float)outCols);
287
const float dy = (float)inRows / ((float)outRows);
248
289
const float filterSize = 0.5;
310
// void ContrastDomain::matrix_downsample(int cols, int rows, float* data, float* res){
312
// const float inRows = rows;
313
// const float inCols = cols;
315
// const int outRows = rows / 2;
316
// const int outCols = cols / 2;
318
// const float dx = (float)inCols / (float)outCols;
319
// const float dy = (float)inRows / (float)outRows;
321
// const float filterSize = 0.5;
326
// for( y = 0, sy = dy/2-0.5; y < outRows; y++, sy += dy )
327
// for( x = 0, sx = dx/2-0.5; x < outCols; x++, sx += dx ) {
331
// for( float ix = max( 0, ceilf( sx-dx*filterSize ) ); ix <= min( floorf( sx+dx*filterSize ), inCols-1 ); ix++ )
332
// for( float iy = max( 0, ceilf( sy-dx*filterSize ) ); iy <= min( floorf( sy+dx*filterSize), inRows-1 ); iy++ ) {
333
// pixVal += data[(int)ix + (int)iy * (int)inCols];
336
// res[x + y * outCols] = pixVal/w;
269
343
// return = a + b
270
344
float* ContrastDomain::matrix_add(int n, float* a, float* b){
271
345
for(int i=0; i<n; i++){
384
458
// calculate sum of divergences in the pyramid
385
459
// divergences for a particular levels should be calculated earlier
386
460
// and set in PYRAMID_LEVEL::divG
387
void ContrastDomain::pyramid_calculate_divergence_sum_in(PYRAMID* pyramid, float* divG_sum){
461
void ContrastDomain::pyramid_calculate_divergence_sum(PYRAMID* pyramid, float* divG_sum){
389
463
if(pyramid->next != NULL)
390
pyramid_calculate_divergence_sum_in((PYRAMID*)pyramid->next, divG_sum);
464
pyramid_calculate_divergence_sum((PYRAMID*)pyramid->next, divG_sum);
392
466
PYRAMID_LEVEL* pl = pyramid->level;
394
matrix_add(pl->rows * pl->cols, pl->divG, divG_sum);
396
468
float* temp = matrix_alloc(pl->rows*pl->cols);
397
matrix_copy(pl->rows*pl->cols, divG_sum, temp);
469
if(pyramid->next != NULL)
470
matrix_upsample(pl->cols, pl->rows, divG_sum, temp );
472
matrix_zero(pl->rows * pl->cols, temp);
474
matrix_add(pl->rows * pl->cols, pl->divG, temp);
399
matrix_upsample(pl->cols, pl->rows, temp, divG_sum);
477
// sprintf( name, "Up_%d.pfs", pl->cols );
478
// dump_matrix_to_file( pl->cols, pl->rows, temp, name );
480
matrix_copy(pl->rows*pl->cols, temp, divG_sum);
401
482
matrix_free(temp);
407
488
// calculate the sum of divergences for the all pyramid level
408
489
// the smaller divergence map is upsamled and added to the divergence map for the higher level of pyramid
409
void ContrastDomain::pyramid_calculate_divergence_sum(PYRAMID* pyramid, float* divG_sum){
411
PYRAMID_LEVEL* pl = pyramid->level;
412
matrix_zero(pl->rows * pl->cols, divG_sum);
414
if(pyramid->next != NULL)
415
pyramid_calculate_divergence_sum_in((PYRAMID*)pyramid->next, divG_sum);
490
// void ContrastDomain::pyramid_calculate_divergence_sum(PYRAMID* pyramid, float* divG_sum){
492
// PYRAMID_LEVEL* pl = pyramid->level;
493
// // matrix_zero(pl->rows * pl->cols, divG_sum);
495
// // if(pyramid->next != NULL)
496
// pyramid_calculate_divergence_sum_in((PYRAMID*)pyramid, divG_sum);
417
matrix_add(pl->rows * pl->cols, pl->divG, divG_sum);
498
// // matrix_add(pl->rows * pl->cols, pl->divG, divG_sum);
422
503
// calculate scale factors (Cx,Cy) for gradients (Gx,Gy)
423
504
// C is equal to EDGE_WEIGHT for gradients smaller than GFIXATE or 1.0 otherwise
429
510
float* C = matrix_alloc(n);
431
512
for(int i=0; i<n; i++){
433
if(fabs(G[i]) < GFIXATE)
514
// const float detectT = 0.001;
515
// const float g = max( detectT, fabs(G[i]) );
516
// const float a = 0.038737;
517
// const float b = 0.537756;
518
// C[i] = a*pow(g,b);
520
if(fabs(G[i]) < GFIXATE)
678
#define PFSEOL "\x0a"
679
void ContrastDomain::dump_matrix_to_file(int width, int height, float* m, const char *file_name){
681
FILE *fh = fopen( file_name, "wb" );
682
assert( fh != NULL );
684
fprintf( fh, "PFS1" PFSEOL "%d %d" PFSEOL "1" PFSEOL "0" PFSEOL
685
"%s" PFSEOL "0" PFSEOL "ENDH", width, height, "Y");
687
for( int y = 0; y < height; y++ )
688
for( int x = 0; x < width; x++ ) {
689
int idx = x + y*width;
690
fwrite( &(m[idx]), sizeof( float ), 1, fh );
592
696
// calculate gradients for the pyramid
593
697
void ContrastDomain::pyramid_calculate_gradient(PYRAMID* pyramid, float* lum){
600
704
calculate_gradient(pl->cols, pl->rows, lum_temp, pl->Gx, pl->Gy);
602
706
PYRAMID* pp = (PYRAMID*)pyramid->next;
707
PYRAMID* prev_pp = pyramid;
610
715
temp = matrix_alloc(pl->rows * pl->cols);
611
matrix_downsample(pl->cols*2, pl->rows*2, lum_temp, temp);
716
matrix_downsample(prev_pp->level->cols, prev_pp->level->rows, lum_temp, temp);
718
// fprintf( stderr, "%d x %d -> %d x %d\n", pl->cols, pl->rows,
719
// prev_pp->level->cols, prev_pp->level->rows );
722
// sprintf( name, "ds_%d.pfs", l++ );
723
// dump_matrix_to_file( pl->cols, pl->rows, temp, name );
613
725
calculate_gradient(pl->cols, pl->rows, temp, pl->Gx, pl->Gy);
615
727
matrix_free(lum_temp);
618
731
pp = (PYRAMID*)pp->next;
620
733
matrix_free(lum_temp);
627
740
void ContrastDomain::solveX(int n, float* b, float* x){
629
742
matrix_copy(n, b, x); // x = b
630
matrix_multiply_const(n, x, -0.25);
743
matrix_multiply_const(n, x, -0.25);
633
746
// divG_sum = A * x = sum(divG(x))
666
779
float* x = matrix_alloc(n); // allocate x matrix filled with zeros
667
780
matrix_zero(n, x); // x = 0
669
782
multiplyA(pyramid_tmp, pyramid, x, r); // r = A*x = divergence(x)
671
784
matrix_substract(n, b, r); // r = b - r
673
786
matrix_copy(n, r, rr); // rr = r
788
multiplyA(pyramid_tmp, pyramid, r, rr); // rr = A*r
677
792
bnrm = sqrt(matrix_DotProduct(n, b, b));
720
835
akden = matrix_DotProduct(n, z, pp); // alfa denominator
722
837
ak = bknum / akden; // alfa = ...
839
// This may need transpossing - possible bug
724
840
multiplyA(pyramid_tmp, pyramid, pp, zz); // zz = A*pp = divergence(pp)
726
842
// values for the next iterration
912
1028
// transform gradients to luminance
913
1029
float* ContrastDomain::transform_to_luminance(PYRAMID* pp){
915
1031
pyramid_calculate_scale_factor(pp); // calculate (Cx,Cy)
916
1032
pyramid_scale_gradient(pp); // scale small gradients by (Cx,Cy);
917
1033
pyramid_calculate_divergence(pp); // calculate divergence for the pyramid
1034
// dump_matrix_to_file( pp->next->level->cols, pp->next->level->rows, pp->next->level->Gx, "Gx.pfs" );
919
1036
float* b = matrix_alloc(pp->level->cols * pp->level->rows);
920
1037
pyramid_calculate_divergence_sum(pp, b); // calculate the sum od divergences (equal to b)
1039
// dump_matrix_to_file( pp->level->cols, pp->level->rows, b, "B.pfs" );
1041
// PYRAMID *pi = pp;
1043
// while( pi != NULL ) {
1044
// PYRAMID_LEVEL* pl = pi->level;
1046
// sprintf( name, "Cx_%d.pfs", i );
1047
// dump_matrix_to_file( pl->cols, pl->rows, pl->Cx, name );
1048
// sprintf( name, "Cy_%d.pfs", i );
1049
// dump_matrix_to_file( pl->cols, pl->rows, pl->Cx, name );
922
1054
float* x = linbcg(pp, b); // calculate luminances from gradients
1009
1141
PYRAMID* pp = pyramid_allocate(c,r); // create pyramid
1010
1142
pyramid_calculate_gradient(pp,Y); // calculate gradiens for pyramid
1012
pyramid_transform_to_R(pp); // transform gradients to R
1144
// dump_matrix_to_file( pp->next->level->cols, pp->next->level->rows, pp->next->level->Gx, "Gx2.pfs" );
1146
pyramid_transform_to_R(pp); // transform gradients to R
1015
1148
if( contrastFactor != 0 ) {
1016
1149
// Contrast mapping
1023
1156
pyramid_transform_to_G(pp); // transform R to gradients
1025
1158
float* x = transform_to_luminance(pp); // transform gradients to luminance Y
1027
// for (int i=0;i<rows*cols;i++) {
1028
// fprintf(stderr,"v=%f\n", (*Yo)(i));
1030
1160
float* temp = matrix_alloc(n);
1032
1162
matrix_copy(n, x, temp); // copy x to temp
1033
1163
qsort(temp, n, sizeof(float), sort_median); // sort temp in ascending order
1035
float median = (temp[(int)((n-1)/2)] + temp[(int)((n-1)/2+1)]) / 2.0; // calculate median
1165
// float median = (temp[(int)((n-1)/2)] + temp[(int)((n-1)/2+1)]) / 2.0; // calculate median
1036
1166
// c and r should be even
1037
1167
float CUT_MARGIN = 0.1;
1045
1175
float p_max = temp[(int)floor(trim)] * delta + temp[(int)ceil(trim)] * (1-delta);
1047
1177
matrix_free(temp);
1051
if( (p_max - median) > (median - p_min) )
1056
float l_max = median + d;
1057
float l_min = median - d;
1059
for(int j=0;j<n;j++){
1061
x[j] = (x[j] - l_min) / (l_max - l_min) * 2.5 - 2.5; // x scaled to <-2.5,0> range
1179
const float disp_dyn_range = 2.3;
1180
for(int j=0;j<n;j++) {
1181
x[j] = (x[j] - p_min) / (p_max - p_min) * disp_dyn_range - disp_dyn_range; // x scaled to <-2.5,0> range
1064
1184
for(int j=0;j<n;j++){
1084
1204
ContrastDomain contrast;
1085
1205
contrast.tone_mapping( cols, rows, R, G, B, Y, contrastFactor, saturationFactor, progress_report );