Changes to black compression and saturation controls. Black compression from 0-50 acts the same as 0-100 on the previous version, compressing dark tones without crushing blacks. 50-100 then starts crushing blacks until by 100 on the slider, all tones up to the set black point are sent to zero. In the new saturation control, negative values of the slider set a linear curve rather than an inverted S curve, and smoothly decrease saturation to zero across the board.
This commit is contained in:
394
rtengine/cfa_linedn_RT.cc
Normal file
394
rtengine/cfa_linedn_RT.cc
Normal file
@@ -0,0 +1,394 @@
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CFA line denoise by DCT filtering
|
||||
//
|
||||
// copyright (c) 2008-2010 Emil Martinec <ejmartin@uchicago.edu>
|
||||
//
|
||||
//
|
||||
// code dated: June 7, 2010
|
||||
//
|
||||
// cfa_linedn_RT.cc 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.
|
||||
//
|
||||
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#define TS 512 // Tile size
|
||||
|
||||
#define CLASS
|
||||
|
||||
|
||||
/*#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>*/
|
||||
#include <math.h>
|
||||
|
||||
|
||||
//#include "shrtdct_float.c"
|
||||
|
||||
|
||||
#define SQR(x) ((x)*(x))
|
||||
//#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
//#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
//#define LIM(x,min,max) MAX(min,MIN(x,max))
|
||||
//#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y))
|
||||
//#define CLIP(x) LIM(x,0,65535)
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void RawImageSource::CLASS cfa_linedn(float noise)
|
||||
{
|
||||
// local variables
|
||||
int height=H, width=W;
|
||||
int top, left, row, col;
|
||||
int rr, cc, indx, i, j;
|
||||
int ex, ey;
|
||||
int verbose=1;
|
||||
|
||||
const float clip_pt = 0.8*ri->defgain;
|
||||
|
||||
float eps=1e-5; //tolerance to avoid dividing by zero
|
||||
|
||||
float gauss[5] = {0.20416368871516755, 0.18017382291138087, 0.1238315368057753, 0.0662822452863612, 0.02763055063889883};
|
||||
float rolloff[8] = {0, 0.135335, 0.249352, 0.411112, 0.606531, 0.800737, 0.945959, 1}; //gaussian with sigma=3
|
||||
float window[8] = {0, .25, .75, 1, 1, .75, .25, 0}; //sine squared
|
||||
float noisevar, linehvar, linevvar, coeffsq;
|
||||
|
||||
float aarr[8][8], *dctblock[8];
|
||||
for (i = 0; i < 8; i++) dctblock[i] = aarr[i];
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if (plistener) {
|
||||
plistener->setProgressStr ("Line Denoise...");
|
||||
plistener->setProgress (0.0);
|
||||
}
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
noisevar=SQR(3*noise*65535); // _noise_ (as a fraction of saturation) is input to the algorithm
|
||||
float *cfain= new float[TS*TS];
|
||||
float *cfablur= new float[TS*TS];
|
||||
float *cfadiff= new float[TS*TS];
|
||||
float *cfadn= new float[TS*TS];
|
||||
|
||||
// Main algorithm: Tile loop
|
||||
for (top=0; top < height-16; top += TS-32)
|
||||
for (left=0; left < width-16; left += TS-32) {
|
||||
int bottom = MIN( top+TS,height);
|
||||
int right = MIN(left+TS, width);
|
||||
int numrows = bottom - top;
|
||||
int numcols = right - left;
|
||||
|
||||
// load CFA data; data should be in linear gamma space, before white balance multipliers are applied
|
||||
for (rr=top; rr < top+numrows; rr++)
|
||||
for (cc=left, indx=(rr-top)*TS; cc < left+numcols; cc++, indx++) {
|
||||
cfain[indx] = ri->data[rr][cc];
|
||||
}
|
||||
//pad the block to a multiple of 16 on both sides
|
||||
|
||||
if (numcols < TS) {
|
||||
indx=numcols % 16;
|
||||
for (i=0; i<(16-indx); i++)
|
||||
for (rr=0; rr<numrows; rr++)
|
||||
cfain[(rr)*TS+numcols+i+1]=cfain[(rr)*TS+numcols-i];
|
||||
numcols += 16-indx;
|
||||
}
|
||||
|
||||
if (numrows < TS) {
|
||||
indx=numrows % 16;
|
||||
for (i=0; i<(16-indx); i++)
|
||||
for (cc=0; cc<numcols; cc++)
|
||||
cfain[(numrows+i+1)*TS+cc]=cfain[(numrows-i)*TS+cc];
|
||||
numrows += 16-indx;
|
||||
}
|
||||
|
||||
//The cleaning algorithm starts here
|
||||
|
||||
|
||||
//gaussian blur of CFA data
|
||||
for (rr=8; rr < numrows-8; rr++)
|
||||
for (indx=rr*TS; indx < rr*TS+numcols; indx++) {
|
||||
|
||||
cfablur[indx]=gauss[0]*cfain[indx];
|
||||
for (i=1; i<5; i++) {
|
||||
cfablur[indx] += gauss[i]*(cfain[indx-(2*i)*TS]+cfain[indx+(2*i)*TS]);
|
||||
}
|
||||
}
|
||||
for (rr=8; rr < numrows-8; rr++)
|
||||
for (indx=rr*TS+8; indx < rr*TS+numcols-8; indx++) {
|
||||
|
||||
cfadn[indx] = gauss[0]*cfablur[indx];
|
||||
for (i=1; i<5; i++) {
|
||||
cfadn[indx] += gauss[i]*(cfablur[indx-2*i]+cfablur[indx+2*i]);
|
||||
}
|
||||
cfadiff[indx]=cfain[indx]-cfadn[indx]; // hipass cfa data
|
||||
}
|
||||
|
||||
//begin block DCT
|
||||
for (ey=0; ey<2; ey++) // (ex,ey) specify RGGB subarray
|
||||
for (ex=0; ex<2; ex++)
|
||||
for (rr=8+ey; rr < numrows-22; rr+=8) // (rr,cc) shift by 8 to overlap blocks
|
||||
for (cc=8+ex; cc < numcols-22; cc+=8) {
|
||||
//grab an 8x8 block of a given RGGB channel
|
||||
for (i=0; i<8; i++)
|
||||
for (j=0; j<8; j++) {
|
||||
dctblock[i][j]=cfadiff[(rr+2*i)*TS+cc+2*j];
|
||||
}
|
||||
|
||||
ddct8x8s(-1, dctblock); //forward DCT
|
||||
|
||||
linehvar=linevvar=0;
|
||||
for (i=4; i<8; i++) {
|
||||
linehvar += SQR(dctblock[0][i]);
|
||||
linevvar += SQR(dctblock[i][0]);
|
||||
}
|
||||
//Wiener filter for line denoising; roll off low frequencies
|
||||
if (noisevar>linehvar) {
|
||||
for (i=1; i<8; i++) {
|
||||
coeffsq=SQR(dctblock[0][i]);
|
||||
dctblock[0][i] *= coeffsq/(coeffsq+rolloff[i]*noisevar+eps);
|
||||
}
|
||||
}
|
||||
if (noisevar>linevvar) {
|
||||
for (i=1; i<8; i++) {
|
||||
coeffsq=SQR(dctblock[i][0]);
|
||||
dctblock[i][0] *= coeffsq/(coeffsq+rolloff[i]*noisevar+eps);
|
||||
}
|
||||
}
|
||||
|
||||
ddct8x8s(1, dctblock); //inverse DCT
|
||||
|
||||
//multiply by window fn and add to output (cfadn)
|
||||
for (i=0; i<8; i++)
|
||||
for (j=0; j<8; j++) {
|
||||
cfadn[(rr+2*i)*TS+cc+2*j] += window[i]*window[j]*dctblock[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// copy smoothed results back to image matrix
|
||||
for (rr=16; rr < numrows-16; rr++) {
|
||||
row = rr + top;
|
||||
for (col=16+left, indx=rr*TS+16; indx < rr*TS+numcols-16; indx++, col++) {
|
||||
if (ri->data[row][col]<clip_pt && cfadn[indx]<clip_pt)
|
||||
ri->data[row][col] = CLIP((int)(cfadn[indx]+ 0.5));
|
||||
}
|
||||
}
|
||||
if(plistener) plistener->setProgress(fabs((float)top/height));
|
||||
}
|
||||
// clean up
|
||||
delete [] cfain;
|
||||
delete [] cfablur;
|
||||
delete [] cfadiff;
|
||||
delete [] cfadn;
|
||||
|
||||
}
|
||||
#undef TS
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
/*
|
||||
Discrete Cosine Transform Code
|
||||
|
||||
Copyright(C) 1997 Takuya OOURA (email: ooura@mmm.t.u-tokyo.ac.jp).
|
||||
You may use, copy, modify this code for any purpose and
|
||||
without fee. You may distribute this ORIGINAL package.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Short Discrete Cosine Transform
|
||||
data length :8x8
|
||||
method :row-column, radix 4 FFT
|
||||
functions
|
||||
ddct8x8s : 8x8 DCT
|
||||
function prototypes
|
||||
void ddct8x8s(int isgn, float **a);
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
-------- 8x8 DCT (Discrete Cosine Transform) / Inverse of DCT --------
|
||||
[definition]
|
||||
<case1> Normalized 8x8 IDCT
|
||||
C[k1][k2] = (1/4) * sum_j1=0^7 sum_j2=0^7
|
||||
a[j1][j2] * s[j1] * s[j2] *
|
||||
cos(pi*j1*(k1+1/2)/8) *
|
||||
cos(pi*j2*(k2+1/2)/8), 0<=k1<8, 0<=k2<8
|
||||
(s[0] = 1/sqrt(2), s[j] = 1, j > 0)
|
||||
<case2> Normalized 8x8 DCT
|
||||
C[k1][k2] = (1/4) * s[k1] * s[k2] * sum_j1=0^7 sum_j2=0^7
|
||||
a[j1][j2] *
|
||||
cos(pi*(j1+1/2)*k1/8) *
|
||||
cos(pi*(j2+1/2)*k2/8), 0<=k1<8, 0<=k2<8
|
||||
(s[0] = 1/sqrt(2), s[j] = 1, j > 0)
|
||||
[usage]
|
||||
<case1>
|
||||
ddct8x8s(1, a);
|
||||
<case2>
|
||||
ddct8x8s(-1, a);
|
||||
[parameters]
|
||||
a[0...7][0...7] :input/output data (double **)
|
||||
output data
|
||||
a[k1][k2] = C[k1][k2], 0<=k1<8, 0<=k2<8
|
||||
*/
|
||||
|
||||
|
||||
/* Cn_kR = sqrt(2.0/n) * cos(pi/2*k/n) */
|
||||
/* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */
|
||||
/* Wn_kR = cos(pi/2*k/n) */
|
||||
/* Wn_kI = sin(pi/2*k/n) */
|
||||
#define C8_1R 0.49039264020161522456
|
||||
#define C8_1I 0.09754516100806413392
|
||||
#define C8_2R 0.46193976625564337806
|
||||
#define C8_2I 0.19134171618254488586
|
||||
#define C8_3R 0.41573480615127261854
|
||||
#define C8_3I 0.27778511650980111237
|
||||
#define C8_4R 0.35355339059327376220
|
||||
#define W8_4R 0.70710678118654752440
|
||||
|
||||
|
||||
void RawImageSource::ddct8x8s(int isgn, float **a)
|
||||
{
|
||||
int j;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
float xr, xi;
|
||||
|
||||
if (isgn < 0) {
|
||||
for (j = 0; j <= 7; j++) {
|
||||
x0r = a[0][j] + a[7][j];
|
||||
x1r = a[0][j] - a[7][j];
|
||||
x0i = a[2][j] + a[5][j];
|
||||
x1i = a[2][j] - a[5][j];
|
||||
x2r = a[4][j] + a[3][j];
|
||||
x3r = a[4][j] - a[3][j];
|
||||
x2i = a[6][j] + a[1][j];
|
||||
x3i = a[6][j] - a[1][j];
|
||||
xr = x0r + x2r;
|
||||
xi = x0i + x2i;
|
||||
a[0][j] = C8_4R * (xr + xi);
|
||||
a[4][j] = C8_4R * (xr - xi);
|
||||
xr = x0r - x2r;
|
||||
xi = x0i - x2i;
|
||||
a[2][j] = C8_2R * xr - C8_2I * xi;
|
||||
a[6][j] = C8_2R * xi + C8_2I * xr;
|
||||
xr = W8_4R * (x1i - x3i);
|
||||
x1i = W8_4R * (x1i + x3i);
|
||||
x3i = x1i - x3r;
|
||||
x1i += x3r;
|
||||
x3r = x1r - xr;
|
||||
x1r += xr;
|
||||
a[1][j] = C8_1R * x1r - C8_1I * x1i;
|
||||
a[7][j] = C8_1R * x1i + C8_1I * x1r;
|
||||
a[3][j] = C8_3R * x3r - C8_3I * x3i;
|
||||
a[5][j] = C8_3R * x3i + C8_3I * x3r;
|
||||
}
|
||||
for (j = 0; j <= 7; j++) {
|
||||
x0r = a[j][0] + a[j][7];
|
||||
x1r = a[j][0] - a[j][7];
|
||||
x0i = a[j][2] + a[j][5];
|
||||
x1i = a[j][2] - a[j][5];
|
||||
x2r = a[j][4] + a[j][3];
|
||||
x3r = a[j][4] - a[j][3];
|
||||
x2i = a[j][6] + a[j][1];
|
||||
x3i = a[j][6] - a[j][1];
|
||||
xr = x0r + x2r;
|
||||
xi = x0i + x2i;
|
||||
a[j][0] = C8_4R * (xr + xi);
|
||||
a[j][4] = C8_4R * (xr - xi);
|
||||
xr = x0r - x2r;
|
||||
xi = x0i - x2i;
|
||||
a[j][2] = C8_2R * xr - C8_2I * xi;
|
||||
a[j][6] = C8_2R * xi + C8_2I * xr;
|
||||
xr = W8_4R * (x1i - x3i);
|
||||
x1i = W8_4R * (x1i + x3i);
|
||||
x3i = x1i - x3r;
|
||||
x1i += x3r;
|
||||
x3r = x1r - xr;
|
||||
x1r += xr;
|
||||
a[j][1] = C8_1R * x1r - C8_1I * x1i;
|
||||
a[j][7] = C8_1R * x1i + C8_1I * x1r;
|
||||
a[j][3] = C8_3R * x3r - C8_3I * x3i;
|
||||
a[j][5] = C8_3R * x3i + C8_3I * x3r;
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j <= 7; j++) {
|
||||
x1r = C8_1R * a[1][j] + C8_1I * a[7][j];
|
||||
x1i = C8_1R * a[7][j] - C8_1I * a[1][j];
|
||||
x3r = C8_3R * a[3][j] + C8_3I * a[5][j];
|
||||
x3i = C8_3R * a[5][j] - C8_3I * a[3][j];
|
||||
xr = x1r - x3r;
|
||||
xi = x1i + x3i;
|
||||
x1r += x3r;
|
||||
x3i -= x1i;
|
||||
x1i = W8_4R * (xr + xi);
|
||||
x3r = W8_4R * (xr - xi);
|
||||
xr = C8_2R * a[2][j] + C8_2I * a[6][j];
|
||||
xi = C8_2R * a[6][j] - C8_2I * a[2][j];
|
||||
x0r = C8_4R * (a[0][j] + a[4][j]);
|
||||
x0i = C8_4R * (a[0][j] - a[4][j]);
|
||||
x2r = x0r - xr;
|
||||
x2i = x0i - xi;
|
||||
x0r += xr;
|
||||
x0i += xi;
|
||||
a[0][j] = x0r + x1r;
|
||||
a[7][j] = x0r - x1r;
|
||||
a[2][j] = x0i + x1i;
|
||||
a[5][j] = x0i - x1i;
|
||||
a[4][j] = x2r - x3i;
|
||||
a[3][j] = x2r + x3i;
|
||||
a[6][j] = x2i - x3r;
|
||||
a[1][j] = x2i + x3r;
|
||||
}
|
||||
for (j = 0; j <= 7; j++) {
|
||||
x1r = C8_1R * a[j][1] + C8_1I * a[j][7];
|
||||
x1i = C8_1R * a[j][7] - C8_1I * a[j][1];
|
||||
x3r = C8_3R * a[j][3] + C8_3I * a[j][5];
|
||||
x3i = C8_3R * a[j][5] - C8_3I * a[j][3];
|
||||
xr = x1r - x3r;
|
||||
xi = x1i + x3i;
|
||||
x1r += x3r;
|
||||
x3i -= x1i;
|
||||
x1i = W8_4R * (xr + xi);
|
||||
x3r = W8_4R * (xr - xi);
|
||||
xr = C8_2R * a[j][2] + C8_2I * a[j][6];
|
||||
xi = C8_2R * a[j][6] - C8_2I * a[j][2];
|
||||
x0r = C8_4R * (a[j][0] + a[j][4]);
|
||||
x0i = C8_4R * (a[j][0] - a[j][4]);
|
||||
x2r = x0r - xr;
|
||||
x2i = x0i - xi;
|
||||
x0r += xr;
|
||||
x0i += xi;
|
||||
a[j][0] = x0r + x1r;
|
||||
a[j][7] = x0r - x1r;
|
||||
a[j][2] = x0i + x1i;
|
||||
a[j][5] = x0i - x1i;
|
||||
a[j][4] = x2r - x3i;
|
||||
a[j][3] = x2r + x3i;
|
||||
a[j][6] = x2i - x3r;
|
||||
a[j][1] = x2i + x3r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user