4006 lines
153 KiB
C++
4006 lines
153 KiB
C++
/*
|
|
* This file is part of RawTherapee.
|
|
*
|
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
|
*
|
|
* RawTherapee 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.
|
|
*
|
|
* RawTherapee 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 RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <cmath>
|
|
#include <cassert>
|
|
|
|
#include "rawimagesource.h"
|
|
#include "rawimagesource_i.h"
|
|
#include "median.h"
|
|
#include "rawimage.h"
|
|
#include "mytime.h"
|
|
#include "iccmatrices.h"
|
|
#include "iccstore.h"
|
|
#include "image8.h"
|
|
#include "curves.h"
|
|
#include "dfmanager.h"
|
|
#include "slicer.h"
|
|
#include "rt_math.h"
|
|
#include "color.h"
|
|
#include "../rtgui/multilangmgr.h"
|
|
#include "procparams.h"
|
|
#include "sleef.c"
|
|
#include "opthelper.h"
|
|
|
|
#ifdef _OPENMP
|
|
#include <omp.h>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
namespace rtengine {
|
|
#undef ABS
|
|
#undef DIST
|
|
|
|
#define ABS(a) ((a)<0?-(a):(a))
|
|
#define DIST(a,b) (ABS(a-b))
|
|
#define CLIREF(x) LIM(x,-200000.0f,200000.0f) // avoid overflow : do not act directly on image[] or pix[]
|
|
#define x1125(a) (a + xdivf(a, 3))
|
|
#define x0875(a) (a - xdivf(a, 3))
|
|
#define x0250(a) xdivf(a, 2)
|
|
#define x00625(a) xdivf(a, 4)
|
|
#define x0125(a) xdivf(a, 3)
|
|
|
|
|
|
#define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} }
|
|
#define PIX_SORTV(av,bv) tempv = _mm_min_ps(av,bv); bv = _mm_max_ps(av,bv); av = tempv;
|
|
extern const Settings* settings;
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
void RawImageSource::eahd_demosaic () {
|
|
if (plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::eahd]));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
|
|
// prepare cache and constants for cielab conversion
|
|
//TODO: revisit after conversion to D50 illuminant
|
|
lc00 = (0.412453 * imatrices.rgb_cam[0][0] + 0.357580 * imatrices.rgb_cam[0][1] + 0.180423 * imatrices.rgb_cam[0][2]) ;// / 0.950456;
|
|
lc01 = (0.412453 * imatrices.rgb_cam[1][0] + 0.357580 * imatrices.rgb_cam[1][1] + 0.180423 * imatrices.rgb_cam[1][2]) ;// / 0.950456;
|
|
lc02 = (0.412453 * imatrices.rgb_cam[2][0] + 0.357580 * imatrices.rgb_cam[2][1] + 0.180423 * imatrices.rgb_cam[2][2]) ;// / 0.950456;
|
|
|
|
lc10 = 0.212671 * imatrices.rgb_cam[0][0] + 0.715160 * imatrices.rgb_cam[0][1] + 0.072169 * imatrices.rgb_cam[0][2];
|
|
lc11 = 0.212671 * imatrices.rgb_cam[1][0] + 0.715160 * imatrices.rgb_cam[1][1] + 0.072169 * imatrices.rgb_cam[1][2];
|
|
lc12 = 0.212671 * imatrices.rgb_cam[2][0] + 0.715160 * imatrices.rgb_cam[2][1] + 0.072169 * imatrices.rgb_cam[2][2];
|
|
|
|
lc20 = (0.019334 * imatrices.rgb_cam[0][0] + 0.119193 * imatrices.rgb_cam[0][1] + 0.950227 * imatrices.rgb_cam[0][2]) ;// / 1.088754;
|
|
lc21 = (0.019334 * imatrices.rgb_cam[1][0] + 0.119193 * imatrices.rgb_cam[1][1] + 0.950227 * imatrices.rgb_cam[1][2]) ;// / 1.088754;
|
|
lc22 = (0.019334 * imatrices.rgb_cam[2][0] + 0.119193 * imatrices.rgb_cam[2][1] + 0.950227 * imatrices.rgb_cam[2][2]) ;// / 1.088754;
|
|
|
|
int maxindex = 3*65536;//2*65536 3 = avoid crash 3/2013 J.Desmis
|
|
cache = new double[maxindex];
|
|
threshold = (int)(0.008856*MAXVALD);
|
|
for (int i=0; i<maxindex; i++)
|
|
cache[i] = exp(1.0/3.0 * log(double(i) / MAXVALD));
|
|
|
|
// end of cielab preparation
|
|
|
|
float* rh[3];
|
|
float* gh[4];
|
|
float* bh[3];
|
|
float* rv[3];
|
|
float* gv[4];
|
|
float* bv[3];
|
|
float* lLh[3];
|
|
float* lah[3];
|
|
float* lbh[3];
|
|
float* lLv[3];
|
|
float* lav[3];
|
|
float* lbv[3];
|
|
float* homh[3];
|
|
float* homv[3];
|
|
|
|
for (int i=0; i<4; i++) {
|
|
gh[i] = new float[W];
|
|
gv[i] = new float[W];
|
|
}
|
|
|
|
for (int i=0; i<3; i++) {
|
|
rh[i] = new float[W];
|
|
bh[i] = new float[W];
|
|
rv[i] = new float[W];
|
|
bv[i] = new float[W];
|
|
lLh[i] = new float[W];
|
|
lah[i] = new float[W];
|
|
lbh[i] = new float[W];
|
|
lLv[i] = new float[W];
|
|
lav[i] = new float[W];
|
|
lbv[i] = new float[W];
|
|
homh[i] = new float[W];
|
|
homv[i] = new float[W];
|
|
}
|
|
|
|
// interpolate first two lines
|
|
interpolate_row_g (gh[0], gv[0], 0);
|
|
interpolate_row_g (gh[1], gv[1], 1);
|
|
interpolate_row_g (gh[2], gv[2], 2);
|
|
interpolate_row_rb (rh[0], bh[0], NULL, gh[0], gh[1], 0);
|
|
interpolate_row_rb (rv[0], bv[0], NULL, gv[0], gv[1], 0);
|
|
interpolate_row_rb (rh[1], bh[1], gh[0], gh[1], gh[2], 1);
|
|
interpolate_row_rb (rv[1], bv[1], gv[0], gv[1], gv[2], 1);
|
|
|
|
convert_to_cielab_row (rh[0], gh[0], bh[0], lLh[0], lah[0], lbh[0]);
|
|
convert_to_cielab_row (rv[0], gv[0], bv[0], lLv[0], lav[0], lbv[0]);
|
|
convert_to_cielab_row (rh[1], gh[1], bh[1], lLh[1], lah[1], lbh[1]);
|
|
convert_to_cielab_row (rv[1], gv[1], bv[1], lLv[1], lav[1], lbv[1]);
|
|
|
|
for (int j=0; j<W; j++) {
|
|
homh[0][j] = 0;
|
|
homv[0][j] = 0;
|
|
homh[1][j] = 0;
|
|
homv[1][j] = 0;
|
|
}
|
|
|
|
int dLmaph[9];
|
|
int dLmapv[9];
|
|
int dCamaph[9];
|
|
int dCamapv[9];
|
|
int dCbmaph[9];
|
|
int dCbmapv[9];
|
|
|
|
for (int i=1; i<H-1; i++) {
|
|
int ix = i%3;
|
|
int imx = (i-1)%3;
|
|
int ipx = (i+1)%3;
|
|
|
|
if (i<H-2) {
|
|
interpolate_row_g (gh[(i+2)%4], gv[(i+2)%4], i+2);
|
|
interpolate_row_rb (rh[(i+1)%3], bh[(i+1)%3], gh[i%4], gh[(i+1)%4], gh[(i+2)%4], i+1);
|
|
interpolate_row_rb (rv[(i+1)%3], bv[(i+1)%3], gv[i%4], gv[(i+1)%4], gv[(i+2)%4], i+1);
|
|
}
|
|
else {
|
|
interpolate_row_rb (rh[(i+1)%3], bh[(i+1)%3], gh[i%4], gh[(i+1)%4], NULL, i+1);
|
|
interpolate_row_rb (rv[(i+1)%3], bv[(i+1)%3], gv[i%4], gv[(i+1)%4], NULL, i+1);
|
|
}
|
|
|
|
convert_to_cielab_row (rh[(i+1)%3], gh[(i+1)%4], bh[(i+1)%3], lLh[(i+1)%3], lah[(i+1)%3], lbh[(i+1)%3]);
|
|
convert_to_cielab_row (rv[(i+1)%3], gv[(i+1)%4], bv[(i+1)%3], lLv[(i+1)%3], lav[(i+1)%3], lbv[(i+1)%3]);
|
|
|
|
for (int j=0; j<W; j++) {
|
|
homh[ipx][j] = 0;
|
|
homv[ipx][j] = 0;
|
|
}
|
|
int sh, sv, idx;
|
|
for (int j=1; j<W-1; j++) {
|
|
int dmi = 0;
|
|
for (int x=-1; x<=1; x++) {
|
|
idx = (i+x)%3;
|
|
for (int y=-1; y<=1; y++) {
|
|
// compute distance in a, b, and L
|
|
if (dmi<4) {
|
|
sh=homh[idx][j+y];
|
|
sv=homv[idx][j+y];
|
|
if (sh>sv) { // fixate horizontal pixel
|
|
dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]);
|
|
dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]);
|
|
dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]);
|
|
dLmapv[dmi] = DIST(lLv[ix][j], lLh[idx][j+y]);
|
|
dCamapv[dmi] = DIST(lav[ix][j], lah[idx][j+y]);
|
|
dCbmapv[dmi] = DIST(lbv[ix][j], lbh[idx][j+y]);
|
|
}
|
|
else if (sh<sv) {
|
|
dLmaph[dmi] = DIST(lLh[ix][j], lLv[idx][j+y]);
|
|
dCamaph[dmi] = DIST(lah[ix][j], lav[idx][j+y]);
|
|
dCbmaph[dmi] = DIST(lbh[ix][j], lbv[idx][j+y]);
|
|
dLmapv[dmi] = DIST(lLv[ix][j], lLv[idx][j+y]);
|
|
dCamapv[dmi] = DIST(lav[ix][j], lav[idx][j+y]);
|
|
dCbmapv[dmi] = DIST(lbv[ix][j], lbv[idx][j+y]);
|
|
}
|
|
else {
|
|
dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]);
|
|
dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]);
|
|
dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]);
|
|
dLmapv[dmi] = DIST(lLv[ix][j], lLv[idx][j+y]);
|
|
dCamapv[dmi] = DIST(lav[ix][j], lav[idx][j+y]);
|
|
dCbmapv[dmi] = DIST(lbv[ix][j], lbv[idx][j+y]);
|
|
}
|
|
}
|
|
else {
|
|
dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]);
|
|
dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]);
|
|
dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]);
|
|
dLmapv[dmi] = DIST(lLv[ix][j], lLv[idx][j+y]);
|
|
dCamapv[dmi] = DIST(lav[ix][j], lav[idx][j+y]);
|
|
dCbmapv[dmi] = DIST(lbv[ix][j], lbv[idx][j+y]);
|
|
}
|
|
dmi++;
|
|
}
|
|
}
|
|
// compute eL & eC
|
|
int eL = min(max(dLmaph[3],dLmaph[5]),max(dLmapv[1],dLmapv[7]));
|
|
int eCa = min(max(dCamaph[3],dCamaph[5]),max(dCamapv[1],dCamapv[7]));
|
|
int eCb = min(max(dCbmaph[3],dCbmaph[5]),max(dCbmapv[1],dCbmapv[7]));
|
|
|
|
int wh = 0;
|
|
for (int dmi=0; dmi<9; dmi++)
|
|
if (dLmaph[dmi]<=eL && dCamaph[dmi]<=eCa && dCbmaph[dmi]<=eCb)
|
|
wh++;
|
|
|
|
int wv = 0;
|
|
for (int dmi=0; dmi<9; dmi++)
|
|
if (dLmapv[dmi]<=eL && dCamapv[dmi]<=eCa && dCbmapv[dmi]<=eCb)
|
|
wv++;
|
|
|
|
homh[imx][j-1]+=wh;
|
|
homh[imx][j] +=wh;
|
|
homh[imx][j+1]+=wh;
|
|
homh[ix][j-1] +=wh;
|
|
homh[ix][j] +=wh;
|
|
homh[ix][j+1] +=wh;
|
|
homh[ipx][j-1]+=wh;
|
|
homh[ipx][j] +=wh;
|
|
homh[ipx][j+1]+=wh;
|
|
|
|
homv[imx][j-1]+=wv;
|
|
homv[imx][j] +=wv;
|
|
homv[imx][j+1]+=wv;
|
|
homv[ix][j-1] +=wv;
|
|
homv[ix][j] +=wv;
|
|
homv[ix][j+1] +=wv;
|
|
homv[ipx][j-1]+=wv;
|
|
homv[ipx][j] +=wv;
|
|
homv[ipx][j+1]+=wv;
|
|
}
|
|
//}
|
|
// finalize image
|
|
int hc, vc;
|
|
for (int j=0; j<W; j++) {
|
|
if (ri->ISGREEN(i-1,j))
|
|
green[i-1][j] = rawData[i-1][j];
|
|
else {
|
|
hc = homh[imx][j];
|
|
vc = homv[imx][j];
|
|
if (hc > vc)
|
|
green[i-1][j] = gh[(i-1)%4][j];
|
|
else if (hc < vc)
|
|
green[i-1][j] = gv[(i-1)%4][j];
|
|
else
|
|
green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2;
|
|
}
|
|
}
|
|
|
|
if (!(i%20) && plistener)
|
|
plistener->setProgress ((double)i / (H-2));
|
|
}
|
|
// finish H-2th and H-1th row, homogenity value is still valailable
|
|
int hc, vc;
|
|
for (int i=H-1; i<H+1; i++)
|
|
for (int j=0; j<W; j++) {
|
|
hc = homh[(i-1)%3][j];
|
|
vc = homv[(i-1)%3][j];
|
|
if (hc > vc)
|
|
green[i-1][j] = gh[(i-1)%4][j];
|
|
else if (hc < vc)
|
|
green[i-1][j] = gv[(i-1)%4][j];
|
|
else
|
|
green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2;
|
|
}
|
|
|
|
freeArray2<float>(rh, 3);
|
|
freeArray2<float>(gh, 4);
|
|
freeArray2<float>(bh, 3);
|
|
freeArray2<float>(rv, 3);
|
|
freeArray2<float>(gv, 4);
|
|
freeArray2<float>(bv, 3);
|
|
freeArray2<float>(lLh, 3);
|
|
freeArray2<float>(lah, 3);
|
|
freeArray2<float>(lbh, 3);
|
|
freeArray2<float>(homh, 3);
|
|
freeArray2<float>(lLv, 3);
|
|
freeArray2<float>(lav, 3);
|
|
freeArray2<float>(lbv, 3);
|
|
freeArray2<float>(homv, 3);
|
|
|
|
// Interpolate R and B
|
|
for (int i=0; i<H; i++) {
|
|
if (i==0)
|
|
// rm, gm, bm must be recovered
|
|
//interpolate_row_rb_mul_pp (red, blue, NULL, green[i], green[i+1], i, rm, gm, bm, 0, W, 1);
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], NULL, green[i], green[i+1], i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
else if (i==H-1)
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], green[i-1], green[i], NULL, i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
else
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], green[i-1], green[i], green[i+1], i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
}
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
void RawImageSource::hphd_vertical (float** hpmap, int col_from, int col_to) {
|
|
float* temp = new float[max(W,H)];
|
|
float* avg = new float[max(W,H)];
|
|
float* dev = new float[max(W,H)];
|
|
|
|
memset (temp, 0, max(W,H)*sizeof(float));
|
|
memset (avg, 0, max(W,H)*sizeof(float));
|
|
memset (dev, 0, max(W,H)*sizeof(float));
|
|
|
|
for (int k=col_from; k<col_to; k++) {
|
|
for (int i=5; i<H-5; i++) {
|
|
temp[i] = (rawData[i-5][k] - 8*rawData[i-4][k] + 27*rawData[i-3][k] - 48*rawData[i-2][k] + 42*rawData[i-1][k] -
|
|
(rawData[i+5][k] - 8*rawData[i+4][k] + 27*rawData[i+3][k] - 48*rawData[i+2][k] + 42*rawData[i+1][k])) / 100.0;
|
|
temp[i] = ABS(temp[i]);
|
|
}
|
|
for (int j=4; j<H-4; j++) {
|
|
float avgL = (temp[j-4] + temp[j-3] + temp[j-2] + temp[j-1] + temp[j] + temp[j+1] + temp[j+2] + temp[j+3] + temp[j+4]) / 9.0;
|
|
avg[j] = avgL;
|
|
float devL = ((temp[j-4]-avgL)*(temp[j-4]-avgL) + (temp[j-3]-avgL)*(temp[j-3]-avgL) + (temp[j-2]-avgL)*(temp[j-2]-avgL) + (temp[j-1]-avgL)*(temp[j-1]-avgL) + (temp[j]-avgL)*(temp[j]-avgL) + (temp[j+1]-avgL)*(temp[j+1]-avgL) + (temp[j+2]-avgL)*(temp[j+2]-avgL) + (temp[j+3]-avgL)*(temp[j+3]-avgL) + (temp[j+4]-avgL)*(temp[j+4]-avgL)) / 9.0;
|
|
if (devL<0.001) devL = 0.001;
|
|
dev[j] = devL;
|
|
}
|
|
for (int j=5; j<H-5; j++) {
|
|
float avgL = avg[j-1];
|
|
float avgR = avg[j+1];
|
|
float devL = dev[j-1];
|
|
float devR = dev[j+1];
|
|
hpmap[j][k] = avgL + (avgR - avgL) * devL / (devL + devR);
|
|
}
|
|
}
|
|
delete [] temp;
|
|
delete [] avg;
|
|
delete [] dev;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
void RawImageSource::hphd_horizontal (float** hpmap, int row_from, int row_to) {
|
|
float* temp = new float[max(W,H)];
|
|
float* avg = new float[max(W,H)];
|
|
float* dev = new float[max(W,H)];
|
|
|
|
memset (temp, 0, max(W,H)*sizeof(float));
|
|
memset (avg, 0, max(W,H)*sizeof(float));
|
|
memset (dev, 0, max(W,H)*sizeof(float));
|
|
|
|
for (int i=row_from; i<row_to; i++) {
|
|
for (int j=5; j<W-5; j++) {
|
|
temp[j] = (rawData[i][j-5] - 8*rawData[i][j-4] + 27*rawData[i][j-3] - 48*rawData[i][j-2] + 42*rawData[i][j-1] -
|
|
(rawData[i][j+5] - 8*rawData[i][j+4] + 27*rawData[i][j+3] - 48*rawData[i][j+2] + 42*rawData[i][j+1])) / 100;
|
|
temp[j] = ABS(temp[j]);
|
|
}
|
|
for (int j=4; j<W-4; j++) {
|
|
float avgL = (temp[j-4] + temp[j-3] + temp[j-2] + temp[j-1] + temp[j] + temp[j+1] + temp[j+2] + temp[j+3] + temp[j+4]) / 9.0;
|
|
avg[j] = avgL;
|
|
float devL = ((temp[j-4]-avgL)*(temp[j-4]-avgL) + (temp[j-3]-avgL)*(temp[j-3]-avgL) + (temp[j-2]-avgL)*(temp[j-2]-avgL) + (temp[j-1]-avgL)*(temp[j-1]-avgL) + (temp[j]-avgL)*(temp[j]-avgL) + (temp[j+1]-avgL)*(temp[j+1]-avgL) + (temp[j+2]-avgL)*(temp[j+2]-avgL) + (temp[j+3]-avgL)*(temp[j+3]-avgL) + (temp[j+4]-avgL)*(temp[j+4]-avgL)) / 9.0;
|
|
if (devL<0.001) devL = 0.001;
|
|
dev[j] = devL;
|
|
}
|
|
for (int j=5; j<W-5; j++) {
|
|
float avgL = avg[j-1];
|
|
float avgR = avg[j+1];
|
|
float devL = dev[j-1];
|
|
float devR = dev[j+1];
|
|
float hpv = avgL + (avgR - avgL) * devL / (devL + devR);
|
|
if (hpmap[i][j] < 0.8*hpv)
|
|
hpmap[i][j] = 2;
|
|
else if (hpv < 0.8*hpmap[i][j])
|
|
hpmap[i][j] = 1;
|
|
else
|
|
hpmap[i][j] = 0;
|
|
}
|
|
}
|
|
delete [] temp;
|
|
delete [] avg;
|
|
delete [] dev;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
void RawImageSource::hphd_green (float** hpmap) {
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (int i=3; i<H-3; i++) {
|
|
for (int j=3; j<W-3; j++) {
|
|
if (ri->ISGREEN(i,j))
|
|
green[i][j] = rawData[i][j];
|
|
else {
|
|
if (hpmap[i][j]==1) {
|
|
int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) /2);
|
|
int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) /2);
|
|
|
|
int dx = rawData[i][j+1] - rawData[i][j-1];
|
|
int d1 = rawData[i][j+3] - rawData[i][j+1];
|
|
int d2 = rawData[i][j+2] - rawData[i][j];
|
|
int d3 = (rawData[i-1][j+2] - rawData[i-1][j]) /2;
|
|
int d4 = (rawData[i+1][j+2] - rawData[i+1][j]) /2;
|
|
|
|
double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
d1 = rawData[i][j-3] - rawData[i][j-1];
|
|
d2 = rawData[i][j-2] - rawData[i][j];
|
|
d3 = (rawData[i-1][j-2] - rawData[i-1][j]) /2;
|
|
d4 = (rawData[i+1][j-2] - rawData[i+1][j]) /2;
|
|
|
|
double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
green[i][j] = (e2 * g2 + e4 * g4) / (e2 + e4);
|
|
}
|
|
else if (hpmap[i][j]==2) {
|
|
int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) /2);
|
|
int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) /2);
|
|
|
|
int dy = rawData[i+1][j] - rawData[i-1][j];
|
|
int d1 = rawData[i-1][j] - rawData[i-3][j];
|
|
int d2 = rawData[i][j] - rawData[i-2][j];
|
|
int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) /2;
|
|
int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) /2;
|
|
|
|
double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
d1 = rawData[i+1][j] - rawData[i+3][j];
|
|
d2 = rawData[i][j] - rawData[i+2][j];
|
|
d3 = (rawData[i][j-1] - rawData[i+2][j-1]) /2;
|
|
d4 = (rawData[i][j+1] - rawData[i+2][j+1]) /2;
|
|
|
|
double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
green[i][j] = (e1 * g1 + e3 * g3) / (e1 + e3);
|
|
}
|
|
else {
|
|
int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) /2);
|
|
int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) /2);
|
|
int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) /2);
|
|
int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) /2);
|
|
|
|
int dx = rawData[i][j+1] - rawData[i][j-1];
|
|
int dy = rawData[i+1][j] - rawData[i-1][j];
|
|
|
|
int d1 = rawData[i-1][j] - rawData[i-3][j];
|
|
int d2 = rawData[i][j] - rawData[i-2][j];
|
|
int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) /2;
|
|
int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) /2;
|
|
|
|
double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
d1 = rawData[i][j+3] - rawData[i][j+1];
|
|
d2 = rawData[i][j+2] - rawData[i][j];
|
|
d3 = (rawData[i-1][j+2] - rawData[i-1][j]) /2;
|
|
d4 = (rawData[i+1][j+2] - rawData[i+1][j]) /2;
|
|
|
|
double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
d1 = rawData[i+1][j] - rawData[i+3][j];
|
|
d2 = rawData[i][j] - rawData[i+2][j];
|
|
d3 = (rawData[i][j-1] - rawData[i+2][j-1]) /2;
|
|
d4 = (rawData[i][j+1] - rawData[i+2][j+1]) /2;
|
|
|
|
double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
d1 = rawData[i][j-3] - rawData[i][j-1];
|
|
d2 = rawData[i][j-2] - rawData[i][j];
|
|
d3 = (rawData[i-1][j-2] - rawData[i-1][j]) /2;
|
|
d4 = (rawData[i+1][j-2] - rawData[i+1][j]) /2;
|
|
|
|
double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4));
|
|
|
|
green[i][j] = (e1*g1 + e2*g2 + e3*g3 + e4*g4) / (e1 + e2 + e3 + e4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
void RawImageSource::hphd_demosaic () {
|
|
if (plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::hphd]));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
|
|
float** hpmap = allocArray< float >(W,H, true);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
{
|
|
int tid = omp_get_thread_num();
|
|
int nthreads = omp_get_num_threads();
|
|
int blk = W/nthreads;
|
|
|
|
if (tid<nthreads-1)
|
|
hphd_vertical (hpmap, tid*blk, (tid+1)*blk);
|
|
else
|
|
hphd_vertical (hpmap, tid*blk, W);
|
|
}
|
|
#else
|
|
hphd_vertical (hpmap, 0, W);
|
|
#endif
|
|
if (plistener)
|
|
plistener->setProgress (0.33);
|
|
|
|
for (int i=0; i<H; i++)
|
|
memset(hpmap[i], 0, W*sizeof(char));
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
{
|
|
int tid = omp_get_thread_num();
|
|
int nthreads = omp_get_num_threads();
|
|
int blk = H/nthreads;
|
|
|
|
if (tid<nthreads-1)
|
|
hphd_horizontal (hpmap, tid*blk, (tid+1)*blk);
|
|
else
|
|
hphd_horizontal (hpmap, tid*blk, H);
|
|
}
|
|
#else
|
|
hphd_horizontal (hpmap, 0, H);
|
|
#endif
|
|
|
|
hphd_green (hpmap);
|
|
freeArray<float>(hpmap, H);//TODO: seems to cause sigabrt ??? why???
|
|
|
|
if (plistener)
|
|
plistener->setProgress (0.66);
|
|
|
|
for (int i=0; i<H; i++) {
|
|
if (i==0)
|
|
// rm, gm, bm must be recovered
|
|
//interpolate_row_rb_mul_pp (red, blue, NULL, green[i], green[i+1], i, rm, gm, bm, 0, W, 1);
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], NULL, green[i], green[i+1], i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
else if (i==H-1)
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], green[i-1], green[i], NULL, i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
else
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], green[i-1], green[i], green[i+1], i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
}
|
|
if (plistener)
|
|
plistener->setProgress (1.0);
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
#define fc(row,col) (prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
|
|
typedef unsigned short ushort;
|
|
void RawImageSource::vng4_demosaic () {
|
|
const signed short int *cp, terms[] = {
|
|
-2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01,
|
|
-2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01,
|
|
-2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03,
|
|
-2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06,
|
|
-2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04,
|
|
-1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01,
|
|
-1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40,
|
|
-1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11,
|
|
-1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11,
|
|
-1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22,
|
|
-1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44,
|
|
-1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10,
|
|
-1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04,
|
|
+0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40,
|
|
+0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20,
|
|
+0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08,
|
|
+0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20,
|
|
+0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44,
|
|
+0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60,
|
|
+0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80,
|
|
+1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40,
|
|
+1,+0,+2,+1,0,0x10
|
|
},
|
|
chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
|
|
|
|
double progress = 0.0;
|
|
const bool plistenerActive = plistener;
|
|
|
|
if (plistenerActive) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::vng4]));
|
|
plistener->setProgress (progress);
|
|
}
|
|
|
|
const unsigned prefilters = ri->prefilters;
|
|
const int width=W, height=H;
|
|
const int colors=4;
|
|
float (*image)[4];
|
|
|
|
image = (float (*)[4]) calloc (height*width, sizeof *image);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (int ii=0; ii<H; ii++)
|
|
for (int jj=0; jj<W; jj++)
|
|
image[ii*W+jj][fc(ii,jj)] = rawData[ii][jj];
|
|
|
|
{
|
|
int lcode[16][16][32];
|
|
float mul[16][16][8];
|
|
float csum[16][16][4];
|
|
|
|
// first linear interpolation
|
|
for (int row=0; row < 16; row++)
|
|
for (int col=0; col < 16; col++) {
|
|
int * ip = lcode[row][col];
|
|
int mulcount=0;
|
|
float sum[4];
|
|
memset (sum, 0, sizeof sum);
|
|
for (int y=-1; y <= 1; y++)
|
|
for (int x=-1; x <= 1; x++) {
|
|
int shift = (y==0) + (x==0);
|
|
if (shift == 2)
|
|
continue;
|
|
int color = fc(row+y,col+x);
|
|
*ip++ = (width*y + x)*4 + color;
|
|
|
|
mul[row][col][mulcount] = (1 << shift);
|
|
*ip++ = color;
|
|
sum[color] += (1 << shift);
|
|
mulcount++;
|
|
}
|
|
int colcount = 0;
|
|
for (int c=0; c < colors; c++)
|
|
if (c != fc(row,col)) {
|
|
*ip++ = c;
|
|
csum[row][col][colcount] = sum[c];
|
|
colcount ++;
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (int row=1; row < height-1; row++) {
|
|
for (int col=1; col < width-1; col++) {
|
|
float * pix = image[row*width+col];
|
|
int * ip = lcode[row & 15][col & 15];
|
|
float sum[4];
|
|
memset (sum, 0, sizeof sum);
|
|
for (int i=0; i<8;i++, ip+=2)
|
|
sum[ip[1]] += pix[ip[0]] * mul[row & 15][col & 15][i];
|
|
for (int i=0; i<colors-1;i++, ip++)
|
|
pix[ip[0]] = sum[ip[0]] / csum[row & 15][col & 15][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
const int prow=7, pcol=1;
|
|
int *code[8][2];
|
|
int t, g;
|
|
int * ip = (int *) calloc ((prow+1)*(pcol+1), 1280);
|
|
for (int row=0; row <= prow; row++) /* Precalculate for VNG */
|
|
for (int col=0; col <= pcol; col++) {
|
|
code[row][col] = ip;
|
|
for (cp=terms, t=0; t < 64; t++) {
|
|
int y1 = *cp++;
|
|
int x1 = *cp++;
|
|
int y2 = *cp++;
|
|
int x2 = *cp++;
|
|
int weight = *cp++;
|
|
int grads = *cp++;
|
|
int color = fc(row+y1,col+x1);
|
|
if (fc(row+y2,col+x2) != color)
|
|
continue;
|
|
int diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1;
|
|
if (abs(y1-y2) == diag && abs(x1-x2) == diag)
|
|
continue;
|
|
*ip++ = (y1*width + x1)*4 + color;
|
|
*ip++ = (y2*width + x2)*4 + color;
|
|
*ip++ = weight;
|
|
for (g=0; g < 8; g++)
|
|
if (grads & (1<<g))
|
|
*ip++ = g;
|
|
*ip++ = -1;
|
|
}
|
|
*ip++ = INT_MAX;
|
|
for (cp=chood, g=0; g < 8; g++) {
|
|
int y = *cp++;
|
|
int x = *cp++;
|
|
*ip++ = (y*width + x) * 4;
|
|
int color = fc(row,col);
|
|
if (fc(row+y,col+x) != color && fc(row+y*2,col+x*2) == color)
|
|
*ip++ = (y*width + x) * 8 + color;
|
|
else
|
|
*ip++ = 0;
|
|
}
|
|
}
|
|
|
|
if(plistenerActive) {
|
|
progress = 0.1;
|
|
plistener->setProgress (progress);
|
|
}
|
|
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
#endif
|
|
{
|
|
float gval[8], thold, sum[3];
|
|
int g;
|
|
const int progressStep = 64;
|
|
const double progressInc = (0.98-progress)/((height-2)/progressStep);
|
|
#ifdef _OPENMP
|
|
#pragma omp for nowait
|
|
#endif
|
|
for (int row=2; row < height-2; row++) { /* Do VNG interpolation */
|
|
for (int col=2; col < width-2; col++) {
|
|
float * pix = image[row*width+col];
|
|
int * ip = code[row & prow][col & pcol];
|
|
memset (gval, 0, sizeof gval);
|
|
while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */
|
|
float diff = fabsf(pix[g] - pix[ip[1]]) * (1<< ip[2]);
|
|
gval[ip[3]] += diff;
|
|
ip+=4;
|
|
while ((g = *ip++) != -1)
|
|
gval[g] += diff;
|
|
}
|
|
ip++;
|
|
{
|
|
float gmin, gmax;
|
|
gmin = gmax = gval[0]; /* Choose a threshold */
|
|
for (g=1; g < 8; g++) {
|
|
if (gmin > gval[g])
|
|
gmin = gval[g];
|
|
if (gmax < gval[g])
|
|
gmax = gval[g];
|
|
}
|
|
thold = gmin + (gmax /2);
|
|
}
|
|
memset (sum, 0, sizeof sum);
|
|
float t1,t2;
|
|
int color = fc(row,col);
|
|
t1 = t2 = pix[color];
|
|
if(color&1) {
|
|
int num = 0;
|
|
for (g=0; g < 8; g++,ip+=2) { /* Average the neighbors */
|
|
if (gval[g] <= thold) {
|
|
if(ip[1])
|
|
sum[0] += (t1 + pix[ip[1]])*0.5f;
|
|
sum[1] += pix[ip[0] + (color ^ 2)];
|
|
num++;
|
|
}
|
|
}
|
|
t1 += (sum[1] - sum[0]) / num;
|
|
} else {
|
|
int num = 0;
|
|
for (g=0; g < 8; g++,ip+=2) { /* Average the neighbors */
|
|
if (gval[g] <= thold) {
|
|
sum[1] += pix[ip[0] + 1];
|
|
sum[2] += pix[ip[0] + 3];
|
|
if(ip[1])
|
|
sum[0] += (t1 + pix[ip[1]])*0.5f;
|
|
num++;
|
|
}
|
|
}
|
|
t1 += (sum[1] - sum[0]) / num;
|
|
t2 += (sum[2] - sum[0]) / num;
|
|
}
|
|
green[row][col] = 0.5f * (t1 + t2);
|
|
}
|
|
if(plistenerActive) {
|
|
if((row % progressStep) == 0)
|
|
#ifdef _OPENMP
|
|
#pragma omp critical (updateprogress)
|
|
#endif
|
|
{
|
|
progress += progressInc;
|
|
plistener->setProgress (progress);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
free (code[0][0]);
|
|
free (image);
|
|
if(plistenerActive)
|
|
plistener->setProgress (0.98);
|
|
|
|
// Interpolate R and B
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (int i=0; i<H; i++) {
|
|
if (i==0)
|
|
// rm, gm, bm must be recovered
|
|
//interpolate_row_rb_mul_pp (red, blue, NULL, green[i], green[i+1], i, rm, gm, bm, 0, W, 1);
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], NULL, green[i], green[i+1], i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
else if (i==H-1)
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], green[i-1], green[i], NULL, i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
else
|
|
interpolate_row_rb_mul_pp (red[i], blue[i], green[i-1], green[i], green[i+1], i, 1.0, 1.0, 1.0, 0, W, 1);
|
|
}
|
|
if(plistenerActive)
|
|
plistener->setProgress (1.0);
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#undef fc
|
|
#define fc(row,col) \
|
|
(ri->get_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
|
|
|
|
#define FORCC for (int c=0; c < colors; c++)
|
|
|
|
/*
|
|
Patterned Pixel Grouping Interpolation by Alain Desbiolles
|
|
*/
|
|
void RawImageSource::ppg_demosaic()
|
|
{
|
|
int width=W, height=H;
|
|
int dir[5] = { 1, width, -1, -width, 1 };
|
|
int row, col, diff[2], guess[2], c, d, i;
|
|
float (*pix)[4];
|
|
|
|
float (*image)[4];
|
|
|
|
if (plistener) {
|
|
// looks like ppg isn't supported anymore
|
|
//plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::ppg]));
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "xxx"));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
|
|
image = (float (*)[4]) calloc (H*W, sizeof *image);
|
|
for (int ii=0; ii<H; ii++)
|
|
for (int jj=0; jj<W; jj++)
|
|
image[ii*W+jj][fc(ii,jj)] = rawData[ii][jj];
|
|
|
|
border_interpolate(3, image);
|
|
|
|
/* Fill in the green layer with gradients and pattern recognition: */
|
|
for (row=3; row < height-3; row++) {
|
|
for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) {
|
|
pix = image + row*width+col;
|
|
for (i=0; (d=dir[i]) > 0; i++) {
|
|
guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2
|
|
- pix[-2*d][c] - pix[2*d][c];
|
|
diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) +
|
|
ABS(pix[ 2*d][c] - pix[ 0][c]) +
|
|
ABS(pix[ -d][1] - pix[ d][1]) ) * 3 +
|
|
( ABS(pix[ 3*d][1] - pix[ d][1]) +
|
|
ABS(pix[-3*d][1] - pix[-d][1]) ) * 2;
|
|
}
|
|
d = dir[i = diff[0] > diff[1]];
|
|
pix[0][1] = ULIM(static_cast<float>(guess[i] >> 2), pix[d][1], pix[-d][1]);
|
|
}
|
|
if(plistener) plistener->setProgress(0.33*row/(height-3));
|
|
}
|
|
/* Calculate red and blue for each green pixel: */
|
|
for (row=1; row < height-1; row++) {
|
|
for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) {
|
|
pix = image + row*width+col;
|
|
for (i=0; (d=dir[i]) > 0; c=2-c, i++)
|
|
pix[0][c] = CLIP(0.5*(pix[-d][c] + pix[d][c] + 2*pix[0][1]
|
|
- pix[-d][1] - pix[d][1]) );
|
|
}
|
|
if(plistener) plistener->setProgress(0.33 + 0.33*row/(height-1));
|
|
}
|
|
/* Calculate blue for red pixels and vice versa: */
|
|
for (row=1; row < height-1; row++) {
|
|
for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) {
|
|
pix = image + row*width+col;
|
|
for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) {
|
|
diff[i] = ABS(pix[-d][c] - pix[d][c]) +
|
|
ABS(pix[-d][1] - pix[0][1]) +
|
|
ABS(pix[ d][1] - pix[0][1]);
|
|
guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1]
|
|
- pix[-d][1] - pix[d][1];
|
|
}
|
|
if (diff[0] != diff[1])
|
|
pix[0][c] = CLIP(guess[diff[0] > diff[1]] /2);
|
|
else
|
|
pix[0][c] = CLIP((guess[0]+guess[1]) /4);
|
|
}
|
|
if(plistener) plistener->setProgress(0.67 + 0.33*row/(height-1));
|
|
}
|
|
|
|
red(W,H);
|
|
for (int i=0; i<H; i++)
|
|
for (int j=0; j<W; j++) {
|
|
red[i][j] = image[i*W+j][0];
|
|
}
|
|
green(W,H);
|
|
for (int i=0; i<H; i++)
|
|
for (int j=0; j<W; j++) {
|
|
green[i][j] = image[i*W+j][1];
|
|
}
|
|
blue(W,H);
|
|
for (int i=0; i<H; i++)
|
|
for (int j=0; j<W; j++) {
|
|
blue[i][j] = image[i*W+j][2];
|
|
}
|
|
free (image);
|
|
}
|
|
|
|
void RawImageSource::border_interpolate(unsigned int border, float (*image)[4], unsigned int start, unsigned int end)
|
|
{
|
|
unsigned row, col, y, x, f, c, sum[8];
|
|
unsigned int width=W, height=H;
|
|
unsigned int colors = 3;
|
|
|
|
if (end == 0 )end = H;
|
|
for (row=start; row < end; row++)
|
|
for (col=0; col < width; col++) {
|
|
if (col==border && row >= border && row < height-border)
|
|
col = width-border;
|
|
memset (sum, 0, sizeof sum);
|
|
for (y=row-1; y != row+2; y++)
|
|
for (x=col-1; x != col+2; x++)
|
|
if (y < height && x < width) {
|
|
f = fc(y,x);
|
|
sum[f] += image[y*width+x][f];
|
|
sum[f+4]++;
|
|
}
|
|
f = fc(row,col);
|
|
FORCC if (c != f && sum[c+4])
|
|
image[row*width+col][c] = sum[c] / sum[c+4];
|
|
}
|
|
}
|
|
|
|
void RawImageSource::border_interpolate2( int winw, int winh, int lborders)
|
|
{
|
|
int bord=lborders;
|
|
int width=winw;
|
|
int height=winh;
|
|
for (int i=0; i<height; i++) {
|
|
|
|
float sum[6];
|
|
|
|
for (int j=0; j<bord; j++) {//first few columns
|
|
for (int c=0; c<6; c++) sum[c]=0;
|
|
for (int i1=i-1; i1<i+2; i1++)
|
|
for (int j1=j-1; j1<j+2; j1++) {
|
|
if ((i1 > -1) && (i1 < height) && (j1 > -1)) {
|
|
int c = FC(i1,j1);
|
|
sum[c] += rawData[i1][j1];
|
|
sum[c+3]++;
|
|
}
|
|
}
|
|
int c=FC(i,j);
|
|
if (c==1) {
|
|
red[i][j]=sum[0]/sum[3];
|
|
green[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
green[i][j]=sum[1]/sum[4];
|
|
if (c==0) {
|
|
red[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
red[i][j]=sum[0]/sum[3];
|
|
blue[i][j]=rawData[i][j];
|
|
}
|
|
}
|
|
}//j
|
|
|
|
for (int j=width-bord; j<width; j++) {//last few columns
|
|
for (int c=0; c<6; c++) sum[c]=0;
|
|
for (int i1=i-1; i1<i+2; i1++)
|
|
for (int j1=j-1; j1<j+2; j1++) {
|
|
if ((i1 > -1) && (i1 < height ) && (j1 < width)) {
|
|
int c = FC(i1,j1);
|
|
sum[c] += rawData[i1][j1];
|
|
sum[c+3]++;
|
|
}
|
|
}
|
|
int c=FC(i,j);
|
|
if (c==1) {
|
|
red[i][j]=sum[0]/sum[3];
|
|
green[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
green[i][j]=sum[1]/sum[4];
|
|
if (c==0) {
|
|
red[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
red[i][j]=sum[0]/sum[3];
|
|
blue[i][j]=rawData[i][j];
|
|
}
|
|
}
|
|
}//j
|
|
}//i
|
|
for (int i=0; i<bord; i++) {
|
|
|
|
float sum[6];
|
|
|
|
for (int j=bord; j<width-bord; j++) {//first few rows
|
|
for (int c=0; c<6; c++) sum[c]=0;
|
|
for (int i1=i-1; i1<i+2; i1++)
|
|
for (int j1=j-1; j1<j+2; j1++) {
|
|
if ((i1 > -1) && (i1 < height) && (j1 > -1)) {
|
|
int c = FC(i1,j1);
|
|
sum[c] += rawData[i1][j1];
|
|
sum[c+3]++;
|
|
}
|
|
}
|
|
int c=FC(i,j);
|
|
if (c==1) {
|
|
red[i][j]=sum[0]/sum[3];
|
|
green[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
green[i][j]=sum[1]/sum[4];
|
|
if (c==0) {
|
|
red[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
red[i][j]=sum[0]/sum[3];
|
|
blue[i][j]=rawData[i][j];
|
|
}
|
|
}
|
|
}//j
|
|
}
|
|
|
|
for (int i=height-bord; i<height; i++) {
|
|
|
|
float sum[6];
|
|
|
|
for (int j=bord; j<width-bord; j++) {//last few rows
|
|
for (int c=0; c<6; c++) sum[c]=0;
|
|
for (int i1=i-1; i1<i+2; i1++)
|
|
for (int j1=j-1; j1<j+2; j1++) {
|
|
if ((i1 > -1) && (i1 < height) && (j1 < width)) {
|
|
int c = FC(i1,j1);
|
|
sum[c] += rawData[i1][j1];
|
|
sum[c+3]++;
|
|
}
|
|
}
|
|
int c=FC(i,j);
|
|
if (c==1) {
|
|
red[i][j]=sum[0]/sum[3];
|
|
green[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
green[i][j]=sum[1]/sum[4];
|
|
if (c==0) {
|
|
red[i][j]=rawData[i][j];
|
|
blue[i][j]=sum[2]/sum[5];
|
|
} else {
|
|
red[i][j]=sum[0]/sum[3];
|
|
blue[i][j]=rawData[i][j];
|
|
}
|
|
}
|
|
}//j
|
|
}
|
|
|
|
}
|
|
|
|
// Joint Demosaicing and Denoising using High Order Interpolation Techniques
|
|
// Revision 0.9.1a - 09/02/2010 - Contact info: luis.sanz.rodriguez@gmail.com
|
|
// Copyright Luis Sanz Rodriguez 2010
|
|
// Adapted to RT by Jacques Desmis 3/2013
|
|
|
|
void RawImageSource::jdl_interpolate_omp() // from "Lassus"
|
|
{
|
|
int width=W, height=H;
|
|
int row,col,c,d,i,u=width,v=2*u,w=3*u,x=4*u,y=5*u,z=6*u,indx,(*dif)[2],(*chr)[2];
|
|
float f[4],g[4];
|
|
float (*image)[4];
|
|
image = (float (*)[4]) calloc (width*height, sizeof *image);
|
|
dif = (int (*)[2]) calloc(width*height, sizeof *dif);
|
|
chr = (int (*)[2]) calloc(width*height, sizeof *chr);
|
|
if (plistener) {
|
|
// this function seems to be unused
|
|
//plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::jdl]));
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "xxx"));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel default(none) shared(image,width,height,u,w,v,y,x,z,dif,chr) private(row,col,f,g,indx,c,d,i)
|
|
#endif
|
|
{
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int ii=0; ii<height; ii++)
|
|
for (int jj=0; jj<width; jj++)
|
|
image[ii*width+jj][fc(ii,jj)] = rawData[ii][jj];
|
|
|
|
border_interpolate(6, image);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (row=5; row < height-5; row++)
|
|
for (col=5+(FC(row,1)&1),indx=row*width+col,c=FC(row,col); col < u-5; col+=2,indx+=2) {
|
|
f[0]=1.f+abs(image[indx-u][1]-image[indx-w][1])+abs(image[indx-u][1]-image[indx+u][1])+abs(image[indx][c]-image[indx-v][c])+abs(image[indx-v][c]-image[indx-x][c]);
|
|
f[1]=1.f+abs(image[indx+1][1]-image[indx+3][1])+abs(image[indx+1][1]-image[indx-1][1])+abs(image[indx][c]-image[indx+2][c])+abs(image[indx+2][c]-image[indx+4][c]);
|
|
f[2]=1.f+abs(image[indx-1][1]-image[indx-3][1])+abs(image[indx-1][1]-image[indx+1][1])+abs(image[indx][c]-image[indx-2][c])+abs(image[indx-2][c]-image[indx-4][c]);
|
|
f[3]=1.f+abs(image[indx+u][1]-image[indx+w][1])+abs(image[indx+u][1]-image[indx-u][1])+abs(image[indx][c]-image[indx+v][c])+abs(image[indx+v][c]-image[indx+x][c]);
|
|
g[0]=CLIP((22.f*image[indx-u][1]+22.f*image[indx-w][1]+2.f*image[indx-y][1]+2.f*image[indx+u][1]+40.f*image[indx][c]-32.f*image[indx-v][c]-8.f*image[indx-x][c])/48.f);
|
|
g[1]=CLIP((22.f*image[indx+1][1]+22.f*image[indx+3][1]+2.f*image[indx+5][1]+2.f*image[indx-1][1]+40.f*image[indx][c]-32.f*image[indx+2][c]-8.f*image[indx+4][c])/48.f);
|
|
g[2]=CLIP((22.f*image[indx-1][1]+22.f*image[indx-3][1]+2.f*image[indx-5][1]+2.f*image[indx+1][1]+40.f*image[indx][c]-32.f*image[indx-2][c]-8.f*image[indx-4][c])/48.f);
|
|
g[3]=CLIP((22.f*image[indx+u][1]+22.f*image[indx+w][1]+2.f*image[indx+y][1]+2.f*image[indx-u][1]+40.f*image[indx][c]-32.f*image[indx+v][c]-8.f*image[indx+x][c])/48.f);
|
|
dif[indx][0]=CLIP((f[3]*g[0]+f[0]*g[3])/(f[0]+f[3]))-image[indx][c];
|
|
dif[indx][1]=CLIP((f[2]*g[1]+f[1]*g[2])/(f[1]+f[2]))-image[indx][c];
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (row=6; row < height-6; row++)
|
|
for (col=6+(FC(row,2)&1),indx=row*width+col,c=FC(row,col)/2; col < u-6; col+=2,indx+=2) {
|
|
f[0]=1.f+78.f*SQR((float)dif[indx][0])+69.f*(SQR((float) dif[indx-v][0])+SQR((float)dif[indx+v][0]))+51.f*(SQR((float)dif[indx-x][0])+SQR((float)dif[indx+x][0]))+21.f*(SQR((float)dif[indx-z][0])+SQR((float)dif[indx+z][0]))-6.f*SQR((float)dif[indx-v][0]+dif[indx][0]+dif[indx+v][0])-10.f*(SQR((float)dif[indx-x][0]+dif[indx-v][0]+dif[indx][0])+SQR((float)dif[indx][0]+dif[indx+v][0]+dif[indx+x][0]))-7.f*(SQR((float)dif[indx-z][0]+dif[indx-x][0]+dif[indx-v][0])+SQR((float)dif[indx+v][0]+dif[indx+x][0]+dif[indx+z][0]));
|
|
f[1]=1.f+78.f*SQR((float)dif[indx][1])+69.f*(SQR((float)dif[indx-2][1])+SQR((float)dif[indx+2][1]))+51.f*(SQR((float)dif[indx-4][1])+SQR((float)dif[indx+4][1]))+21.f*(SQR((float)dif[indx-6][1])+SQR((float)dif[indx+6][1]))-6.f*SQR((float)dif[indx-2][1]+dif[indx][1]+dif[indx+2][1])-10.f*(SQR((float)dif[indx-4][1]+dif[indx-2][1]+dif[indx][1])+SQR((float)dif[indx][1]+dif[indx+2][1]+dif[indx+4][1]))-7.f*(SQR((float)dif[indx-6][1]+dif[indx-4][1]+dif[indx-2][1])+SQR((float)dif[indx+2][1]+dif[indx+4][1]+dif[indx+6][1]));
|
|
g[0]=ULIM<float>(0.725f*dif[indx][0]+0.1375f*dif[indx-v][0]+0.1375f*dif[indx+v][0],dif[indx-v][0],dif[indx+v][0]);
|
|
g[1]=ULIM<float>(0.725f*dif[indx][1]+0.1375f*dif[indx-2][1]+0.1375f*dif[indx+2][1],dif[indx-2][1],dif[indx+2][1]);
|
|
chr[indx][c]=(f[1]*g[0]+f[0]*g[1])/(f[0]+f[1]);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (row=6; row<height-6; row++)
|
|
for (col=6+(FC(row,2)&1),indx=row*width+col,c=1-FC(row,col)/2,d=2*c; col<u-6; col+=2,indx+=2) {
|
|
f[0]=1.f/(float)(1.f+fabs((float)chr[indx-u-1][c]-chr[indx+u+1][c])+fabs((float)chr[indx-u-1][c]-chr[indx-w-3][c])+fabs((float)chr[indx+u+1][c]-chr[indx-w-3][c]));
|
|
f[1]=1.f/(float)(1.f+fabs((float)chr[indx-u+1][c]-chr[indx+u-1][c])+fabs((float)chr[indx-u+1][c]-chr[indx-w+3][c])+fabs((float)chr[indx+u-1][c]-chr[indx-w+3][c]));
|
|
f[2]=1.f/(float)(1.f+fabs((float)chr[indx+u-1][c]-chr[indx-u+1][c])+fabs((float)chr[indx+u-1][c]-chr[indx+w+3][c])+fabs((float)chr[indx-u+1][c]-chr[indx+w-3][c]));
|
|
f[3]=1.f/(float)(1.f+fabs((float)chr[indx+u+1][c]-chr[indx-u-1][c])+fabs((float)chr[indx+u+1][c]-chr[indx+w-3][c])+fabs((float)chr[indx-u-1][c]-chr[indx+w+3][c]));
|
|
g[0]=ULIM(chr[indx-u-1][c],chr[indx-w-1][c],chr[indx-u-3][c]);
|
|
g[1]=ULIM(chr[indx-u+1][c],chr[indx-w+1][c],chr[indx-u+3][c]);
|
|
g[2]=ULIM(chr[indx+u-1][c],chr[indx+w-1][c],chr[indx+u-3][c]);
|
|
g[3]=ULIM(chr[indx+u+1][c],chr[indx+w+1][c],chr[indx+u+3][c]);
|
|
chr[indx][c]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3]);
|
|
image[indx][1]=CLIP(image[indx][2-d]+chr[indx][1-c]);
|
|
image[indx][d]=CLIP(image[indx][1]-chr[indx][c]);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (row=6; row<height-6; row++)
|
|
for (col=6+(FC(row,1)&1),indx=row*width+col,c=FC(row,col+1)/2,d=2*c; col<u-6; col+=2,indx+=2)
|
|
for(i=0;i<=1;c=1-c,d=2*c,i++){
|
|
f[0]=1.f/(float)(1.f+fabs((float)chr[indx-u][c]-chr[indx+u][c])+fabs((float)chr[indx-u][c]-chr[indx-w][c])+fabs((float)chr[indx+u][c]-chr[indx-w][c]));
|
|
f[1]=1.f/(float)(1.f+fabs((float)chr[indx+1][c]-chr[indx-1][c])+fabs((float)chr[indx+1][c]-chr[indx+3][c])+fabs((float)chr[indx-1][c]-chr[indx+3][c]));
|
|
f[2]=1.f/(float)(1.f+fabs((float)chr[indx-1][c]-chr[indx+1][c])+fabs((float)chr[indx-1][c]-chr[indx-3][c])+fabs((float)chr[indx+1][c]-chr[indx-3][c]));
|
|
f[3]=1.f/(float)(1.f+fabs((float)chr[indx+u][c]-chr[indx-u][c])+fabs((float)chr[indx+u][c]-chr[indx+w][c])+fabs((float)chr[indx-u][c]-chr[indx+w][c]));
|
|
g[0]=0.875f*chr[indx-u][c]+0.125f*chr[indx-w][c];
|
|
g[1]=0.875f*chr[indx+1][c]+0.125f*chr[indx+3][c];
|
|
g[2]=0.875f*chr[indx-1][c]+0.125f*chr[indx-3][c];
|
|
g[3]=0.875f*chr[indx+u][c]+0.125f*chr[indx+w][c];
|
|
image[indx][d]=CLIP(image[indx][1]-(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3]));
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int ii=0; ii<height; ii++) {
|
|
for (int jj=0; jj<width; jj++){
|
|
red[ii][jj] = CLIP(image[ii*width+jj][0]);
|
|
green[ii][jj] = CLIP(image[ii*width+jj][1]);
|
|
blue[ii][jj] = CLIP(image[ii*width+jj][2]);
|
|
}
|
|
}
|
|
} // End of parallelization
|
|
free (image);
|
|
free(dif); free(chr);
|
|
//RawImageSource::refinement_lassus();
|
|
}
|
|
|
|
// LSMME demosaicing algorithm
|
|
// L. Zhang and X. Wu,
|
|
// Color demozaicing via directional Linear Minimum Mean Square-error Estimation,
|
|
// IEEE Trans. on Image Processing, vol. 14, pp. 2167-2178,
|
|
// Dec. 2005.
|
|
// Adapted to RT by Jacques Desmis 3/2013
|
|
// Improved speed and reduced memory consumption by Ingo Weyrich 2/2015
|
|
//TODO Tiles to reduce memory consumption
|
|
SSEFUNCTION void RawImageSource::lmmse_interpolate_omp(int winw, int winh, int iterations)
|
|
{
|
|
const int width=winw, height=winh;
|
|
const int ba = 10;
|
|
const int rr1 = height + 2*ba;
|
|
const int cc1 = width + 2*ba;
|
|
const int w1 = cc1;
|
|
const int w2 = 2*w1;
|
|
const int w3 = 3*w1;
|
|
const int w4 = 4*w1;
|
|
float h0, h1, h2, h3, h4, hs;
|
|
h0 = 1.0f;
|
|
h1 = exp( -1.0f/8.0f);
|
|
h2 = exp( -4.0f/8.0f);
|
|
h3 = exp( -9.0f/8.0f);
|
|
h4 = exp(-16.0f/8.0f);
|
|
hs = h0 + 2.0f*(h1 + h2 + h3 + h4);
|
|
h0 /= hs;
|
|
h1 /= hs;
|
|
h2 /= hs;
|
|
h3 /= hs;
|
|
h4 /= hs;
|
|
int passref;
|
|
int iter;
|
|
if(iterations <=4) {
|
|
iter = iterations-1;
|
|
passref=0;
|
|
} else if (iterations <=6) {
|
|
iter=3;
|
|
passref=iterations-4;
|
|
} else if (iterations <=8) {
|
|
iter=3;
|
|
passref=iterations-6;
|
|
}
|
|
bool applyGamma=true;
|
|
if(iterations==0) {
|
|
applyGamma=false;
|
|
iter=0;
|
|
} else
|
|
applyGamma=true;
|
|
|
|
float *rix[5];
|
|
float *qix[5];
|
|
float *buffer = (float *)calloc(rr1*cc1*5*sizeof(float),1);
|
|
if(buffer == NULL) { // allocation of big block of memory failed, try to get 5 smaller ones
|
|
printf("lmmse_interpolate_omp: allocation of big memory block failed, try to get 5 smaller ones now...\n");
|
|
bool allocationFailed = false;
|
|
for(int i=0;i<5;i++) {
|
|
qix[i] = (float *)calloc(rr1*cc1*sizeof(float),1);
|
|
if(!qix[i]) { // allocation of at least one small block failed
|
|
allocationFailed = true;
|
|
}
|
|
}
|
|
if(allocationFailed) { // fall back to igv_interpolate
|
|
printf("lmmse_interpolate_omp: allocation of 5 small memory blocks failed, falling back to igv_interpolate...\n");
|
|
for(int i=0;i<5;i++) { // free the already allocated buffers
|
|
if(qix[i])
|
|
free(qix[i]);
|
|
}
|
|
igv_interpolate(winw, winh);
|
|
return;
|
|
}
|
|
} else {
|
|
qix[0] = buffer;
|
|
for(int i=1;i<5;i++)
|
|
qix[i] = qix[i-1] + rr1*cc1;
|
|
}
|
|
|
|
if (plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::lmmse]));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
|
|
|
|
LUTf *gamtab;
|
|
if(applyGamma)
|
|
gamtab = &(Color::gammatab_24_17a);
|
|
else {
|
|
gamtab = new LUTf(65536, LUT_CLIP_ABOVE | LUT_CLIP_BELOW);
|
|
for(int i=0;i<65536;i++)
|
|
(*gamtab)[i] = (float)i / 65535.f;
|
|
}
|
|
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel private(rix)
|
|
#endif
|
|
{
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int rrr=ba; rrr < rr1-ba; rrr++) {
|
|
for (int ccc=ba, row=rrr-ba; ccc < cc1-ba; ccc++) {
|
|
int col = ccc - ba;
|
|
float *rix = qix[4] + rrr*cc1 + ccc;
|
|
rix[0] = (*gamtab)[rawData[row][col]];
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.1);
|
|
}
|
|
|
|
// G-R(B)
|
|
#ifdef _OPENMP
|
|
#pragma omp for schedule(dynamic,16)
|
|
#endif
|
|
for (int rr=2; rr < rr1-2; rr++) {
|
|
// G-R(B) at R(B) location
|
|
for (int cc=2+(FC(rr,2)&1); cc < cc1-2; cc+=2) {
|
|
rix[4] = qix[4] + rr*cc1 + cc;
|
|
float v0 = x00625(rix[4][-w1-1]+rix[4][-w1+1]+rix[4][w1-1]+rix[4][w1+1]) +x0250(rix[4][0]);
|
|
// horizontal
|
|
rix[0] = qix[0] + rr*cc1 + cc;
|
|
rix[0][0] = - x0250(rix[4][ -2] + rix[4][ 2])+ xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]);
|
|
float Y = v0 + xdiv2f(rix[0][0]);
|
|
if (rix[4][0] > 1.75f*Y)
|
|
rix[0][0] = ULIM(rix[0][0],rix[4][ -1],rix[4][ 1]);
|
|
else
|
|
rix[0][0] = LIM(rix[0][0],0.0f,1.0f);
|
|
rix[0][0] -= rix[4][0];
|
|
// vertical
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[1][0] = -x0250(rix[4][-w2] + rix[4][w2])+ xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]);
|
|
Y = v0 + xdiv2f(rix[1][0]);
|
|
if (rix[4][0] > 1.75f*Y)
|
|
rix[1][0] = ULIM(rix[1][0],rix[4][-w1],rix[4][w1]);
|
|
else
|
|
rix[1][0] = LIM(rix[1][0],0.0f,1.0f);
|
|
rix[1][0] -= rix[4][0];
|
|
}
|
|
// G-R(B) at G location
|
|
for (int ccc=2+(FC(rr,3)&1); ccc < cc1-2; ccc+=2) {
|
|
rix[0] = qix[0] + rr*cc1 + ccc;
|
|
rix[1] = qix[1] + rr*cc1 + ccc;
|
|
rix[4] = qix[4] + rr*cc1 + ccc;
|
|
rix[0][0] = x0250(rix[4][ -2] + rix[4][ 2])- xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]);
|
|
rix[1][0] = x0250(rix[4][-w2] + rix[4][w2])- xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]);
|
|
rix[0][0] = LIM(rix[0][0],-1.0f,0.0f) + rix[4][0];
|
|
rix[1][0] = LIM(rix[1][0],-1.0f,0.0f) + rix[4][0];
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.2);
|
|
}
|
|
|
|
|
|
// apply low pass filter on differential colors
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int rr=4; rr < rr1-4; rr++)
|
|
for (int cc=4; cc < cc1-4; cc++) {
|
|
rix[0] = qix[0] + rr*cc1 + cc;
|
|
rix[2] = qix[2] + rr*cc1 + cc;
|
|
rix[2][0] = h0*rix[0][0] + h1*(rix[0][ -1] + rix[0][ 1]) + h2*(rix[0][ -2] + rix[0][ 2]) + h3*(rix[0][ -3] + rix[0][ 3]) + h4*(rix[0][ -4] + rix[0][ 4]);
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[3] = qix[3] + rr*cc1 + cc;
|
|
rix[3][0] = h0*rix[1][0] + h1*(rix[1][-w1] + rix[1][w1]) + h2*(rix[1][-w2] + rix[1][w2]) + h3*(rix[1][-w3] + rix[1][w3]) + h4*(rix[1][-w4] + rix[1][w4]);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.3);
|
|
}
|
|
|
|
// interpolate G-R(B) at R(B)
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int rr=4; rr < rr1-4; rr++) {
|
|
int cc=4+(FC(rr,4)&1);
|
|
#ifdef __SSE2__
|
|
__m128 p1v, p2v, p3v, p4v, p5v, p6v, p7v, p8v, p9v, muv, vxv, vnv, xhv, vhv, xvv, vvv;
|
|
__m128 epsv = _mm_set1_ps(1e-7);
|
|
__m128 ninev = _mm_set1_ps(9.f);
|
|
for (; cc < cc1-10; cc+=8) {
|
|
rix[0] = qix[0] + rr*cc1 + cc;
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[2] = qix[2] + rr*cc1 + cc;
|
|
rix[3] = qix[3] + rr*cc1 + cc;
|
|
rix[4] = qix[4] + rr*cc1 + cc;
|
|
// horizontal
|
|
p1v = LC2VFU(rix[2][-4]);
|
|
p2v = LC2VFU(rix[2][-3]);
|
|
p3v = LC2VFU(rix[2][-2]);
|
|
p4v = LC2VFU(rix[2][-1]);
|
|
p5v = LC2VFU(rix[2][ 0]);
|
|
p6v = LC2VFU(rix[2][ 1]);
|
|
p7v = LC2VFU(rix[2][ 2]);
|
|
p8v = LC2VFU(rix[2][ 3]);
|
|
p9v = LC2VFU(rix[2][ 4]);
|
|
muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev;
|
|
vxv = epsv+SQRV(p1v-muv)+SQRV(p2v-muv)+SQRV(p3v-muv)+SQRV(p4v-muv)+SQRV(p5v-muv)+SQRV(p6v-muv)+SQRV(p7v-muv)+SQRV(p8v-muv)+SQRV(p9v-muv);
|
|
p1v -= LC2VFU(rix[0][-4]);
|
|
p2v -= LC2VFU(rix[0][-3]);
|
|
p3v -= LC2VFU(rix[0][-2]);
|
|
p4v -= LC2VFU(rix[0][-1]);
|
|
p5v -= LC2VFU(rix[0][ 0]);
|
|
p6v -= LC2VFU(rix[0][ 1]);
|
|
p7v -= LC2VFU(rix[0][ 2]);
|
|
p8v -= LC2VFU(rix[0][ 3]);
|
|
p9v -= LC2VFU(rix[0][ 4]);
|
|
vnv = epsv+SQRV(p1v)+SQRV(p2v)+SQRV(p3v)+SQRV(p4v)+SQRV(p5v)+SQRV(p6v)+SQRV(p7v)+SQRV(p8v)+SQRV(p9v);
|
|
xhv = (LC2VFU(rix[0][0])*vxv + LC2VFU(rix[2][0])*vnv)/(vxv + vnv);
|
|
vhv = vxv*vnv/(vxv + vnv);
|
|
|
|
// vertical
|
|
p1v = LC2VFU(rix[3][-w4]);
|
|
p2v = LC2VFU(rix[3][-w3]);
|
|
p3v = LC2VFU(rix[3][-w2]);
|
|
p4v = LC2VFU(rix[3][-w1]);
|
|
p5v = LC2VFU(rix[3][ 0]);
|
|
p6v = LC2VFU(rix[3][ w1]);
|
|
p7v = LC2VFU(rix[3][ w2]);
|
|
p8v = LC2VFU(rix[3][ w3]);
|
|
p9v = LC2VFU(rix[3][ w4]);
|
|
muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev;
|
|
vxv = epsv+SQRV(p1v-muv)+SQRV(p2v-muv)+SQRV(p3v-muv)+SQRV(p4v-muv)+SQRV(p5v-muv)+SQRV(p6v-muv)+SQRV(p7v-muv)+SQRV(p8v-muv)+SQRV(p9v-muv);
|
|
p1v -= LC2VFU(rix[1][-w4]);
|
|
p2v -= LC2VFU(rix[1][-w3]);
|
|
p3v -= LC2VFU(rix[1][-w2]);
|
|
p4v -= LC2VFU(rix[1][-w1]);
|
|
p5v -= LC2VFU(rix[1][ 0]);
|
|
p6v -= LC2VFU(rix[1][ w1]);
|
|
p7v -= LC2VFU(rix[1][ w2]);
|
|
p8v -= LC2VFU(rix[1][ w3]);
|
|
p9v -= LC2VFU(rix[1][ w4]);
|
|
vnv = epsv+SQRV(p1v)+SQRV(p2v)+SQRV(p3v)+SQRV(p4v)+SQRV(p5v)+SQRV(p6v)+SQRV(p7v)+SQRV(p8v)+SQRV(p9v);
|
|
xvv = (LC2VFU(rix[1][0])*vxv + LC2VFU(rix[3][0])*vnv)/(vxv + vnv);
|
|
vvv = vxv*vnv/(vxv + vnv);
|
|
// interpolated G-R(B)
|
|
muv = (xhv*vvv + xvv*vhv)/(vhv + vvv);
|
|
STC2VFU(rix[4][0], muv);
|
|
}
|
|
#endif
|
|
for (; cc < cc1-4; cc+=2) {
|
|
rix[0] = qix[0] + rr*cc1 + cc;
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[2] = qix[2] + rr*cc1 + cc;
|
|
rix[3] = qix[3] + rr*cc1 + cc;
|
|
rix[4] = qix[4] + rr*cc1 + cc;
|
|
// horizontal
|
|
float p1 = rix[2][-4];
|
|
float p2 = rix[2][-3];
|
|
float p3 = rix[2][-2];
|
|
float p4 = rix[2][-1];
|
|
float p5 = rix[2][ 0];
|
|
float p6 = rix[2][ 1];
|
|
float p7 = rix[2][ 2];
|
|
float p8 = rix[2][ 3];
|
|
float p9 = rix[2][ 4];
|
|
float mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f;
|
|
float vx = 1e-7+SQR(p1-mu)+SQR(p2-mu)+SQR(p3-mu)+SQR(p4-mu)+SQR(p5-mu)+SQR(p6-mu)+SQR(p7-mu)+SQR(p8-mu)+SQR(p9-mu);
|
|
p1 -= rix[0][-4];
|
|
p2 -= rix[0][-3];
|
|
p3 -= rix[0][-2];
|
|
p4 -= rix[0][-1];
|
|
p5 -= rix[0][ 0];
|
|
p6 -= rix[0][ 1];
|
|
p7 -= rix[0][ 2];
|
|
p8 -= rix[0][ 3];
|
|
p9 -= rix[0][ 4];
|
|
float vn = 1e-7+SQR(p1)+SQR(p2)+SQR(p3)+SQR(p4)+SQR(p5)+SQR(p6)+SQR(p7)+SQR(p8)+SQR(p9);
|
|
float xh = (rix[0][0]*vx + rix[2][0]*vn)/(vx + vn);
|
|
float vh = vx*vn/(vx + vn);
|
|
|
|
// vertical
|
|
p1 = rix[3][-w4];
|
|
p2 = rix[3][-w3];
|
|
p3 = rix[3][-w2];
|
|
p4 = rix[3][-w1];
|
|
p5 = rix[3][ 0];
|
|
p6 = rix[3][ w1];
|
|
p7 = rix[3][ w2];
|
|
p8 = rix[3][ w3];
|
|
p9 = rix[3][ w4];
|
|
mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f;
|
|
vx = 1e-7+SQR(p1-mu)+SQR(p2-mu)+SQR(p3-mu)+SQR(p4-mu)+SQR(p5-mu)+SQR(p6-mu)+SQR(p7-mu)+SQR(p8-mu)+SQR(p9-mu);
|
|
p1 -= rix[1][-w4];
|
|
p2 -= rix[1][-w3];
|
|
p3 -= rix[1][-w2];
|
|
p4 -= rix[1][-w1];
|
|
p5 -= rix[1][ 0];
|
|
p6 -= rix[1][ w1];
|
|
p7 -= rix[1][ w2];
|
|
p8 -= rix[1][ w3];
|
|
p9 -= rix[1][ w4];
|
|
vn = 1e-7+SQR(p1)+SQR(p2)+SQR(p3)+SQR(p4)+SQR(p5)+SQR(p6)+SQR(p7)+SQR(p8)+SQR(p9);
|
|
float xv = (rix[1][0]*vx + rix[3][0]*vn)/(vx + vn);
|
|
float vv = vx*vn/(vx + vn);
|
|
// interpolated G-R(B)
|
|
rix[4][0] = (xh*vv + xv*vh)/(vh + vv);
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.4);
|
|
}
|
|
|
|
// copy CFA values
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int rr=0; rr < rr1; rr++)
|
|
for (int cc=0, row=rr-ba; cc < cc1; cc++) {
|
|
int col=cc-ba;
|
|
int c = FC(rr,cc);
|
|
rix[c] = qix[c] + rr*cc1 + cc;
|
|
if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) {
|
|
rix[c][0] = (*gamtab)[rawData[row][col]];
|
|
}
|
|
else
|
|
rix[c][0] = 0.f;
|
|
if (c != 1) {
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[4] = qix[4] + rr*cc1 + cc;
|
|
rix[1][0] = rix[c][0] + rix[4][0];
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.5);
|
|
}
|
|
|
|
// bilinear interpolation for R/B
|
|
// interpolate R/B at G location
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int rr=1; rr < rr1-1; rr++)
|
|
for (int cc=1+(FC(rr,2)&1), c=FC(rr,cc+1); cc < cc1-1; cc+=2) {
|
|
rix[c] = qix[c] + rr*cc1 + cc;
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[c][0] = rix[1][0] + xdiv2f(rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1]);
|
|
c = 2 - c;
|
|
rix[c] = qix[c] + rr*cc1 + cc;
|
|
rix[c][0] = rix[1][0]+ xdiv2f(rix[c][-w1] - rix[1][-w1] + rix[c][w1] - rix[1][w1]);
|
|
c = 2 - c;
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.6);
|
|
}
|
|
|
|
// interpolate R/B at B/R location
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int rr=1; rr < rr1-1; rr++)
|
|
for (int cc=1+(FC(rr,1)&1), c=2-FC(rr,cc); cc < cc1-1; cc+=2) {
|
|
rix[c] = qix[c] + rr*cc1 + cc;
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
rix[c][0] = rix[1][0]+ x0250(rix[c][-w1] - rix[1][-w1] + rix[c][ -1] - rix[1][ -1]+ rix[c][ 1] - rix[1][ 1] + rix[c][ w1] - rix[1][ w1]);
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.7);
|
|
}
|
|
|
|
}// End of parallelization 1
|
|
|
|
// median filter/
|
|
for (int pass=0; pass < iter; pass++) {
|
|
// Apply 3x3 median filter
|
|
// Compute median(R-G) and median(B-G)
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for private(rix)
|
|
#endif
|
|
for (int rr=1; rr < rr1-1; rr++) {
|
|
for (int c=0; c < 3; c+=2) {
|
|
int d = c + 3 - (c == 0 ? 0 : 1);
|
|
int cc=1;
|
|
#ifdef __SSE2__
|
|
__m128 p1v,p2v,p3v,p4v,p5v,p6v,p7v,p8v,p9v,tempv;
|
|
for (; cc < cc1-4; cc+=4) {
|
|
rix[d] = qix[d] + rr*cc1 + cc;
|
|
rix[c] = qix[c] + rr*cc1 + cc;
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
// Assign 3x3 differential color values
|
|
p1v = LVFU(rix[c][-w1-1])-LVFU(rix[1][-w1-1]); p2v = LVFU(rix[c][-w1])-LVFU(rix[1][-w1]); p3v = LVFU(rix[c][-w1+1])-LVFU(rix[1][-w1+1]);
|
|
p4v = LVFU(rix[c][ -1])-LVFU(rix[1][ -1]); p5v = LVFU(rix[c][ 0])-LVFU(rix[1][ 0]); p6v = LVFU(rix[c][ 1])-LVFU(rix[1][ 1]);
|
|
p7v = LVFU(rix[c][ w1-1])-LVFU(rix[1][ w1-1]); p8v = LVFU(rix[c][ w1])-LVFU(rix[1][ w1]); p9v = LVFU(rix[c][ w1+1])-LVFU(rix[1][ w1+1]);
|
|
// Sort for median of 9 values
|
|
PIX_SORTV(p2v,p3v); PIX_SORTV(p5v,p6v); PIX_SORTV(p8v,p9v);
|
|
PIX_SORTV(p1v,p2v); PIX_SORTV(p4v,p5v); PIX_SORTV(p7v,p8v);
|
|
PIX_SORTV(p2v,p3v); PIX_SORTV(p5v,p6v); PIX_SORTV(p8v,p9v);
|
|
p4v = _mm_max_ps(p1v,p4v); p6v = _mm_min_ps(p6v,p9v); PIX_SORTV(p5v,p8v);
|
|
p7v = _mm_max_ps(p4v,p7v); p5v = _mm_max_ps(p5v,p2v); p3v = _mm_min_ps(p3v,p6v);
|
|
p5v = _mm_min_ps(p5v,p8v); PIX_SORTV(p5v,p3v); p5v = _mm_max_ps(p7v,p5v);
|
|
p5v = _mm_min_ps(p3v,p5v);
|
|
_mm_storeu_ps(&rix[d][0], p5v);
|
|
}
|
|
#endif
|
|
for (; cc < cc1-1; cc++) {
|
|
float temp;
|
|
rix[d] = qix[d] + rr*cc1 + cc;
|
|
rix[c] = qix[c] + rr*cc1 + cc;
|
|
rix[1] = qix[1] + rr*cc1 + cc;
|
|
// Assign 3x3 differential color values
|
|
float p1 = rix[c][-w1-1]-rix[1][-w1-1]; float p2 = rix[c][-w1]-rix[1][-w1]; float p3 = rix[c][-w1+1]-rix[1][-w1+1];
|
|
float p4 = rix[c][ -1]-rix[1][ -1]; float p5 = rix[c][ 0]-rix[1][ 0]; float p6 = rix[c][ 1]-rix[1][ 1];
|
|
float p7 = rix[c][ w1-1]-rix[1][ w1-1]; float p8 = rix[c][ w1]-rix[1][ w1]; float p9 = rix[c][ w1+1]-rix[1][ w1+1];
|
|
// Sort for median of 9 values
|
|
PIX_SORT(p2,p3); PIX_SORT(p5,p6); PIX_SORT(p8,p9);
|
|
PIX_SORT(p1,p2); PIX_SORT(p4,p5); PIX_SORT(p7,p8);
|
|
PIX_SORT(p2,p3); PIX_SORT(p5,p6); PIX_SORT(p8,p9);
|
|
PIX_SORT(p1,p4); PIX_SORT(p6,p9); PIX_SORT(p5,p8);
|
|
PIX_SORT(p4,p7); PIX_SORT(p2,p5); PIX_SORT(p3,p6);
|
|
PIX_SORT(p5,p8); PIX_SORT(p5,p3); PIX_SORT(p7,p5);
|
|
PIX_SORT(p5,p3);
|
|
rix[d][0] = p5;
|
|
}
|
|
}
|
|
}
|
|
|
|
// red/blue at GREEN pixel locations & red/blue and green at BLUE/RED pixel locations
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for private (rix)
|
|
#endif
|
|
for (int rr=0; rr < rr1; rr++) {
|
|
rix[0] = qix[0] + rr*cc1;
|
|
rix[1] = qix[1] + rr*cc1;
|
|
rix[2] = qix[2] + rr*cc1;
|
|
rix[3] = qix[3] + rr*cc1;
|
|
rix[4] = qix[4] + rr*cc1;
|
|
int c0 = FC(rr,0);
|
|
int c1 = FC(rr,1);
|
|
if(c0 == 1){
|
|
c1 = 2 - c1;
|
|
int d = c1 + 3 - (c1 == 0 ? 0 : 1);
|
|
int cc;
|
|
for (cc=0; cc < cc1-1; cc+=2) {
|
|
rix[0][0] = rix[1][0] + rix[3][0];
|
|
rix[2][0] = rix[1][0] + rix[4][0];
|
|
rix[0]++; rix[1]++; rix[2]++; rix[3]++; rix[4]++;
|
|
rix[c1][0] = rix[1][0] + rix[d][0];
|
|
rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
|
|
rix[0]++; rix[1]++; rix[2]++; rix[3]++; rix[4]++;
|
|
}
|
|
if(cc < cc1) { // remaining pixel, only if width is odd
|
|
rix[0][0] = rix[1][0] + rix[3][0];
|
|
rix[2][0] = rix[1][0] + rix[4][0];
|
|
}
|
|
} else {
|
|
c0 = 2 - c0;
|
|
int d = c0 + 3 - (c0 == 0 ? 0 : 1);
|
|
int cc;
|
|
for (cc=0; cc < cc1-1; cc+=2) {
|
|
rix[c0][0] = rix[1][0] + rix[d][0];
|
|
rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
|
|
rix[0]++; rix[1]++; rix[2]++; rix[3]++; rix[4]++;
|
|
rix[0][0] = rix[1][0] + rix[3][0];
|
|
rix[2][0] = rix[1][0] + rix[4][0];
|
|
rix[0]++; rix[1]++; rix[2]++; rix[3]++; rix[4]++;
|
|
}
|
|
if(cc < cc1) { // remaining pixel, only if width is odd
|
|
rix[c0][0] = rix[1][0] + rix[d][0];
|
|
rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plistener) plistener->setProgress (0.8);
|
|
|
|
if(applyGamma)
|
|
gamtab = &(Color::igammatab_24_17);
|
|
else {
|
|
for(int i=0;i<65536;i++)
|
|
(*gamtab)[i] = (float)i + 0.5f;
|
|
}
|
|
|
|
array2D<float> (*rgb[3]);
|
|
rgb[0] = &red;
|
|
rgb[1] = &green;
|
|
rgb[2] = &blue;
|
|
|
|
// copy result back to image matrix
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (int row=0; row < height; row++) {
|
|
for (int col=0, rr=row+ba; col < width; col++) {
|
|
int cc = col+ba;
|
|
int c = FC(row,col);
|
|
for (int ii=0; ii < 3; ii++)
|
|
if (ii != c) {
|
|
float *rix = qix[ii] + rr*cc1 + cc;
|
|
(*(rgb[ii]))[row][col] = (*gamtab)[65535.f*rix[0]];
|
|
} else {
|
|
(*(rgb[ii]))[row][col] = CLIP(rawData[row][col]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plistener) plistener->setProgress (1.0);
|
|
if(buffer)
|
|
free(buffer);
|
|
else
|
|
for(int i=0;i<5;i++)
|
|
free(qix[i]);
|
|
|
|
if(!applyGamma)
|
|
delete gamtab;
|
|
|
|
if(iterations > 4 && iterations <=6) refinement(passref);
|
|
else if(iterations > 6) refinement_lassus(passref);
|
|
|
|
}
|
|
|
|
/***
|
|
*
|
|
* Bayer CFA Demosaicing using Integrated Gaussian Vector on Color Differences
|
|
* Revision 1.0 - 2013/02/28
|
|
*
|
|
* Copyright (c) 2007-2013 Luis Sanz Rodriguez
|
|
* Using High Order Interpolation technique by Jim S, Jimmy Li, and Sharmil Randhawa
|
|
*
|
|
* Contact info: luis.sanz.rodriguez@gmail.com
|
|
*
|
|
* This code is distributed under a GNU General Public License, version 3.
|
|
* Visit <http://www.gnu.org/licenses/> for more information.
|
|
*
|
|
***/
|
|
// Adapted to RT by Jacques Desmis 3/2013
|
|
// SSE version by Ingo Weyrich 5/2013
|
|
#ifdef __SSE2__
|
|
#define CLIPV(a) LIMV(a,zerov,c65535v)
|
|
SSEFUNCTION void RawImageSource::igv_interpolate(int winw, int winh)
|
|
{
|
|
static const float eps=1e-5f, epssq=1e-5f;//mod epssq -10f =>-5f Jacques 3/2013 to prevent artifact (divide by zero)
|
|
|
|
static const int h1=1, h2=2, h3=3, h5=5;
|
|
const int width=winw, height=winh;
|
|
const int v1=1*width, v2=2*width, v3=3*width, v5=5*width;
|
|
float* rgb[2];
|
|
float* chr[4];
|
|
float *rgbarray, *vdif, *hdif, *chrarray;
|
|
rgbarray = (float (*)) malloc((width*height) * sizeof( float ) );
|
|
rgb[0] = rgbarray;
|
|
rgb[1] = rgbarray + (width*height)/2;
|
|
|
|
vdif = (float (*)) calloc( width*height/2, sizeof *vdif );
|
|
hdif = (float (*)) calloc( width*height/2, sizeof *hdif );
|
|
|
|
chrarray = (float (*)) calloc( width*height, sizeof( float ) );
|
|
chr[0] = chrarray;
|
|
chr[1] = chrarray + (width*height)/2;
|
|
|
|
// mapped chr[2] and chr[3] to hdif and hdif, because these are out of use, when chr[2] and chr[3] are used
|
|
chr[2] = hdif;
|
|
chr[3] = vdif;
|
|
|
|
border_interpolate2(winw,winh,7);
|
|
|
|
if (plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::igv]));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel default(none) shared(rgb,vdif,hdif,chr)
|
|
#endif
|
|
{
|
|
__m128 ngv, egv, wgv, sgv, nvv, evv, wvv, svv, nwgv, negv, swgv, segv, nwvv, nevv, swvv, sevv,tempv,temp1v,temp2v,temp3v,temp4v,temp5v,temp6v,temp7v,temp8v;
|
|
__m128 epsv = _mm_set1_ps( eps );
|
|
__m128 epssqv = _mm_set1_ps( epssq );
|
|
__m128 c65535v = _mm_set1_ps( 65535.f );
|
|
__m128 c23v = _mm_set1_ps( 23.f );
|
|
__m128 c40v = _mm_set1_ps( 40.f );
|
|
__m128 c51v = _mm_set1_ps( 51.f );
|
|
__m128 c32v = _mm_set1_ps( 32.f );
|
|
__m128 c8v = _mm_set1_ps( 8.f );
|
|
__m128 c7v = _mm_set1_ps( 7.f );
|
|
__m128 c6v = _mm_set1_ps( 6.f );
|
|
__m128 c10v = _mm_set1_ps( 10.f );
|
|
__m128 c21v = _mm_set1_ps( 21.f );
|
|
__m128 c78v = _mm_set1_ps( 78.f );
|
|
__m128 c69v = _mm_set1_ps( 69.f );
|
|
__m128 c3145680v = _mm_set1_ps( 3145680.f );
|
|
__m128 onev = _mm_set1_ps ( 1.f );
|
|
__m128 zerov = _mm_set1_ps ( 0.f );
|
|
__m128 d725v = _mm_set1_ps ( 0.725f );
|
|
__m128 d1375v = _mm_set1_ps ( 0.1375f );
|
|
|
|
float *dest1, *dest2;
|
|
float ng, eg, wg, sg, nv, ev, wv, sv, nwg, neg, swg, seg, nwv, nev, swv, sev;
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=0; row<height-0; row++) {
|
|
dest1 = rgb[FC(row,0)&1];
|
|
dest2 = rgb[FC(row,1)&1];
|
|
int col, indx;
|
|
for (col=0, indx=row*width+col; col<width-7; col+=8, indx+=8) {
|
|
temp1v = LVFU( rawData[row][col] );
|
|
temp1v = CLIPV( temp1v );
|
|
temp2v = LVFU( rawData[row][col+4] );
|
|
temp2v = CLIPV( temp2v );
|
|
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 2,0,2,0 ) );
|
|
_mm_storeu_ps( &dest1[indx>>1], tempv );
|
|
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3,1,3,1 ) );
|
|
_mm_storeu_ps( &dest2[indx>>1], tempv );
|
|
}
|
|
for (; col<width; col++, indx+=2) {
|
|
dest1[indx>>1] = CLIP(rawData[row][col]); //rawData = RT datas
|
|
col++;
|
|
dest2[indx>>1] = CLIP(rawData[row][col]); //rawData = RT datas
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.13);
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=5; row<height-5; row++) {
|
|
int col,indx,indx1;
|
|
for (col=5+(FC(row,1)&1),indx=row*width+col, indx1=indx>>1; col<width-12; col+=8, indx+=8, indx1+=4) {
|
|
//N,E,W,S Gradients
|
|
ngv=(epsv+(vabsf(LVFU(rgb[1][(indx-v1)>>1])-LVFU(rgb[1][(indx-v3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1-v1)])))/c65535v);
|
|
egv=(epsv+(vabsf(LVFU(rgb[1][(indx+h1)>>1])-LVFU(rgb[1][(indx+h3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1+h1)])))/c65535v);
|
|
wgv=(epsv+(vabsf(LVFU(rgb[1][(indx-h1)>>1])-LVFU(rgb[1][(indx-h3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1-h1)])))/c65535v);
|
|
sgv=(epsv+(vabsf(LVFU(rgb[1][(indx+v1)>>1])-LVFU(rgb[1][(indx+v3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1+v1)])))/c65535v);
|
|
//N,E,W,S High Order Interpolation (Li & Randhawa)
|
|
//N,E,W,S Hamilton Adams Interpolation
|
|
// (48.f * 65535.f) = 3145680.f
|
|
tempv = c40v*LVFU(rgb[0][indx1]);
|
|
nvv=LIMV(((c23v*LVFU(rgb[1][(indx-v1)>>1])+c23v*LVFU(rgb[1][(indx-v3)>>1])+LVFU(rgb[1][(indx-v5)>>1])+LVFU(rgb[1][(indx+v1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1-v1)])-c8v*LVFU(rgb[0][(indx1-v2)])))/c3145680v, zerov, onev);
|
|
evv=LIMV(((c23v*LVFU(rgb[1][(indx+h1)>>1])+c23v*LVFU(rgb[1][(indx+h3)>>1])+LVFU(rgb[1][(indx+h5)>>1])+LVFU(rgb[1][(indx-h1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1+h1)])-c8v*LVFU(rgb[0][(indx1+h2)])))/c3145680v, zerov, onev);
|
|
wvv=LIMV(((c23v*LVFU(rgb[1][(indx-h1)>>1])+c23v*LVFU(rgb[1][(indx-h3)>>1])+LVFU(rgb[1][(indx-h5)>>1])+LVFU(rgb[1][(indx+h1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1-h1)])-c8v*LVFU(rgb[0][(indx1-h2)])))/c3145680v, zerov, onev);
|
|
svv=LIMV(((c23v*LVFU(rgb[1][(indx+v1)>>1])+c23v*LVFU(rgb[1][(indx+v3)>>1])+LVFU(rgb[1][(indx+v5)>>1])+LVFU(rgb[1][(indx-v1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1+v1)])-c8v*LVFU(rgb[0][(indx1+v2)])))/c3145680v, zerov, onev);
|
|
//Horizontal and vertical color differences
|
|
tempv = LVFU( rgb[0][indx1] ) / c65535v;
|
|
_mm_storeu_ps( &vdif[indx1], (sgv*nvv+ngv*svv)/(ngv+sgv)- tempv );
|
|
_mm_storeu_ps( &hdif[indx1], (wgv*evv+egv*wvv)/(egv+wgv)- tempv );
|
|
}
|
|
// borders without SSE
|
|
for (; col<width-5; col+=2, indx+=2, indx1++) {
|
|
//N,E,W,S Gradients
|
|
ng=(eps+(fabsf(rgb[1][(indx-v1)>>1]-rgb[1][(indx-v3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1-v1)]))/65535.f);;
|
|
eg=(eps+(fabsf(rgb[1][(indx+h1)>>1]-rgb[1][(indx+h3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1+h1)]))/65535.f);
|
|
wg=(eps+(fabsf(rgb[1][(indx-h1)>>1]-rgb[1][(indx-h3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1-h1)]))/65535.f);
|
|
sg=(eps+(fabsf(rgb[1][(indx+v1)>>1]-rgb[1][(indx+v3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1+v1)]))/65535.f);
|
|
//N,E,W,S High Order Interpolation (Li & Randhawa)
|
|
//N,E,W,S Hamilton Adams Interpolation
|
|
// (48.f * 65535.f) = 3145680.f
|
|
nv=LIM(((23.0f*rgb[1][(indx-v1)>>1]+23.0f*rgb[1][(indx-v3)>>1]+rgb[1][(indx-v5)>>1]+rgb[1][(indx+v1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1-v1)]-8.0f*rgb[0][(indx1-v2)]))/3145680.f, 0.0f, 1.0f);
|
|
ev=LIM(((23.0f*rgb[1][(indx+h1)>>1]+23.0f*rgb[1][(indx+h3)>>1]+rgb[1][(indx+h5)>>1]+rgb[1][(indx-h1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1+h1)]-8.0f*rgb[0][(indx1+h2)]))/3145680.f, 0.0f, 1.0f);
|
|
wv=LIM(((23.0f*rgb[1][(indx-h1)>>1]+23.0f*rgb[1][(indx-h3)>>1]+rgb[1][(indx-h5)>>1]+rgb[1][(indx+h1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1-h1)]-8.0f*rgb[0][(indx1-h2)]))/3145680.f, 0.0f, 1.0f);
|
|
sv=LIM(((23.0f*rgb[1][(indx+v1)>>1]+23.0f*rgb[1][(indx+v3)>>1]+rgb[1][(indx+v5)>>1]+rgb[1][(indx-v1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1+v1)]-8.0f*rgb[0][(indx1+v2)]))/3145680.f, 0.0f, 1.0f);
|
|
//Horizontal and vertical color differences
|
|
vdif[indx1]=(sg*nv+ng*sv)/(ng+sg)-(rgb[0][indx1])/65535.f;
|
|
hdif[indx1]=(wg*ev+eg*wv)/(eg+wg)-(rgb[0][indx1])/65535.f;
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.26);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++) {
|
|
int col,d,indx1;
|
|
for (col=7+(FC(row,1)&1), indx1=(row*width+col)>>1, d=FC(row,col)/2; col<width-14; col+=8, indx1+=4) {
|
|
//H&V integrated gaussian vector over variance on color differences
|
|
//Mod Jacques 3/2013
|
|
ngv=LIMV(epssqv+c78v*SQRV(LVFU(vdif[indx1]))+c69v*(SQRV(LVFU(vdif[indx1-v1]))+SQRV(LVFU(vdif[indx1+v1])))+c51v*(SQRV(LVFU(vdif[indx1-v2]))+SQRV(LVFU(vdif[indx1+v2])))+c21v*(SQRV(LVFU(vdif[indx1-v3]))+SQRV(LVFU(vdif[indx1+v3])))-c6v*SQRV(LVFU(vdif[indx1-v1])+LVFU(vdif[indx1])+LVFU(vdif[indx1+v1]))
|
|
-c10v*(SQRV(LVFU(vdif[indx1-v2])+LVFU(vdif[indx1-v1])+LVFU(vdif[indx1]))+SQRV(LVFU(vdif[indx1])+LVFU(vdif[indx1+v1])+LVFU(vdif[indx1+v2])))-c7v*(SQRV(LVFU(vdif[indx1-v3])+LVFU(vdif[indx1-v2])+LVFU(vdif[indx1-v1]))+SQRV(LVFU(vdif[indx1+v1])+LVFU(vdif[indx1+v2])+LVFU(vdif[indx1+v3]))),zerov,onev);
|
|
egv=LIMV(epssqv+c78v*SQRV(LVFU(hdif[indx1]))+c69v*(SQRV(LVFU(hdif[indx1-h1]))+SQRV(LVFU(hdif[indx1+h1])))+c51v*(SQRV(LVFU(hdif[indx1-h2]))+SQRV(LVFU(hdif[indx1+h2])))+c21v*(SQRV(LVFU(hdif[indx1-h3]))+SQRV(LVFU(hdif[indx1+h3])))-c6v*SQRV(LVFU(hdif[indx1-h1])+LVFU(hdif[indx1])+LVFU(hdif[indx1+h1]))
|
|
-c10v*(SQRV(LVFU(hdif[indx1-h2])+LVFU(hdif[indx1-h1])+LVFU(hdif[indx1]))+SQRV(LVFU(hdif[indx1])+LVFU(hdif[indx1+h1])+LVFU(hdif[indx1+h2])))-c7v*(SQRV(LVFU(hdif[indx1-h3])+LVFU(hdif[indx1-h2])+LVFU(hdif[indx1-h1]))+SQRV(LVFU(hdif[indx1+h1])+LVFU(hdif[indx1+h2])+LVFU(hdif[indx1+h3]))),zerov,onev);
|
|
//Limit chrominance using H/V neighbourhood
|
|
nvv=ULIMV(d725v*LVFU(vdif[indx1])+d1375v*LVFU(vdif[indx1-v1])+d1375v*LVFU(vdif[indx1+v1]),LVFU(vdif[indx1-v1]),LVFU(vdif[indx1+v1]));
|
|
evv=ULIMV(d725v*LVFU(hdif[indx1])+d1375v*LVFU(hdif[indx1-h1])+d1375v*LVFU(hdif[indx1+h1]),LVFU(hdif[indx1-h1]),LVFU(hdif[indx1+h1]));
|
|
//Chrominance estimation
|
|
tempv = (egv*nvv+ngv*evv)/(ngv+egv);
|
|
_mm_storeu_ps(&(chr[d][indx1]), tempv);
|
|
//Green channel population
|
|
temp1v = c65535v * tempv + LVFU(rgb[0][indx1]);
|
|
_mm_storeu_ps( &(rgb[0][indx1]), temp1v );
|
|
}
|
|
for (; col<width-7; col+=2, indx1++) {
|
|
//H&V integrated gaussian vector over variance on color differences
|
|
//Mod Jacques 3/2013
|
|
ng=LIM(epssq+78.0f*SQR(vdif[indx1])+69.0f*(SQR(vdif[indx1-v1])+SQR(vdif[indx1+v1]))+51.0f*(SQR(vdif[indx1-v2])+SQR(vdif[indx1+v2]))+21.0f*(SQR(vdif[indx1-v3])+SQR(vdif[indx1+v3]))-6.0f*SQR(vdif[indx1-v1]+vdif[indx1]+vdif[indx1+v1])
|
|
-10.0f*(SQR(vdif[indx1-v2]+vdif[indx1-v1]+vdif[indx1])+SQR(vdif[indx1]+vdif[indx1+v1]+vdif[indx1+v2]))-7.0f*(SQR(vdif[indx1-v3]+vdif[indx1-v2]+vdif[indx1-v1])+SQR(vdif[indx1+v1]+vdif[indx1+v2]+vdif[indx1+v3])),0.f,1.f);
|
|
eg=LIM(epssq+78.0f*SQR(hdif[indx1])+69.0f*(SQR(hdif[indx1-h1])+SQR(hdif[indx1+h1]))+51.0f*(SQR(hdif[indx1-h2])+SQR(hdif[indx1+h2]))+21.0f*(SQR(hdif[indx1-h3])+SQR(hdif[indx1+h3]))-6.0f*SQR(hdif[indx1-h1]+hdif[indx1]+hdif[indx1+h1])
|
|
-10.0f*(SQR(hdif[indx1-h2]+hdif[indx1-h1]+hdif[indx1])+SQR(hdif[indx1]+hdif[indx1+h1]+hdif[indx1+h2]))-7.0f*(SQR(hdif[indx1-h3]+hdif[indx1-h2]+hdif[indx1-h1])+SQR(hdif[indx1+h1]+hdif[indx1+h2]+hdif[indx1+h3])),0.f,1.f);
|
|
//Limit chrominance using H/V neighbourhood
|
|
nv=ULIM(0.725f*vdif[indx1]+0.1375f*vdif[indx1-v1]+0.1375f*vdif[indx1+v1],vdif[indx1-v1],vdif[indx1+v1]);
|
|
ev=ULIM(0.725f*hdif[indx1]+0.1375f*hdif[indx1-h1]+0.1375f*hdif[indx1+h1],hdif[indx1-h1],hdif[indx1+h1]);
|
|
//Chrominance estimation
|
|
chr[d][indx1]=(eg*nv+ng*ev)/(ng+eg);
|
|
//Green channel population
|
|
rgb[0][indx1]=rgb[0][indx1]+65535.f*chr[d][indx1];
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.39);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++) {
|
|
int col,indx,c;
|
|
for (col=7+(FC(row,1)&1), indx=row*width+col, c=1-FC(row,col)/2; col<width-14; col+=8, indx+=8) {
|
|
//NW,NE,SW,SE Gradients
|
|
nwgv=onev/(epsv+vabsf(LVFU(chr[c][(indx-v1-h1)>>1])-LVFU(chr[c][(indx-v3-h3)>>1]))+vabsf(LVFU(chr[c][(indx+v1+h1)>>1])-LVFU(chr[c][(indx-v3-h3)>>1])));
|
|
negv=onev/(epsv+vabsf(LVFU(chr[c][(indx-v1+h1)>>1])-LVFU(chr[c][(indx-v3+h3)>>1]))+vabsf(LVFU(chr[c][(indx+v1-h1)>>1])-LVFU(chr[c][(indx-v3+h3)>>1])));
|
|
swgv=onev/(epsv+vabsf(LVFU(chr[c][(indx+v1-h1)>>1])-LVFU(chr[c][(indx+v3+h3)>>1]))+vabsf(LVFU(chr[c][(indx-v1+h1)>>1])-LVFU(chr[c][(indx+v3-h3)>>1])));
|
|
segv=onev/(epsv+vabsf(LVFU(chr[c][(indx+v1+h1)>>1])-LVFU(chr[c][(indx+v3-h3)>>1]))+vabsf(LVFU(chr[c][(indx-v1-h1)>>1])-LVFU(chr[c][(indx+v3+h3)>>1])));
|
|
//Limit NW,NE,SW,SE Color differences
|
|
nwvv=ULIMV(LVFU(chr[c][(indx-v1-h1)>>1]),LVFU(chr[c][(indx-v3-h1)>>1]),LVFU(chr[c][(indx-v1-h3)>>1]));
|
|
nevv=ULIMV(LVFU(chr[c][(indx-v1+h1)>>1]),LVFU(chr[c][(indx-v3+h1)>>1]),LVFU(chr[c][(indx-v1+h3)>>1]));
|
|
swvv=ULIMV(LVFU(chr[c][(indx+v1-h1)>>1]),LVFU(chr[c][(indx+v3-h1)>>1]),LVFU(chr[c][(indx+v1-h3)>>1]));
|
|
sevv=ULIMV(LVFU(chr[c][(indx+v1+h1)>>1]),LVFU(chr[c][(indx+v3+h1)>>1]),LVFU(chr[c][(indx+v1+h3)>>1]));
|
|
//Interpolate chrominance: R@B and B@R
|
|
tempv = (nwgv*nwvv+negv*nevv+swgv*swvv+segv*sevv)/(nwgv+negv+swgv+segv);
|
|
_mm_storeu_ps( &(chr[c][indx>>1]), tempv);
|
|
}
|
|
for (; col<width-7; col+=2, indx+=2) {
|
|
//NW,NE,SW,SE Gradients
|
|
nwg=1.0f/(eps+fabsf(chr[c][(indx-v1-h1)>>1]-chr[c][(indx-v3-h3)>>1])+fabsf(chr[c][(indx+v1+h1)>>1]-chr[c][(indx-v3-h3)>>1]));
|
|
neg=1.0f/(eps+fabsf(chr[c][(indx-v1+h1)>>1]-chr[c][(indx-v3+h3)>>1])+fabsf(chr[c][(indx+v1-h1)>>1]-chr[c][(indx-v3+h3)>>1]));
|
|
swg=1.0f/(eps+fabsf(chr[c][(indx+v1-h1)>>1]-chr[c][(indx+v3+h3)>>1])+fabsf(chr[c][(indx-v1+h1)>>1]-chr[c][(indx+v3-h3)>>1]));
|
|
seg=1.0f/(eps+fabsf(chr[c][(indx+v1+h1)>>1]-chr[c][(indx+v3-h3)>>1])+fabsf(chr[c][(indx-v1-h1)>>1]-chr[c][(indx+v3+h3)>>1]));
|
|
//Limit NW,NE,SW,SE Color differences
|
|
nwv=ULIM(chr[c][(indx-v1-h1)>>1],chr[c][(indx-v3-h1)>>1],chr[c][(indx-v1-h3)>>1]);
|
|
nev=ULIM(chr[c][(indx-v1+h1)>>1],chr[c][(indx-v3+h1)>>1],chr[c][(indx-v1+h3)>>1]);
|
|
swv=ULIM(chr[c][(indx+v1-h1)>>1],chr[c][(indx+v3-h1)>>1],chr[c][(indx+v1-h3)>>1]);
|
|
sev=ULIM(chr[c][(indx+v1+h1)>>1],chr[c][(indx+v3+h1)>>1],chr[c][(indx+v1+h3)>>1]);
|
|
//Interpolate chrominance: R@B and B@R
|
|
chr[c][indx>>1]=(nwg*nwv+neg*nev+swg*swv+seg*sev)/(nwg+neg+swg+seg);
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.65);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++) {
|
|
int col,indx;
|
|
for (col=7+(FC(row,0)&1), indx=row*width+col; col<width-14; col+=8, indx+=8) {
|
|
//N,E,W,S Gradients
|
|
ngv=onev/(epsv+vabsf(LVFU(chr[0][(indx-v1)>>1])-LVFU(chr[0][(indx-v3)>>1]))+vabsf(LVFU(chr[0][(indx+v1)>>1])-LVFU(chr[0][(indx-v3)>>1])));
|
|
egv=onev/(epsv+vabsf(LVFU(chr[0][(indx+h1)>>1])-LVFU(chr[0][(indx+h3)>>1]))+vabsf(LVFU(chr[0][(indx-h1)>>1])-LVFU(chr[0][(indx+h3)>>1])));
|
|
wgv=onev/(epsv+vabsf(LVFU(chr[0][(indx-h1)>>1])-LVFU(chr[0][(indx-h3)>>1]))+vabsf(LVFU(chr[0][(indx+h1)>>1])-LVFU(chr[0][(indx-h3)>>1])));
|
|
sgv=onev/(epsv+vabsf(LVFU(chr[0][(indx+v1)>>1])-LVFU(chr[0][(indx+v3)>>1]))+vabsf(LVFU(chr[0][(indx-v1)>>1])-LVFU(chr[0][(indx+v3)>>1])));
|
|
//Interpolate chrominance: R@G and B@G
|
|
tempv = ((ngv*LVFU(chr[0][(indx-v1)>>1])+egv*LVFU(chr[0][(indx+h1)>>1])+wgv*LVFU(chr[0][(indx-h1)>>1])+sgv*LVFU(chr[0][(indx+v1)>>1]))/(ngv+egv+wgv+sgv));
|
|
_mm_storeu_ps( &chr[0+2][indx>>1], tempv);
|
|
}
|
|
for (; col<width-7; col+=2, indx+=2) {
|
|
//N,E,W,S Gradients
|
|
ng=1.0f/(eps+fabsf(chr[0][(indx-v1)>>1]-chr[0][(indx-v3)>>1])+fabsf(chr[0][(indx+v1)>>1]-chr[0][(indx-v3)>>1]));
|
|
eg=1.0f/(eps+fabsf(chr[0][(indx+h1)>>1]-chr[0][(indx+h3)>>1])+fabsf(chr[0][(indx-h1)>>1]-chr[0][(indx+h3)>>1]));
|
|
wg=1.0f/(eps+fabsf(chr[0][(indx-h1)>>1]-chr[0][(indx-h3)>>1])+fabsf(chr[0][(indx+h1)>>1]-chr[0][(indx-h3)>>1]));
|
|
sg=1.0f/(eps+fabsf(chr[0][(indx+v1)>>1]-chr[0][(indx+v3)>>1])+fabsf(chr[0][(indx-v1)>>1]-chr[0][(indx+v3)>>1]));
|
|
//Interpolate chrominance: R@G and B@G
|
|
chr[0+2][indx>>1]=((ng*chr[0][(indx-v1)>>1]+eg*chr[0][(indx+h1)>>1]+wg*chr[0][(indx-h1)>>1]+sg*chr[0][(indx+v1)>>1])/(ng+eg+wg+sg));
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.78);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++) {
|
|
int col,indx;
|
|
for (col=7+(FC(row,0)&1), indx=row*width+col; col<width-14; col+=8, indx+=8) {
|
|
//N,E,W,S Gradients
|
|
ngv=onev/(epsv+vabsf(LVFU(chr[1][(indx-v1)>>1])-LVFU(chr[1][(indx-v3)>>1]))+vabsf(LVFU(chr[1][(indx+v1)>>1])-LVFU(chr[1][(indx-v3)>>1])));
|
|
egv=onev/(epsv+vabsf(LVFU(chr[1][(indx+h1)>>1])-LVFU(chr[1][(indx+h3)>>1]))+vabsf(LVFU(chr[1][(indx-h1)>>1])-LVFU(chr[1][(indx+h3)>>1])));
|
|
wgv=onev/(epsv+vabsf(LVFU(chr[1][(indx-h1)>>1])-LVFU(chr[1][(indx-h3)>>1]))+vabsf(LVFU(chr[1][(indx+h1)>>1])-LVFU(chr[1][(indx-h3)>>1])));
|
|
sgv=onev/(epsv+vabsf(LVFU(chr[1][(indx+v1)>>1])-LVFU(chr[1][(indx+v3)>>1]))+vabsf(LVFU(chr[1][(indx-v1)>>1])-LVFU(chr[1][(indx+v3)>>1])));
|
|
//Interpolate chrominance: R@G and B@G
|
|
tempv = ((ngv*LVFU(chr[1][(indx-v1)>>1])+egv*LVFU(chr[1][(indx+h1)>>1])+wgv*LVFU(chr[1][(indx-h1)>>1])+sgv*LVFU(chr[1][(indx+v1)>>1]))/(ngv+egv+wgv+sgv));
|
|
_mm_storeu_ps( &chr[1+2][indx>>1], tempv);
|
|
}
|
|
for (; col<width-7; col+=2, indx+=2) {
|
|
//N,E,W,S Gradients
|
|
ng=1.0f/(eps+fabsf(chr[1][(indx-v1)>>1]-chr[1][(indx-v3)>>1])+fabsf(chr[1][(indx+v1)>>1]-chr[1][(indx-v3)>>1]));
|
|
eg=1.0f/(eps+fabsf(chr[1][(indx+h1)>>1]-chr[1][(indx+h3)>>1])+fabsf(chr[1][(indx-h1)>>1]-chr[1][(indx+h3)>>1]));
|
|
wg=1.0f/(eps+fabsf(chr[1][(indx-h1)>>1]-chr[1][(indx-h3)>>1])+fabsf(chr[1][(indx+h1)>>1]-chr[1][(indx-h3)>>1]));
|
|
sg=1.0f/(eps+fabsf(chr[1][(indx+v1)>>1]-chr[1][(indx+v3)>>1])+fabsf(chr[1][(indx-v1)>>1]-chr[1][(indx+v3)>>1]));
|
|
//Interpolate chrominance: R@G and B@G
|
|
chr[1+2][indx>>1]=((ng*chr[1][(indx-v1)>>1]+eg*chr[1][(indx+h1)>>1]+wg*chr[1][(indx-h1)>>1]+sg*chr[1][(indx+v1)>>1])/(ng+eg+wg+sg));
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.91);
|
|
}
|
|
float *src1, *src2, *redsrc0, *redsrc1, *bluesrc0, *bluesrc1;
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for(int row=7; row<height-7; row++){
|
|
int col,indx,fc;
|
|
fc = FC(row,7)&1;
|
|
src1 = rgb[fc];
|
|
src2 = rgb[fc^1];
|
|
redsrc0 = chr[fc<<1];
|
|
redsrc1 = chr[(fc^1)<<1];
|
|
bluesrc0 = chr[(fc<<1)+1];
|
|
bluesrc1 = chr[((fc^1)<<1)+1];
|
|
for(col=7, indx=row*width+col; col<width-14; col+=8, indx+=8) {
|
|
temp1v = LVFU( src1[indx>>1] );
|
|
temp2v = LVFU( src2[(indx+1)>>1] );
|
|
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 1,0,1,0 ) );
|
|
tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3,1,2,0 ) );
|
|
_mm_storeu_ps( &green[row][col], CLIPV( tempv ));
|
|
temp5v = LVFU(redsrc0[indx>>1]);
|
|
temp6v = LVFU(redsrc1[(indx+1)>>1]);
|
|
temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 1,0,1,0 ) );
|
|
temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3,1,2,0 ) );
|
|
temp3v = CLIPV( tempv - c65535v * temp3v );
|
|
_mm_storeu_ps( &red[row][col], temp3v);
|
|
temp7v = LVFU(bluesrc0[indx>>1]);
|
|
temp8v = LVFU(bluesrc1[(indx+1)>>1]);
|
|
temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 1,0,1,0 ) );
|
|
temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3,1,2,0 ) );
|
|
temp4v = CLIPV( tempv - c65535v * temp4v );
|
|
_mm_storeu_ps( &blue[row][col], temp4v);
|
|
|
|
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3,2,3,2 ) );
|
|
tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3,1,2,0 ) );
|
|
_mm_storeu_ps( &green[row][col+4], CLIPV( tempv ));
|
|
|
|
temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 3,2,3,2 ) );
|
|
temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3,1,2,0 ) );
|
|
temp3v = CLIPV( tempv - c65535v * temp3v );
|
|
_mm_storeu_ps( &red[row][col+4], temp3v);
|
|
temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 3,2,3,2 ) );
|
|
temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3,1,2,0 ) );
|
|
temp4v = CLIPV( tempv - c65535v * temp4v );
|
|
_mm_storeu_ps( &blue[row][col+4], temp4v);
|
|
}
|
|
|
|
for(; col<width-7; col++, indx+=2) {
|
|
red [row][col] = CLIP(src1[indx>>1]-65535.f*redsrc0[indx>>1]);
|
|
green[row][col] = CLIP(src1[indx>>1]);
|
|
blue [row][col] = CLIP(src1[indx>>1]-65535.f*bluesrc0[indx>>1]);
|
|
col++;
|
|
red [row][col] = CLIP(src2[(indx+1)>>1]-65535.f*redsrc1[(indx+1)>>1]);
|
|
green[row][col] = CLIP(src2[(indx+1)>>1]);
|
|
blue [row][col] = CLIP(src2[(indx+1)>>1]-65535.f*bluesrc1[(indx+1)>>1]);
|
|
}
|
|
}
|
|
}// End of parallelization
|
|
if (plistener) plistener->setProgress (1.0);
|
|
|
|
free(chrarray); free(rgbarray);
|
|
free(vdif); free(hdif);
|
|
}
|
|
#undef CLIPV
|
|
#else
|
|
void RawImageSource::igv_interpolate(int winw, int winh)
|
|
{
|
|
static const float eps=1e-5f, epssq=1e-5f;//mod epssq -10f =>-5f Jacques 3/2013 to prevent artifact (divide by zero)
|
|
static const int h1=1, h2=2, h3=3, h4=4, h5=5, h6=6;
|
|
const int width=winw, height=winh;
|
|
const int v1=1*width, v2=2*width, v3=3*width, v4=4*width, v5=5*width, v6=6*width;
|
|
float* rgb[3];
|
|
float* chr[2];
|
|
float (*rgbarray), *vdif, *hdif, (*chrarray);
|
|
|
|
rgbarray = (float (*)) calloc(width*height*3, sizeof( float));
|
|
rgb[0] = rgbarray;
|
|
rgb[1] = rgbarray + (width*height);
|
|
rgb[2] = rgbarray + 2*(width*height);
|
|
|
|
chrarray = (float (*)) calloc(width*height*2, sizeof( float));
|
|
chr[0] = chrarray;
|
|
chr[1] = chrarray + (width*height);
|
|
|
|
vdif = (float (*)) calloc(width*height/2, sizeof *vdif);
|
|
hdif = (float (*)) calloc(width*height/2, sizeof *hdif);
|
|
|
|
border_interpolate2(winw,winh,7);
|
|
|
|
if (plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::igv]));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel default(none) shared(rgb,vdif,hdif,chr)
|
|
#endif
|
|
{
|
|
|
|
float ng, eg, wg, sg, nv, ev, wv, sv, nwg, neg, swg, seg, nwv, nev, swv, sev;
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=0; row<height-0; row++)
|
|
for (int col=0, indx=row*width+col; col<width-0; col++, indx++) {
|
|
int c=FC(row,col);
|
|
rgb[c][indx]=CLIP(rawData[row][col]); //rawData = RT datas
|
|
}
|
|
// border_interpolate2(7, rgb);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.13);
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=5; row<height-5; row++)
|
|
for (int col=5+(FC(row,1)&1), indx=row*width+col, c=FC(row,col); col<width-5; col+=2, indx+=2) {
|
|
//N,E,W,S Gradients
|
|
ng=(eps+(fabsf(rgb[1][indx-v1]-rgb[1][indx-v3])+fabsf(rgb[c][indx]-rgb[c][indx-v2]))/65535.f);;
|
|
eg=(eps+(fabsf(rgb[1][indx+h1]-rgb[1][indx+h3])+fabsf(rgb[c][indx]-rgb[c][indx+h2]))/65535.f);
|
|
wg=(eps+(fabsf(rgb[1][indx-h1]-rgb[1][indx-h3])+fabsf(rgb[c][indx]-rgb[c][indx-h2]))/65535.f);
|
|
sg=(eps+(fabsf(rgb[1][indx+v1]-rgb[1][indx+v3])+fabsf(rgb[c][indx]-rgb[c][indx+v2]))/65535.f);
|
|
//N,E,W,S High Order Interpolation (Li & Randhawa)
|
|
//N,E,W,S Hamilton Adams Interpolation
|
|
// (48.f * 65535.f) = 3145680.f
|
|
nv=LIM(((23.0f*rgb[1][indx-v1]+23.0f*rgb[1][indx-v3]+rgb[1][indx-v5]+rgb[1][indx+v1]+40.0f*rgb[c][indx]-32.0f*rgb[c][indx-v2]-8.0f*rgb[c][indx-v4]))/3145680.f, 0.0f, 1.0f);
|
|
ev=LIM(((23.0f*rgb[1][indx+h1]+23.0f*rgb[1][indx+h3]+rgb[1][indx+h5]+rgb[1][indx-h1]+40.0f*rgb[c][indx]-32.0f*rgb[c][indx+h2]-8.0f*rgb[c][indx+h4]))/3145680.f, 0.0f, 1.0f);
|
|
wv=LIM(((23.0f*rgb[1][indx-h1]+23.0f*rgb[1][indx-h3]+rgb[1][indx-h5]+rgb[1][indx+h1]+40.0f*rgb[c][indx]-32.0f*rgb[c][indx-h2]-8.0f*rgb[c][indx-h4]))/3145680.f, 0.0f, 1.0f);
|
|
sv=LIM(((23.0f*rgb[1][indx+v1]+23.0f*rgb[1][indx+v3]+rgb[1][indx+v5]+rgb[1][indx-v1]+40.0f*rgb[c][indx]-32.0f*rgb[c][indx+v2]-8.0f*rgb[c][indx+v4]))/3145680.f, 0.0f, 1.0f);
|
|
//Horizontal and vertical color differences
|
|
vdif[indx>>1]=(sg*nv+ng*sv)/(ng+sg)-(rgb[c][indx])/65535.f;
|
|
hdif[indx>>1]=(wg*ev+eg*wv)/(eg+wg)-(rgb[c][indx])/65535.f;
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.26);
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++)
|
|
for (int col=7+(FC(row,1)&1), indx=row*width+col, c=FC(row,col), d=c/2; col<width-7; col+=2, indx+=2) {
|
|
//H&V integrated gaussian vector over variance on color differences
|
|
//Mod Jacques 3/2013
|
|
ng=LIM(epssq+78.0f*SQR(vdif[indx>>1])+69.0f*(SQR(vdif[(indx-v2)>>1])+SQR(vdif[(indx+v2)>>1]))+51.0f*(SQR(vdif[(indx-v4)>>1])+SQR(vdif[(indx+v4)>>1]))+21.0f*(SQR(vdif[(indx-v6)>>1])+SQR(vdif[(indx+v6)>>1]))-6.0f*SQR(vdif[(indx-v2)>>1]+vdif[indx>>1]+vdif[(indx+v2)>>1])
|
|
-10.0f*(SQR(vdif[(indx-v4)>>1]+vdif[(indx-v2)>>1]+vdif[indx>>1])+SQR(vdif[indx>>1]+vdif[(indx+v2)>>1]+vdif[(indx+v4)>>1]))-7.0f*(SQR(vdif[(indx-v6)>>1]+vdif[(indx-v4)>>1]+vdif[(indx-v2)>>1])+SQR(vdif[(indx+v2)>>1]+vdif[(indx+v4)>>1]+vdif[(indx+v6)>>1])),0.f,1.f);
|
|
eg=LIM(epssq+78.0f*SQR(hdif[indx>>1])+69.0f*(SQR(hdif[(indx-h2)>>1])+SQR(hdif[(indx+h2)>>1]))+51.0f*(SQR(hdif[(indx-h4)>>1])+SQR(hdif[(indx+h4)>>1]))+21.0f*(SQR(hdif[(indx-h6)>>1])+SQR(hdif[(indx+h6)>>1]))-6.0f*SQR(hdif[(indx-h2)>>1]+hdif[indx>>1]+hdif[(indx+h2)>>1])
|
|
-10.0f*(SQR(hdif[(indx-h4)>>1]+hdif[(indx-h2)>>1]+hdif[indx>>1])+SQR(hdif[indx>>1]+hdif[(indx+h2)>>1]+hdif[(indx+h4)>>1]))-7.0f*(SQR(hdif[(indx-h6)>>1]+hdif[(indx-h4)>>1]+hdif[(indx-h2)>>1])+SQR(hdif[(indx+h2)>>1]+hdif[(indx+h4)>>1]+hdif[(indx+h6)>>1])),0.f,1.f);
|
|
//Limit chrominance using H/V neighbourhood
|
|
nv=ULIM(0.725f*vdif[indx>>1]+0.1375f*vdif[(indx-v2)>>1]+0.1375f*vdif[(indx+v2)>>1],vdif[(indx-v2)>>1],vdif[(indx+v2)>>1]);
|
|
ev=ULIM(0.725f*hdif[indx>>1]+0.1375f*hdif[(indx-h2)>>1]+0.1375f*hdif[(indx+h2)>>1],hdif[(indx-h2)>>1],hdif[(indx+h2)>>1]);
|
|
//Chrominance estimation
|
|
chr[d][indx]=(eg*nv+ng*ev)/(ng+eg);
|
|
//Green channel population
|
|
rgb[1][indx]=rgb[c][indx]+65535.f*chr[d][indx];
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.39);
|
|
}
|
|
|
|
// free(vdif); free(hdif);
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row+=2)
|
|
for (int col=7+(FC(row,1)&1), indx=row*width+col, c=1-FC(row,col)/2; col<width-7; col+=2, indx+=2) {
|
|
//NW,NE,SW,SE Gradients
|
|
nwg=1.0f/(eps+fabsf(chr[c][indx-v1-h1]-chr[c][indx-v3-h3])+fabsf(chr[c][indx+v1+h1]-chr[c][indx-v3-h3]));
|
|
neg=1.0f/(eps+fabsf(chr[c][indx-v1+h1]-chr[c][indx-v3+h3])+fabsf(chr[c][indx+v1-h1]-chr[c][indx-v3+h3]));
|
|
swg=1.0f/(eps+fabsf(chr[c][indx+v1-h1]-chr[c][indx+v3+h3])+fabsf(chr[c][indx-v1+h1]-chr[c][indx+v3-h3]));
|
|
seg=1.0f/(eps+fabsf(chr[c][indx+v1+h1]-chr[c][indx+v3-h3])+fabsf(chr[c][indx-v1-h1]-chr[c][indx+v3+h3]));
|
|
//Limit NW,NE,SW,SE Color differences
|
|
nwv=ULIM(chr[c][indx-v1-h1],chr[c][indx-v3-h1],chr[c][indx-v1-h3]);
|
|
nev=ULIM(chr[c][indx-v1+h1],chr[c][indx-v3+h1],chr[c][indx-v1+h3]);
|
|
swv=ULIM(chr[c][indx+v1-h1],chr[c][indx+v3-h1],chr[c][indx+v1-h3]);
|
|
sev=ULIM(chr[c][indx+v1+h1],chr[c][indx+v3+h1],chr[c][indx+v1+h3]);
|
|
//Interpolate chrominance: R@B and B@R
|
|
chr[c][indx]=(nwg*nwv+neg*nev+swg*swv+seg*sev)/(nwg+neg+swg+seg);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.52);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=8; row<height-7; row+=2)
|
|
for (int col=7+(FC(row,1)&1), indx=row*width+col, c=1-FC(row,col)/2; col<width-7; col+=2, indx+=2) {
|
|
//NW,NE,SW,SE Gradients
|
|
nwg=1.0f/(eps+fabsf(chr[c][indx-v1-h1]-chr[c][indx-v3-h3])+fabsf(chr[c][indx+v1+h1]-chr[c][indx-v3-h3]));
|
|
neg=1.0f/(eps+fabsf(chr[c][indx-v1+h1]-chr[c][indx-v3+h3])+fabsf(chr[c][indx+v1-h1]-chr[c][indx-v3+h3]));
|
|
swg=1.0f/(eps+fabsf(chr[c][indx+v1-h1]-chr[c][indx+v3+h3])+fabsf(chr[c][indx-v1+h1]-chr[c][indx+v3-h3]));
|
|
seg=1.0f/(eps+fabsf(chr[c][indx+v1+h1]-chr[c][indx+v3-h3])+fabsf(chr[c][indx-v1-h1]-chr[c][indx+v3+h3]));
|
|
//Limit NW,NE,SW,SE Color differences
|
|
nwv=ULIM(chr[c][indx-v1-h1],chr[c][indx-v3-h1],chr[c][indx-v1-h3]);
|
|
nev=ULIM(chr[c][indx-v1+h1],chr[c][indx-v3+h1],chr[c][indx-v1+h3]);
|
|
swv=ULIM(chr[c][indx+v1-h1],chr[c][indx+v3-h1],chr[c][indx+v1-h3]);
|
|
sev=ULIM(chr[c][indx+v1+h1],chr[c][indx+v3+h1],chr[c][indx+v1+h3]);
|
|
//Interpolate chrominance: R@B and B@R
|
|
chr[c][indx]=(nwg*nwv+neg*nev+swg*swv+seg*sev)/(nwg+neg+swg+seg);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.65);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++)
|
|
for (int col=7+(FC(row,0)&1), indx=row*width+col; col<width-7; col+=2, indx+=2) {
|
|
//N,E,W,S Gradients
|
|
ng=1.0f/(eps+fabsf(chr[0][indx-v1]-chr[0][indx-v3])+fabsf(chr[0][indx+v1]-chr[0][indx-v3]));
|
|
eg=1.0f/(eps+fabsf(chr[0][indx+h1]-chr[0][indx+h3])+fabsf(chr[0][indx-h1]-chr[0][indx+h3]));
|
|
wg=1.0f/(eps+fabsf(chr[0][indx-h1]-chr[0][indx-h3])+fabsf(chr[0][indx+h1]-chr[0][indx-h3]));
|
|
sg=1.0f/(eps+fabsf(chr[0][indx+v1]-chr[0][indx+v3])+fabsf(chr[0][indx-v1]-chr[0][indx+v3]));
|
|
//Interpolate chrominance: R@G and B@G
|
|
chr[0][indx]=((ng*chr[0][indx-v1]+eg*chr[0][indx+h1]+wg*chr[0][indx-h1]+sg*chr[0][indx+v1])/(ng+eg+wg+sg));
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.78);
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=7; row<height-7; row++)
|
|
for (int col=7+(FC(row,0)&1), indx=row*width+col; col<width-7; col+=2, indx+=2) {
|
|
|
|
//N,E,W,S Gradients
|
|
ng=1.0f/(eps+fabsf(chr[1][indx-v1]-chr[1][indx-v3])+fabsf(chr[1][indx+v1]-chr[1][indx-v3]));
|
|
eg=1.0f/(eps+fabsf(chr[1][indx+h1]-chr[1][indx+h3])+fabsf(chr[1][indx-h1]-chr[1][indx+h3]));
|
|
wg=1.0f/(eps+fabsf(chr[1][indx-h1]-chr[1][indx-h3])+fabsf(chr[1][indx+h1]-chr[1][indx-h3]));
|
|
sg=1.0f/(eps+fabsf(chr[1][indx+v1]-chr[1][indx+v3])+fabsf(chr[1][indx-v1]-chr[1][indx+v3]));
|
|
//Interpolate chrominance: R@G and B@G
|
|
chr[1][indx]=((ng*chr[1][indx-v1]+eg*chr[1][indx+h1]+wg*chr[1][indx-h1]+sg*chr[1][indx+v1])/(ng+eg+wg+sg));
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp single
|
|
#endif
|
|
{
|
|
if (plistener) plistener->setProgress (0.91);
|
|
|
|
//Interpolate borders
|
|
// border_interpolate2(7, rgb);
|
|
}
|
|
/*
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=0; row < height; row++) //borders
|
|
for (int col=0; col < width; col++) {
|
|
if (col==7 && row >= 7 && row < height-7)
|
|
col = width-7;
|
|
int indxc=row*width+col;
|
|
red [row][col] = rgb[indxc][0];
|
|
green[row][col] = rgb[indxc][1];
|
|
blue [row][col] = rgb[indxc][2];
|
|
}
|
|
*/
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for(int row=7; row<height-7; row++)
|
|
for(int col=7, indx=row*width+col; col<width-7; col++, indx++) {
|
|
red [row][col] = CLIP(rgb[1][indx]-65535.f*chr[0][indx]);
|
|
green[row][col] = CLIP(rgb[1][indx]);
|
|
blue [row][col] = CLIP(rgb[1][indx]-65535.f*chr[1][indx]);
|
|
}
|
|
}// End of parallelization
|
|
|
|
if (plistener) plistener->setProgress (1.0);
|
|
|
|
free(chrarray); free(rgbarray);
|
|
free(vdif); free(hdif);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
Adaptive Homogeneity-Directed interpolation is based on
|
|
the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
|
|
*/
|
|
#define TS 256 /* Tile Size */
|
|
#define FORC(cnt) for (c=0; c < cnt; c++)
|
|
#define FORC3 FORC(3)
|
|
|
|
void RawImageSource::ahd_demosaic(int winx, int winy, int winw, int winh)
|
|
{
|
|
int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2];
|
|
float (*pix)[4], (*rix)[3];
|
|
static const int dir[4] = { -1, 1, -TS, TS };
|
|
float ldiff[2][4], abdiff[2][4], leps, abeps;
|
|
float xyz[3], xyz_cam[3][4];
|
|
float (*cbrt);
|
|
float (*rgb)[TS][TS][3];
|
|
float (*lab)[TS][TS][3];
|
|
float (*lix)[3];
|
|
char (*homo)[TS][TS], *buffer;
|
|
double r;
|
|
|
|
int width=W, height=H;
|
|
float (*image)[4];
|
|
int colors = 3;
|
|
|
|
const double xyz_rgb[3][3] = { /* XYZ from RGB */
|
|
{ 0.412453, 0.357580, 0.180423 },
|
|
{ 0.212671, 0.715160, 0.072169 },
|
|
{ 0.019334, 0.119193, 0.950227 }
|
|
};
|
|
|
|
const float d65_white[3] = { 0.950456, 1, 1.088754 };
|
|
|
|
if (plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::ahd]));
|
|
plistener->setProgress (0.0);
|
|
}
|
|
|
|
image = (float (*)[4]) calloc (H*W, sizeof *image);
|
|
for (int ii=0; ii<H; ii++)
|
|
for (int jj=0; jj<W; jj++)
|
|
image[ii*W+jj][fc(ii,jj)] = rawData[ii][jj];
|
|
|
|
cbrt = (float (*)) calloc (0x10000, sizeof *cbrt);
|
|
for (i=0; i < 0x10000; i++) {
|
|
r = (double)i / 65535.0;
|
|
cbrt[i] = r > 0.008856 ? pow(r,0.333333333) : 7.787*r + 16/116.0;
|
|
}
|
|
|
|
for (i=0; i < 3; i++)
|
|
for (j=0; j < colors; j++)
|
|
for (xyz_cam[i][j] = k=0; k < 3; k++)
|
|
xyz_cam[i][j] += xyz_rgb[i][k] * imatrices.rgb_cam[k][j] / d65_white[i];
|
|
|
|
border_interpolate(5, image);
|
|
buffer = (char *) malloc (13*TS*TS*sizeof(float)); /* 1664 kB */
|
|
//merror (buffer, "ahd_interpolate()");
|
|
rgb = (float(*)[TS][TS][3]) buffer;
|
|
lab = (float(*)[TS][TS][3])(buffer + 6*TS*TS*sizeof(float));
|
|
homo = (char (*)[TS][TS]) (buffer + 12*TS*TS*sizeof(float));
|
|
|
|
// helper variables for progress indication
|
|
int n_tiles = ((height-7 + (TS-7))/(TS-6)) * ((width-7 + (TS-7))/(TS-6));
|
|
int tile = 0;
|
|
|
|
for (top=2; top < height-5; top += TS-6)
|
|
for (left=2; left < width-5; left += TS-6) {
|
|
/* Interpolate green horizontally and vertically: */
|
|
for (row = top; row < top+TS && row < height-2; row++) {
|
|
col = left + (FC(row,left) & 1);
|
|
for (c = FC(row,col); col < left+TS && col < width-2; col+=2) {
|
|
pix = image + (row*width+col);
|
|
val = 0.25*((pix[-1][1] + pix[0][c] + pix[1][1]) * 2
|
|
- pix[-2][c] - pix[2][c]) ;
|
|
rgb[0][row-top][col-left][1] = ULIM(static_cast<float>(val),pix[-1][1],pix[1][1]);
|
|
val = 0.25*((pix[-width][1] + pix[0][c] + pix[width][1]) * 2
|
|
- pix[-2*width][c] - pix[2*width][c]) ;
|
|
rgb[1][row-top][col-left][1] = ULIM(static_cast<float>(val),pix[-width][1],pix[width][1]);
|
|
}
|
|
}
|
|
|
|
/* Interpolate red and blue, and convert to CIELab: */
|
|
for (d=0; d < 2; d++)
|
|
for (row=top+1; row < top+TS-1 && row < height-3; row++)
|
|
for (col=left+1; col < left+TS-1 && col < width-3; col++) {
|
|
pix = image + (row*width+col);
|
|
rix = &rgb[d][row-top][col-left];
|
|
lix = &lab[d][row-top][col-left];
|
|
if ((c = 2 - FC(row,col)) == 1) {
|
|
c = FC(row+1,col);
|
|
val = pix[0][1] + (0.5*( pix[-1][2-c] + pix[1][2-c]
|
|
- rix[-1][1] - rix[1][1] ) );
|
|
rix[0][2-c] = CLIP(val);
|
|
val = pix[0][1] + (0.5*( pix[-width][c] + pix[width][c]
|
|
- rix[-TS][1] - rix[TS][1] ) );
|
|
} else
|
|
val = rix[0][1] + (0.25*( pix[-width-1][c] + pix[-width+1][c]
|
|
+ pix[+width-1][c] + pix[+width+1][c]
|
|
- rix[-TS-1][1] - rix[-TS+1][1]
|
|
- rix[+TS-1][1] - rix[+TS+1][1]) );
|
|
rix[0][c] = CLIP(val);
|
|
c = FC(row,col);
|
|
rix[0][c] = pix[0][c];
|
|
xyz[0] = xyz[1] = xyz[2] = 0.0;
|
|
FORCC {
|
|
xyz[0] += xyz_cam[0][c] * rix[0][c];
|
|
xyz[1] += xyz_cam[1][c] * rix[0][c];
|
|
xyz[2] += xyz_cam[2][c] * rix[0][c];
|
|
}
|
|
|
|
xyz[0] = CurveFactory::flinterp(cbrt,xyz[0]);
|
|
xyz[1] = CurveFactory::flinterp(cbrt,xyz[1]);
|
|
xyz[2] = CurveFactory::flinterp(cbrt,xyz[2]);
|
|
|
|
//xyz[0] = xyz[0] > 0.008856 ? pow(xyz[0]/65535,1/3.0) : 7.787*xyz[0] + 16/116.0;
|
|
//xyz[1] = xyz[1] > 0.008856 ? pow(xyz[1]/65535,1/3.0) : 7.787*xyz[1] + 16/116.0;
|
|
//xyz[2] = xyz[2] > 0.008856 ? pow(xyz[2]/65535,1/3.0) : 7.787*xyz[2] + 16/116.0;
|
|
|
|
lix[0][0] = (116 * xyz[1] - 16);
|
|
lix[0][1] = 500 * (xyz[0] - xyz[1]);
|
|
lix[0][2] = 200 * (xyz[1] - xyz[2]);
|
|
}
|
|
|
|
/* Build homogeneity maps from the CIELab images: */
|
|
memset (homo, 0, 2*TS*TS);
|
|
for (row=top+2; row < top+TS-2 && row < height-4; row++) {
|
|
tr = row-top;
|
|
for (col=left+2; col < left+TS-2 && col < width-4; col++) {
|
|
tc = col-left;
|
|
for (d=0; d < 2; d++) {
|
|
lix = &lab[d][tr][tc];
|
|
for (i=0; i < 4; i++) {
|
|
ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]);
|
|
abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1])
|
|
+ SQR(lix[0][2]-lix[dir[i]][2]);
|
|
}
|
|
}
|
|
leps = min(max(ldiff[0][0],ldiff[0][1]),
|
|
max(ldiff[1][2],ldiff[1][3]));
|
|
abeps = min(max(abdiff[0][0],abdiff[0][1]),
|
|
max(abdiff[1][2],abdiff[1][3]));
|
|
for (d=0; d < 2; d++)
|
|
for (i=0; i < 4; i++)
|
|
if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
|
|
homo[d][tr][tc]++;
|
|
}
|
|
}
|
|
|
|
/* Combine the most homogenous pixels for the final result: */
|
|
for (row=top+3; row < top+TS-3 && row < height-5; row++) {
|
|
tr = row-top;
|
|
for (col=left+3; col < left+TS-3 && col < width-5; col++) {
|
|
tc = col-left;
|
|
for (d=0; d < 2; d++)
|
|
for (hm[d]=0, i=tr-1; i <= tr+1; i++)
|
|
for (j=tc-1; j <= tc+1; j++)
|
|
hm[d] += homo[d][i][j];
|
|
if (hm[0] != hm[1])
|
|
FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c];
|
|
else
|
|
FORC3 image[row*width+col][c] =
|
|
0.5*(rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) ;
|
|
}
|
|
}
|
|
|
|
tile++;
|
|
if(plistener) {
|
|
plistener->setProgress((double)tile / n_tiles);
|
|
}
|
|
}
|
|
|
|
if(plistener) plistener->setProgress (1.0);
|
|
free (buffer);
|
|
for (int i=0; i<H; i++) {
|
|
for (int j=0; j<W; j++){
|
|
red[i][j] = image[i*W+j][0];
|
|
green[i][j] = image[i*W+j][1];
|
|
blue[i][j] = image[i*W+j][2];
|
|
}
|
|
}
|
|
|
|
free (image);
|
|
free (cbrt);
|
|
}
|
|
#undef TS
|
|
|
|
void RawImageSource::nodemosaic(bool bw)
|
|
{
|
|
red(W,H);
|
|
green(W,H);
|
|
blue(W,H);
|
|
#pragma omp parallel for
|
|
for (int i=0; i<H; i++) {
|
|
for (int j=0; j<W; j++){
|
|
if (bw) {
|
|
red[i][j] = green[i][j] = blue[i][j] = rawData[i][j];
|
|
} else if(ri->getSensorType()!=ST_FUJI_XTRANS){
|
|
switch( FC(i,j)) {
|
|
case 0: red[i][j] = rawData[i][j]; green[i][j]=blue[i][j]=0; break;
|
|
case 1: green[i][j] = rawData[i][j]; red[i][j]=blue[i][j]=0; break;
|
|
case 2: blue[i][j] = rawData[i][j]; red[i][j]=green[i][j]=0; break;
|
|
}
|
|
} else {
|
|
switch( ri->XTRANSFC(i,j)) {
|
|
case 0: red[i][j] = rawData[i][j]; green[i][j]=blue[i][j]=0; break;
|
|
case 1: green[i][j] = rawData[i][j]; red[i][j]=blue[i][j]=0; break;
|
|
case 2: blue[i][j] = rawData[i][j]; red[i][j]=green[i][j]=0; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Refinement based on EECI demosaicing algorithm by L. Chang and Y.P. Tan
|
|
Paul Lee
|
|
Adapted for Rawtherapee - Jacques Desmis 04/2013
|
|
*/
|
|
|
|
#ifdef __SSE2__
|
|
#define CLIPV(a) LIMV(a,ZEROV,c65535v)
|
|
#endif
|
|
SSEFUNCTION void RawImageSource::refinement(int PassCount)
|
|
{
|
|
MyTime t1e,t2e;
|
|
t1e.set();
|
|
|
|
int width=W;
|
|
int height=H;
|
|
int w1 = width;
|
|
int w2 = 2*w1;
|
|
if (plistener) {
|
|
plistener->setProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE"));
|
|
}
|
|
|
|
array2D<float> *rgb[3];
|
|
rgb[0] = &red;
|
|
rgb[1] = &green;
|
|
rgb[2] = &blue;
|
|
|
|
for (int b=0; b<PassCount; b++) {
|
|
if (plistener) {
|
|
plistener->setProgress ((float)b/PassCount);
|
|
}
|
|
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
#endif
|
|
{
|
|
float *pix[3];
|
|
|
|
/* Reinforce interpolated green pixels on RED/BLUE pixel locations */
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=2; row < height-2; row++) {
|
|
int col = 2+(FC(row,2) & 1);
|
|
int c = FC(row,col);
|
|
#ifdef __SSE2__
|
|
__m128 dLv, dRv, dUv, dDv, v0v;
|
|
__m128 onev = _mm_set1_ps(1.f);
|
|
__m128 zd5v = _mm_set1_ps(0.5f);
|
|
__m128 c65535v = _mm_set1_ps(65535.f);
|
|
for (; col < width-8; col+=8) {
|
|
int indx = row*width+col;
|
|
pix[c] = (float*)(*rgb[c]) + indx;
|
|
pix[1] = (float*)(*rgb[1]) + indx;
|
|
dLv = onev/(onev+vabsf(LC2VFU(pix[c][ -2])-LC2VFU(pix[c][0]))+vabsf(LC2VFU(pix[1][ 1])-LC2VFU(pix[1][ -1])));
|
|
dRv = onev/(onev+vabsf(LC2VFU(pix[c][ 2])-LC2VFU(pix[c][0]))+vabsf(LC2VFU(pix[1][ 1])-LC2VFU(pix[1][ -1])));
|
|
dUv = onev/(onev+vabsf(LC2VFU(pix[c][-w2])-LC2VFU(pix[c][0]))+vabsf(LC2VFU(pix[1][w1])-LC2VFU(pix[1][-w1])));
|
|
dDv = onev/(onev+vabsf(LC2VFU(pix[c][ w2])-LC2VFU(pix[c][0]))+vabsf(LC2VFU(pix[1][w1])-LC2VFU(pix[1][-w1])));
|
|
v0v = CLIPV(LC2VFU(pix[c][0]) + zd5v +((LC2VFU(pix[1][-1])-LC2VFU(pix[c][-1]))*dLv +(LC2VFU(pix[1][1])-LC2VFU(pix[c][1]))*dRv +(LC2VFU(pix[1][-w1])-LC2VFU(pix[c][-w1]))*dUv + (LC2VFU(pix[1][w1])-LC2VFU(pix[c][w1]))*dDv ) / (dLv+dRv+dUv+dDv));
|
|
STC2VFU(pix[1][0],v0v);
|
|
}
|
|
#endif
|
|
for (; col < width-2; col+=2) {
|
|
int indx = row*width+col;
|
|
pix[c] = (float*)(*rgb[c]) + indx;
|
|
pix[1] = (float*)(*rgb[1]) + indx;
|
|
float dL = 1.f/(1.f+fabsf(pix[c][ -2]-pix[c][0])+fabsf(pix[1][ 1]-pix[1][ -1]));
|
|
float dR = 1.f/(1.f+fabsf(pix[c][ 2]-pix[c][0])+fabsf(pix[1][ 1]-pix[1][ -1]));
|
|
float dU = 1.f/(1.f+fabsf(pix[c][-w2]-pix[c][0])+fabsf(pix[1][w1]-pix[1][-w1]));
|
|
float dD = 1.f/(1.f+fabsf(pix[c][ w2]-pix[c][0])+fabsf(pix[1][w1]-pix[1][-w1]));
|
|
float v0 = (pix[c][0] + 0.5f +((pix[1][ -1]-pix[c][ -1])*dL +(pix[1][ 1]-pix[c][ 1])*dR +(pix[1][-w1]-pix[c][-w1])*dU + (pix[1][ w1]-pix[c][ w1])*dD ) / (dL+dR+dU+dD));
|
|
pix[1][0] = CLIP(v0);
|
|
}
|
|
}
|
|
/* Reinforce interpolated red/blue pixels on GREEN pixel locations */
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=2; row < height-2; row++) {
|
|
int col = 2+(FC(row,3) & 1);
|
|
int c = FC(row,col+1);
|
|
#ifdef __SSE2__
|
|
__m128 dLv, dRv, dUv, dDv, v0v;
|
|
__m128 onev = _mm_set1_ps(1.f);
|
|
__m128 zd5v = _mm_set1_ps(0.5f);
|
|
__m128 c65535v = _mm_set1_ps(65535.f);
|
|
for (; col < width-8; col+=8) {
|
|
int indx = row*width+col;
|
|
pix[1] = (float*)(*rgb[1]) + indx;
|
|
for (int i=0; i < 2; c=2-c, i++) {
|
|
pix[c] = (float*)(*rgb[c]) + indx;
|
|
dLv = onev/(onev+vabsf(LC2VFU(pix[1][ -2])-LC2VFU(pix[1][0]))+vabsf(LC2VFU(pix[c][ 1])-LC2VFU(pix[c][ -1])));
|
|
dRv = onev/(onev+vabsf(LC2VFU(pix[1][ 2])-LC2VFU(pix[1][0]))+vabsf(LC2VFU(pix[c][ 1])-LC2VFU(pix[c][ -1])));
|
|
dUv = onev/(onev+vabsf(LC2VFU(pix[1][-w2])-LC2VFU(pix[1][0]))+vabsf(LC2VFU(pix[c][w1])-LC2VFU(pix[c][-w1])));
|
|
dDv = onev/(onev+vabsf(LC2VFU(pix[1][ w2])-LC2VFU(pix[1][0]))+vabsf(LC2VFU(pix[c][w1])-LC2VFU(pix[c][-w1])));
|
|
v0v = CLIPV(LC2VFU(pix[1][0]) + zd5v -((LC2VFU(pix[1][-1])-LC2VFU(pix[c][-1]))*dLv + (LC2VFU(pix[1][1])-LC2VFU(pix[c][1]))*dRv +(LC2VFU(pix[1][-w1])-LC2VFU(pix[c][-w1]))*dUv + (LC2VFU(pix[1][w1])-LC2VFU(pix[c][w1]))*dDv ) / (dLv+dRv+dUv+dDv));
|
|
STC2VFU(pix[c][0],v0v);
|
|
}
|
|
}
|
|
#endif
|
|
for (; col < width-2; col+=2) {
|
|
int indx = row*width+col;
|
|
pix[1] = (float*)(*rgb[1]) + indx;
|
|
for (int i=0; i < 2; c=2-c, i++) {
|
|
pix[c] = (float*)(*rgb[c]) + indx;
|
|
float dL = 1.f/(1.f+fabsf(pix[1][ -2]-pix[1][0])+fabsf(pix[c][ 1]-pix[c][ -1]));
|
|
float dR = 1.f/(1.f+fabsf(pix[1][ 2]-pix[1][0])+fabsf(pix[c][ 1]-pix[c][ -1]));
|
|
float dU = 1.f/(1.f+fabsf(pix[1][-w2]-pix[1][0])+fabsf(pix[c][w1]-pix[c][-w1]));
|
|
float dD = 1.f/(1.f+fabsf(pix[1][ w2]-pix[1][0])+fabsf(pix[c][w1]-pix[c][-w1]));
|
|
float v0 = (pix[1][0] + 0.5f -((pix[1][ -1]-pix[c][ -1])*dL + (pix[1][ 1]-pix[c][ 1])*dR +(pix[1][-w1]-pix[c][-w1])*dU + (pix[1][ w1]-pix[c][ w1])*dD ) / (dL+dR+dU+dD));
|
|
pix[c][0] = CLIP(v0);
|
|
}
|
|
}
|
|
}
|
|
/* Reinforce integrated red/blue pixels on BLUE/RED pixel locations */
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=2; row < height-2; row++) {
|
|
int col = 2+(FC(row,2) & 1);
|
|
int c = 2-FC(row,col);
|
|
#ifdef __SSE2__
|
|
__m128 dLv, dRv, dUv, dDv, v0v;
|
|
__m128 onev = _mm_set1_ps(1.f);
|
|
__m128 zd5v = _mm_set1_ps(0.5f);
|
|
__m128 c65535v = _mm_set1_ps(65535.f);
|
|
for (; col < width-8; col+=8) {
|
|
int indx = row*width+col;
|
|
pix[0] = (float*)(*rgb[0]) + indx;
|
|
pix[1] = (float*)(*rgb[1]) + indx;
|
|
pix[2] = (float*)(*rgb[2]) + indx;
|
|
int d = 2 - c;
|
|
dLv = onev/(onev+vabsf(LC2VFU(pix[d][ -2])-LC2VFU(pix[d][0]))+vabsf(LC2VFU(pix[1][ 1])-LC2VFU(pix[1][ -1])));
|
|
dRv = onev/(onev+vabsf(LC2VFU(pix[d][ 2])-LC2VFU(pix[d][0]))+vabsf(LC2VFU(pix[1][ 1])-LC2VFU(pix[1][ -1])));
|
|
dUv = onev/(onev+vabsf(LC2VFU(pix[d][-w2])-LC2VFU(pix[d][0]))+vabsf(LC2VFU(pix[1][w1])-LC2VFU(pix[1][-w1])));
|
|
dDv = onev/(onev+vabsf(LC2VFU(pix[d][ w2])-LC2VFU(pix[d][0]))+vabsf(LC2VFU(pix[1][w1])-LC2VFU(pix[1][-w1])));
|
|
v0v = CLIPV(LC2VFU(pix[1][0]) + zd5v -((LC2VFU(pix[1][-1])-LC2VFU(pix[c][-1]))*dLv +(LC2VFU(pix[1][1])-LC2VFU(pix[c][1]))*dRv +(LC2VFU(pix[1][-w1])-LC2VFU(pix[c][-w1]))*dUv + (LC2VFU(pix[1][w1])-LC2VFU(pix[c][w1]))*dDv ) / (dLv+dRv+dUv+dDv));
|
|
STC2VFU(pix[c][0],v0v);
|
|
}
|
|
#endif
|
|
for (; col < width-2; col+=2) {
|
|
int indx = row*width+col;
|
|
pix[0] = (float*)(*rgb[0]) + indx;
|
|
pix[1] = (float*)(*rgb[1]) + indx;
|
|
pix[2] = (float*)(*rgb[2]) + indx;
|
|
int d = 2 - c;
|
|
float dL = 1.f/(1.f+fabsf(pix[d][ -2]-pix[d][0])+fabsf(pix[1][ 1]-pix[1][ -1]));
|
|
float dR = 1.f/(1.f+fabsf(pix[d][ 2]-pix[d][0])+fabsf(pix[1][ 1]-pix[1][ -1]));
|
|
float dU = 1.f/(1.f+fabsf(pix[d][-w2]-pix[d][0])+fabsf(pix[1][w1]-pix[1][-w1]));
|
|
float dD = 1.f/(1.f+fabsf(pix[d][ w2]-pix[d][0])+fabsf(pix[1][w1]-pix[1][-w1]));
|
|
float v0 = (pix[1][0] + 0.5f -((pix[1][ -1]-pix[c][ -1])*dL +(pix[1][ 1]-pix[c][ 1])*dR +(pix[1][-w1]-pix[c][-w1])*dU + (pix[1][ w1]-pix[c][ w1])*dD ) / (dL+dR+dU+dD));
|
|
pix[c][0] = CLIP(v0);
|
|
}
|
|
}
|
|
} // end parallel
|
|
}
|
|
t2e.set();
|
|
if (settings->verbose) printf("Refinement Lee %d usec\n", t2e.etime(t1e));
|
|
}
|
|
#ifdef __SSE2__
|
|
#undef CLIPV
|
|
#endif
|
|
|
|
|
|
// Refinement based on EECI demozaicing algorithm by L. Chang and Y.P. Tan
|
|
// from "Lassus" : Luis Sanz Rodriguez, adapted by Jacques Desmis - JDC - and Oliver Duis for RawTherapee
|
|
// increases the signal to noise ratio (PSNR) # +1 to +2 dB : tested with Dcraw : eg: Lighthouse + AMaZE : whitout refinement:39.96dB, with refinement:41.86 dB
|
|
// reduce color artifacts, improves the interpolation
|
|
// but it's relatively slow
|
|
//
|
|
// Should be DISABLED if it decreases image quality by increases some image noise and generates blocky edges
|
|
void RawImageSource::refinement_lassus(int PassCount)
|
|
{
|
|
// const int PassCount=1;
|
|
|
|
// if (settings->verbose) printf("Refinement\n");
|
|
|
|
MyTime t1e,t2e;
|
|
t1e.set();
|
|
int u=W, v=2*u, w=3*u, x=4*u, y=5*u;
|
|
float (*image)[3];
|
|
image = (float(*)[3]) calloc(W*H, sizeof *image);
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel shared(image)
|
|
#endif
|
|
{
|
|
// convert red, blue, green to image
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int i=0;i<H;i++) {
|
|
for (int j=0;j<W;j++) {
|
|
image[i*W+j][0] = red [i][j];
|
|
image[i*W+j][1] = green[i][j];
|
|
image[i*W+j][2] = blue [i][j];
|
|
}
|
|
}
|
|
|
|
for (int b=0; b<PassCount; b++) {
|
|
if (plistener) {
|
|
plistener->setProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE"));
|
|
plistener->setProgress ((float)b/PassCount);
|
|
}
|
|
|
|
// Reinforce interpolated green pixels on RED/BLUE pixel locations
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=6; row<H-6; row++) {
|
|
for (int col=6+(FC(row,2)&1),c=FC(row,col); col<W-6; col+=2) {
|
|
float (*pix)[3]=image+row*W+col;
|
|
|
|
// Cubic Spline Interpolation by Li and Randhawa, modified by Luis Sanz Rodriguez
|
|
|
|
float f[4];
|
|
f[0]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[-v][c])-x0875(pix[0][c])-x0250(pix[-x][c])))+fabs(x0875(pix[u][1])-x1125(pix[-u][1])+x0250(pix[-w][1]))+fabs(x0875(pix[-w][1])-x1125(pix[-u][1])+x0250(pix[-y][1])));
|
|
f[1]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[+2][c])-x0875(pix[0][c])-x0250(pix[+4][c])))+fabs(x0875(pix[1][1])-x1125(pix[-1][1])+x0250(pix[+3][1]))+fabs(x0875(pix[+3][1])-x1125(pix[+1][1])+x0250(pix[+5][1])));
|
|
f[2]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[-2][c])-x0875(pix[0][c])-x0250(pix[-4][c])))+fabs(x0875(pix[1][1])-x1125(pix[-1][1])+x0250(pix[-3][1]))+fabs(x0875(pix[-3][1])-x1125(pix[-1][1])+x0250(pix[-5][1])));
|
|
f[3]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[+v][c])-x0875(pix[0][c])-x0250(pix[+x][c])))+fabs(x0875(pix[u][1])-x1125(pix[-u][1])+x0250(pix[+w][1]))+fabs(x0875(pix[+w][1])-x1125(pix[+u][1])+x0250(pix[+y][1])));
|
|
|
|
float g[4];//CLIREF avoid overflow
|
|
g[0]=pix[0][c]+(x0875(CLIREF(pix[-u][1]-pix[-u][c]))+x0125(CLIREF(pix[+u][1]-pix[+u][c])));
|
|
g[1]=pix[0][c]+(x0875(CLIREF(pix[+1][1]-pix[+1][c]))+x0125(CLIREF(pix[-1][1]-pix[-1][c])));
|
|
g[2]=pix[0][c]+(x0875(CLIREF(pix[-1][1]-pix[-1][c]))+x0125(CLIREF(pix[+1][1]-pix[+1][c])));
|
|
g[3]=pix[0][c]+(x0875(CLIREF(pix[+u][1]-pix[+u][c]))+x0125(CLIREF(pix[-u][1]-pix[-u][c])));
|
|
|
|
pix[0][1]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3]) / (f[0]+f[1]+f[2]+f[3]);
|
|
|
|
}
|
|
}
|
|
// Reinforce interpolated red/blue pixels on GREEN pixel locations
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=6; row<H-6; row++) {
|
|
for (int col=6+(FC(row,3)&1),c=FC(row,col+1); col<W-6; col+=2) {
|
|
float (*pix)[3]=image+row*W+col;
|
|
for (int i=0; i<2; c=2-c,i++) {
|
|
float f[4];
|
|
f[0]=1.0f/(1.0f+xmul2f(fabs(x0875(pix[-v][1])-x1125(pix[0][1])+x0250(pix[-x][1])))+fabs(pix[u] [c]-pix[-u][c])+fabs(pix[-w][c]-pix[-u][c]));
|
|
f[1]=1.0f/(1.0f+xmul2f(fabs(x0875(pix[+2][1])-x1125(pix[0][1])+x0250(pix[+4][1])))+fabs(pix[+1][c]-pix[-1][c])+fabs(pix[+3][c]-pix[+1][c]));
|
|
f[2]=1.0f/(1.0f+xmul2f(fabs(x0875(pix[-2][1])-x1125(pix[0][1])+x0250(pix[-4][1])))+fabs(pix[+1][c]-pix[-1][c])+fabs(pix[-3][c]-pix[-1][c]));
|
|
f[3]=1.0f/(1.0f+xmul2f(fabs(x0875(pix[+v][1])-x1125(pix[0][1])+x0250(pix[+x][1])))+fabs(pix[u] [c]-pix[-u][c])+fabs(pix[+w][c]-pix[+u][c]));
|
|
|
|
float g[5];//CLIREF avoid overflow
|
|
g[0]=CLIREF(pix[-u][1]-pix[-u][c]);
|
|
g[1]=CLIREF(pix[+1][1]-pix[+1][c]);
|
|
g[2]=CLIREF(pix[-1][1]-pix[-1][c]);
|
|
g[3]=CLIREF(pix[+u][1]-pix[+u][c]);
|
|
g[4]=((f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3]) / (f[0]+f[1]+f[2]+f[3]));
|
|
pix[0][c]= pix[0][1]-(0.65f*g[4]+0.35f*CLIREF(pix[0][1]-pix[0][c]));
|
|
}
|
|
}
|
|
}
|
|
// Reinforce integrated red/blue pixels on BLUE/RED pixel locations
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int row=6; row<H-6; row++) {
|
|
for (int col=6+(FC(row,2)&1),c=2-FC(row,col),d=2-c; col<W-6; col+=2) {
|
|
float (*pix)[3]=image+row*W+col;
|
|
|
|
float f[4];
|
|
f[0]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[-v][d])-x0875(pix[0][d])-x0250(pix[-x][d])))+fabs(x0875(pix[u][1])-x1125(pix[-u][1])+x0250(pix[-w][1]))+fabs(x0875(pix[-w][1])-x1125(pix[-u][1])+x0250(pix[-y][1])));
|
|
f[1]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[+2][d])-x0875(pix[0][d])-x0250(pix[+4][d])))+fabs(x0875(pix[1][1])-x1125(pix[-1][1])+x0250(pix[+3][1]))+fabs(x0875(pix[+3][1])-x1125(pix[+1][1])+x0250(pix[+5][1])));
|
|
f[2]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[-2][d])-x0875(pix[0][d])-x0250(pix[-4][d])))+fabs(x0875(pix[1][1])-x1125(pix[-1][1])+x0250(pix[-3][1]))+fabs(x0875(pix[-3][1])-x1125(pix[-1][1])+x0250(pix[-5][1])));
|
|
f[3]=1.0f/(1.0f+xmul2f(fabs(x1125(pix[+v][d])-x0875(pix[0][d])-x0250(pix[+x][d])))+fabs(x0875(pix[u][1])-x1125(pix[-u][1])+x0250(pix[+w][1]))+fabs(x0875(pix[+w][1])-x1125(pix[+u][1])+x0250(pix[+y][1])));
|
|
|
|
float g[5];
|
|
g[0]=(x0875((pix[-u][1]-pix[-u][c]))+x0125((pix[-v][1]-pix[-v][c])));
|
|
g[1]=(x0875((pix[+1][1]-pix[+1][c]))+x0125((pix[+2][1]-pix[+2][c])));
|
|
g[2]=(x0875((pix[-1][1]-pix[-1][c]))+x0125((pix[-2][1]-pix[-2][c])));
|
|
g[3]=(x0875((pix[+u][1]-pix[+u][c]))+x0125((pix[+v][1]-pix[+v][c])));
|
|
|
|
g[4]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3]) / (f[0]+f[1]+f[2]+f[3]);
|
|
|
|
float p[9];
|
|
p[0]=(pix[-u-1][1]-pix[-u-1][c]);
|
|
p[1]=(pix[-u+0][1]-pix[-u+0][c]);
|
|
p[2]=(pix[-u+1][1]-pix[-u+1][c]);
|
|
p[3]=(pix[+0-1][1]-pix[+0-1][c]);
|
|
p[4]=(pix[+0+0][1]-pix[+0+0][c]);
|
|
p[5]=(pix[+0+1][1]-pix[+0+1][c]);
|
|
p[6]=(pix[+u-1][1]-pix[+u-1][c]);
|
|
p[7]=(pix[+u+0][1]-pix[+u+0][c]);
|
|
p[8]=(pix[+u+1][1]-pix[+u+1][c]);
|
|
|
|
// sort p[]
|
|
float temp; // used in PIX_SORT macro;
|
|
PIX_SORT(p[1],p[2]); PIX_SORT(p[4],p[5]); PIX_SORT(p[7],p[8]); PIX_SORT(p[0],p[1]); PIX_SORT(p[3],p[4]); PIX_SORT(p[6],p[7]); PIX_SORT(p[1],p[2]); PIX_SORT(p[4],p[5]); PIX_SORT(p[7],p[8]); PIX_SORT(p[0],p[3]); PIX_SORT(p[5],p[8]); PIX_SORT(p[4],p[7]); PIX_SORT(p[3],p[6]); PIX_SORT(p[1],p[4]); PIX_SORT(p[2],p[5]); PIX_SORT(p[4],p[7]); PIX_SORT(p[4],p[2]); PIX_SORT(p[6],p[4]); PIX_SORT(p[4],p[2]);
|
|
pix[0][c]=LIM(pix[0][1]-(1.30f*g[4]-0.30f*(pix[0][1]-pix[0][c])), 0.99f*(pix[0][1]-p[4]), 1.01f*(pix[0][1]-p[4]));
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// put modified values to red, green, blue
|
|
#ifdef _OPENMP
|
|
#pragma omp for
|
|
#endif
|
|
for (int i=0;i<H;i++) {
|
|
for (int j=0; j<W; j++) {
|
|
red [i][j] =image[i*W+j][0];
|
|
green[i][j] =image[i*W+j][1];
|
|
blue [i][j] =image[i*W+j][2];
|
|
}
|
|
}
|
|
}
|
|
|
|
free(image);
|
|
|
|
t2e.set();
|
|
if (settings->verbose) printf("Refinement Lassus %d usec\n", t2e.etime(t1e));
|
|
}
|
|
|
|
|
|
/*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of the author nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// If you want to use the code, you need to display name of the original authors in
|
|
// your software!
|
|
|
|
/* DCB demosaicing by Jacek Gozdz (cuniek@kft.umcs.lublin.pl)
|
|
* the code is open source (BSD licence)
|
|
*/
|
|
|
|
#define TILESIZE 256
|
|
#define TILEBORDER 10
|
|
#define CACHESIZE (TILESIZE+2*TILEBORDER)
|
|
|
|
inline void RawImageSource::dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border)
|
|
{
|
|
rowMin = border;
|
|
colMin = border;
|
|
rowMax = CACHESIZE-border;
|
|
colMax = CACHESIZE-border;
|
|
if(!y0 ) rowMin = TILEBORDER+border;
|
|
if(!x0 ) colMin = TILEBORDER+border;
|
|
if( y0+TILESIZE+TILEBORDER >= H-border) rowMax = TILEBORDER+H-border-y0;
|
|
if( x0+TILESIZE+TILEBORDER >= W-border) colMax = TILEBORDER+W-border-x0;
|
|
}
|
|
|
|
void RawImageSource::fill_raw( float (*cache )[4], int x0, int y0, float** rawData)
|
|
{
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,0);
|
|
|
|
for (int row=rowMin,y=y0-TILEBORDER+rowMin; row<rowMax; row++,y++)
|
|
for (int col=colMin,x=x0-TILEBORDER+colMin,indx=row*CACHESIZE+col; col<colMax; col++,x++,indx++){
|
|
cache[indx][fc(y,x)] = rawData[y][x];
|
|
}
|
|
}
|
|
|
|
void RawImageSource::fill_border( float (*cache )[4], int border, int x0, int y0)
|
|
{
|
|
unsigned row, col, y, x, f, c;
|
|
float sum[8];
|
|
const unsigned int colors = 3; // used in FORCC
|
|
|
|
for (row = y0; row < y0+TILESIZE+TILEBORDER && row<H; row++){
|
|
for (col = x0; col < x0+TILESIZE+TILEBORDER && col<W; col++) {
|
|
if (col >= border && col < W - border && row >= border && row < H - border){
|
|
col = W - border;
|
|
if(col >= x0+TILESIZE+TILEBORDER )
|
|
break;
|
|
}
|
|
memset(sum, 0, sizeof sum);
|
|
for (y = row - 1; y != row + 2; y++)
|
|
for (x = col - 1; x != col + 2; x++)
|
|
if (y < H && y< y0+TILESIZE+TILEBORDER && x < W && x<x0+TILESIZE+TILEBORDER) {
|
|
f = fc(y,x);
|
|
sum[f] += cache[(y-y0 +TILEBORDER)* CACHESIZE +TILEBORDER+ x-x0][f];
|
|
sum[f + 4]++;
|
|
}
|
|
f = fc(row,col);
|
|
FORCC
|
|
if (c != f && sum[c + 4]>0)
|
|
cache[(row-y0+TILEBORDER) * CACHESIZE +TILEBORDER + col-x0][c] = sum[c] / sum[c + 4];
|
|
}
|
|
}
|
|
}
|
|
// saves red and blue
|
|
void RawImageSource::copy_to_buffer( float (*buffer)[3], float (*image)[4])
|
|
{
|
|
for (int indx=0; indx < CACHESIZE*CACHESIZE; indx++) {
|
|
buffer[indx][0]=image[indx][0]; //R
|
|
buffer[indx][2]=image[indx][2]; //B
|
|
}
|
|
}
|
|
|
|
// restores red and blue
|
|
void RawImageSource::restore_from_buffer(float (*image)[4], float (*buffer)[3])
|
|
{
|
|
for (int indx=0; indx < CACHESIZE*CACHESIZE; indx++) {
|
|
image[indx][0]=buffer[indx][0]; //R
|
|
image[indx][2]=buffer[indx][2]; //B
|
|
}
|
|
}
|
|
|
|
// First pass green interpolation
|
|
void RawImageSource::dcb_hid(float (*image)[4],float (*bufferH)[3], float (*bufferV)[3], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE, v=2*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2);
|
|
|
|
// green pixels
|
|
for (int row = rowMin; row < rowMax; row++) {
|
|
for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col; col < colMax; col+=2, indx+=2) {
|
|
assert(indx-u>=0 && indx+u<u*u);
|
|
bufferH[indx][1] = (image[indx-1][1] + image[indx+1][1]) * 0.5f;
|
|
bufferV[indx][1] = (image[indx+u][1] + image[indx-u][1]) * 0.5f;
|
|
}
|
|
}
|
|
// red in blue pixel, blue in red pixel
|
|
for (int row=rowMin; row < rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin) & 1), indx=row*CACHESIZE+col, c=2-FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) {
|
|
assert(indx-u-1>=0 && indx+u+1<u*u && c>=0 && c<3);
|
|
|
|
bufferH[indx][c] = ( 4.f * bufferH[indx][1]
|
|
- bufferH[indx+u+1][1] - bufferH[indx+u-1][1] - bufferH[indx-u+1][1] - bufferH[indx-u-1][1]
|
|
+ image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] ) * 0.25f;
|
|
bufferV[indx][c] = ( 4.f * bufferV[indx][1]
|
|
- bufferV[indx+u+1][1] - bufferV[indx+u-1][1] - bufferV[indx-u+1][1] - bufferV[indx-u-1][1]
|
|
+ image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] ) * 0.25f;
|
|
}
|
|
|
|
// red or blue in green pixels
|
|
for (int row=rowMin; row<rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin+1)&1), indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col+1),d=2-c; col<colMax; col+=2, indx+=2) {
|
|
assert(indx-u>=0 && indx+u<u*u && c>=0 && c<3 && d>=0 && d<3);
|
|
bufferH[indx][c] = (image[indx+1][c] + image[indx-1][c]) * 0.5f;
|
|
bufferH[indx][d] = (2.f * bufferH[indx][1] - bufferH[indx+u][1] - bufferH[indx-u][1] + image[indx+u][d] + image[indx-u][d]) * 0.5f;
|
|
bufferV[indx][c] = (2.f * bufferV[indx][1] - bufferV[indx+1][1] - bufferV[indx-1][1] + image[indx+1][c] + image[indx-1][c]) * 0.5f;
|
|
bufferV[indx][d] = (image[indx+u][d] + image[indx-u][d]) * 0.5f;
|
|
}
|
|
|
|
// Decide green pixels
|
|
for (int row = rowMin; row < rowMax; row++)
|
|
for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col),d=2-c; col < colMax; col+=2, indx+=2) {
|
|
float current = max(image[indx+v][c], image[indx-v][c], image[indx-2][c], image[indx+2][c]) -
|
|
min(image[indx+v][c], image[indx-v][c], image[indx-2][c], image[indx+2][c]) +
|
|
max(image[indx+1+u][d], image[indx+1-u][d], image[indx-1+u][d], image[indx-1-u][d]) -
|
|
min(image[indx+1+u][d], image[indx+1-u][d], image[indx-1+u][d], image[indx-1-u][d]);
|
|
|
|
float currentH = max(bufferH[indx+v][d], bufferH[indx-v][d], bufferH[indx-2][d], bufferH[indx+2][d]) -
|
|
min(bufferH[indx+v][d], bufferH[indx-v][d], bufferH[indx-2][d], bufferH[indx+2][d]) +
|
|
max(bufferH[indx+1+u][c], bufferH[indx+1-u][c], bufferH[indx-1+u][c], bufferH[indx-1-u][c]) -
|
|
min(bufferH[indx+1+u][c], bufferH[indx+1-u][c], bufferH[indx-1+u][c], bufferH[indx-1-u][c]);
|
|
|
|
float currentV = max(bufferV[indx+v][d], bufferV[indx-v][d], bufferV[indx-2][d], bufferV[indx+2][d]) -
|
|
min(bufferV[indx+v][d], bufferV[indx-v][d], bufferV[indx-2][d], bufferV[indx+2][d]) +
|
|
max(bufferV[indx+1+u][c], bufferV[indx+1-u][c], bufferV[indx-1+u][c], bufferV[indx-1-u][c]) -
|
|
min(bufferV[indx+1+u][c], bufferV[indx+1-u][c], bufferV[indx-1+u][c], bufferV[indx-1-u][c]);
|
|
|
|
assert(indx>=0 && indx<u*u);
|
|
if (ABS(current-currentH) < ABS(current-currentV))
|
|
image[indx][1] = bufferH[indx][1];
|
|
else
|
|
image[indx][1] = bufferV[indx][1];
|
|
}
|
|
}
|
|
|
|
// missing colors are interpolated
|
|
void RawImageSource::dcb_color(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,1);
|
|
|
|
// red in blue pixel, blue in red pixel
|
|
for (int row=rowMin; row < rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin) & 1), indx=row*CACHESIZE+col, c=2-FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) {
|
|
assert(indx>=0 && indx<u*u && c>=0 && c<4);
|
|
image[indx][c] = ( 4.f * image[indx][1]
|
|
- image[indx+u+1][1] - image[indx+u-1][1] - image[indx-u+1][1] - image[indx-u-1][1]
|
|
+ image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] ) * 0.25f;
|
|
}
|
|
|
|
// red or blue in green pixels
|
|
for (int row=rowMin; row<rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin+1)&1), indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col+1),d=2-c; col<colMax; col+=2, indx+=2) {
|
|
assert(indx>=0 && indx<u*u && c>=0 && c<4);
|
|
image[indx][c] = (2.f * image[indx][1] - image[indx+1][1] - image[indx-1][1] + image[indx+1][c] + image[indx-1][c]) * 0.5f;
|
|
image[indx][d] = (2.f * image[indx][1] - image[indx+u][1] - image[indx-u][1] + image[indx+u][d] + image[indx-u][d]) * 0.5f;
|
|
}
|
|
}
|
|
|
|
// green correction
|
|
void RawImageSource::dcb_hid2(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE, v=2*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2);
|
|
|
|
for (int row=rowMin; row < rowMax; row++) {
|
|
for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) {
|
|
assert(indx-v>=0 && indx+v<u*u);
|
|
image[indx][1] = (image[indx+v][1] + image[indx-v][1] + image[indx-2][1] + image[indx+2][1]) * 0.25f +
|
|
image[indx][c] - ( image[indx+v][c] + image[indx-v][c] + image[indx-2][c] + image[indx+2][c]) * 0.25f;
|
|
}
|
|
}
|
|
}
|
|
|
|
// green is used to create
|
|
// an interpolation direction map
|
|
// 1 = vertical
|
|
// 0 = horizontal
|
|
// saved in image[][3]
|
|
void RawImageSource::dcb_map(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=4*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2);
|
|
|
|
for (int row=rowMin; row < rowMax; row++) {
|
|
for (int col=colMin, indx=row*CACHESIZE+col; col < colMax; col++, indx++) {
|
|
float *pix = &(image[indx][1]);
|
|
|
|
assert(indx>=0 && indx<u*u);
|
|
if ( *pix > ( pix[-4] + pix[+4] + pix[-u] + pix[+u])/4 )
|
|
image[indx][3] = ((min(pix[-4], pix[+4]) + pix[-4] + pix[+4] ) < (min(pix[-u], pix[+u]) + pix[-u] + pix[+u]));
|
|
else
|
|
image[indx][3] = ((max(pix[-4], pix[+4]) + pix[-4] + pix[+4] ) > (max(pix[-u], pix[+u]) + pix[-u] + pix[+u]));
|
|
}
|
|
}
|
|
}
|
|
|
|
// interpolated green pixels are corrected using the map
|
|
void RawImageSource::dcb_correction(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE, v=2*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2);
|
|
|
|
for (int row=rowMin; row < rowMax; row++) {
|
|
for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col; col < colMax; col+=2, indx+=2) {
|
|
float current = 4.f * image[indx][3] +
|
|
2.f * (image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) +
|
|
image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3];
|
|
|
|
assert(indx>=0 && indx<u*u);
|
|
image[indx][1] = ((16.f-current)*(image[indx-1][1] + image[indx+1][1]) * 0.5f + current*(image[indx-u][1] + image[indx+u][1]) * 0.5f ) * 0.0625f;
|
|
}
|
|
}
|
|
}
|
|
|
|
// R and B smoothing using green contrast, all pixels except 2 pixel wide border
|
|
void RawImageSource::dcb_pp(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2);
|
|
|
|
for (int row=rowMin; row < rowMax; row++)
|
|
for (int col=colMin, indx=row*CACHESIZE+col; col < colMax; col++, indx++) {
|
|
//int r1 = ( image[indx-1][0] + image[indx+1][0] + image[indx-u][0] + image[indx+u][0] + image[indx-u-1][0] + image[indx+u+1][0] + image[indx-u+1][0] + image[indx+u-1][0])/8;
|
|
//int g1 = ( image[indx-1][1] + image[indx+1][1] + image[indx-u][1] + image[indx+u][1] + image[indx-u-1][1] + image[indx+u+1][1] + image[indx-u+1][1] + image[indx+u-1][1])/8;
|
|
//int b1 = ( image[indx-1][2] + image[indx+1][2] + image[indx-u][2] + image[indx+u][2] + image[indx-u-1][2] + image[indx+u+1][2] + image[indx-u+1][2] + image[indx+u-1][2])/8;
|
|
float (*pix)[4] = image+(indx-u-1);
|
|
float r1 = (*pix)[0];
|
|
float g1 = (*pix)[1];
|
|
float b1 = (*pix)[2];
|
|
pix++;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
pix++;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
pix+=CACHESIZE-2;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
pix+=2;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
pix+=CACHESIZE-2;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
pix++;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
pix++;
|
|
r1 += (*pix)[0];
|
|
g1 += (*pix)[1];
|
|
b1 += (*pix)[2];
|
|
r1 *=0.125f;
|
|
g1 *=0.125f;
|
|
b1 *=0.125f;
|
|
r1 = r1 + ( image[indx][1] - g1 );
|
|
b1 = b1 + ( image[indx][1] - g1 );
|
|
|
|
assert(indx>=0 && indx<u*u);
|
|
image[indx][0] = r1;
|
|
image[indx][2] = b1;
|
|
}
|
|
}
|
|
|
|
// interpolated green pixels are corrected using the map
|
|
// with correction
|
|
void RawImageSource::dcb_correction2(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE, v=2*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,4);
|
|
|
|
for (int row=rowMin; row < rowMax; row++) {
|
|
for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) {
|
|
float current = 4.f * image[indx][3] +
|
|
2.f * (image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) +
|
|
image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3];
|
|
|
|
assert(indx>=0 && indx<u*u);
|
|
image[indx][1] = ((16.f-current)*((image[indx-1][1] + image[indx+1][1]) * 0.5f
|
|
+ image[indx][c] - (image[indx+2][c] + image[indx-2][c]) * 0.5f)
|
|
+ current*((image[indx-u][1] + image[indx+u][1]) * 0.5f + image[indx][c] - (image[indx+v][c] + image[indx-v][c]) * 0.5f)) * 0.0625f;
|
|
}
|
|
}
|
|
}
|
|
|
|
// image refinement
|
|
void RawImageSource::dcb_refinement(float (*image)[4], int x0, int y0)
|
|
{
|
|
const int u=CACHESIZE, v=2*CACHESIZE, w=3*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,4);
|
|
|
|
float f[5],g1,g2;
|
|
|
|
for (int row=rowMin; row < rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2,indx+=2){
|
|
float current = 4.f * image[indx][3] +
|
|
2.f * (image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3])
|
|
+image[indx+v][3] + image[indx-v][3] + image[indx-2][3] + image[indx+2][3];
|
|
|
|
f[0] = (float)(image[indx-u][1] + image[indx+u][1])/(2.f + 2.f * image[indx][c]);
|
|
f[1] = 2.f * image[indx-u][1]/(2 + image[indx-v][c] + image[indx][c]);
|
|
f[2] = (float)(image[indx-u][1] + image[indx-w][1])/(2.f + 2.f * image[indx-v][c]);
|
|
f[3] = 2.f * image[indx+u][1]/(2 + image[indx+v][c] + image[indx][c]);
|
|
f[4] = (float)(image[indx+u][1] + image[indx+w][1])/(2.f + 2.f * image[indx+v][c]);
|
|
|
|
g1 = (f[0] + f[1] + f[2] + f[3] + f[4] - max(f[1], f[2], f[3], f[4]) - min(f[1], f[2], f[3], f[4])) / 3.f;
|
|
|
|
f[0] = (float)(image[indx-1][1] + image[indx+1][1])/(2.f + 2.f * image[indx][c]);
|
|
f[1] = 2.f * image[indx-1][1]/(2 + image[indx-2][c] + image[indx][c]);
|
|
f[2] = (float)(image[indx-1][1] + image[indx-3][1])/(2.f + 2.f * image[indx-2][c]);
|
|
f[3] = 2.f * image[indx+1][1]/(2 + image[indx+2][c] + image[indx][c]);
|
|
f[4] = (float)(image[indx+1][1] + image[indx+3][1])/(2.f + 2.f * image[indx+2][c]);
|
|
|
|
g2 = (f[0] + f[1] + f[2] + f[3] + f[4] - max(f[1], f[2], f[3], f[4]) - min(f[1], f[2], f[3], f[4])) / 3.f;
|
|
|
|
assert(indx>=0 && indx<u*u);
|
|
image[indx][1] = (2.f+image[indx][c]) * (current*g1 + (16.f-current)*g2) * 0.0625f;
|
|
|
|
// get rid of the overshooted pixels
|
|
float min_f = min(image[indx+1+u][1], min(image[indx+1-u][1], min(image[indx-1+u][1], min(image[indx-1-u][1], min(image[indx-1][1], min(image[indx+1][1], min(image[indx-u][1], image[indx+u][1])))))));
|
|
float max_f = max(image[indx+1+u][1], max(image[indx+1-u][1], max(image[indx-1+u][1], max(image[indx-1-u][1], max(image[indx-1][1], max(image[indx+1][1], max(image[indx-u][1], image[indx+u][1])))))));
|
|
|
|
image[indx][1] = LIM(image[indx][1], min_f, max_f);
|
|
}
|
|
}
|
|
|
|
// missing colors are interpolated using high quality algorithm by Luis Sanz Rodriguez
|
|
void RawImageSource::dcb_color_full(float (*image)[4], int x0, int y0, float (*chroma)[2])
|
|
{
|
|
const int u=CACHESIZE, w=3*CACHESIZE;
|
|
int rowMin,colMin,rowMax,colMax;
|
|
dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,3);
|
|
|
|
float f[4],g[4];
|
|
|
|
for (int row=1; row < CACHESIZE-1; row++)
|
|
for (int col=1+(FC(y0-TILEBORDER+row,x0-TILEBORDER+1)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col),d=c/2; col < CACHESIZE-1; col+=2,indx+=2) {
|
|
assert(indx>=0 && indx<u*u && c>=0 && c<4);
|
|
chroma[indx][d]=image[indx][c]-image[indx][1];
|
|
}
|
|
|
|
for (int row=rowMin; row<rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=1-FC(y0-TILEBORDER+row,x0-TILEBORDER+col)/2; col<colMax; col+=2,indx+=2) {
|
|
f[0]=1.f/(float)(1.f+fabs(chroma[indx-u-1][c]-chroma[indx+u+1][c])+fabs(chroma[indx-u-1][c]-chroma[indx-w-3][c])+fabs(chroma[indx+u+1][c]-chroma[indx-w-3][c]));
|
|
f[1]=1.f/(float)(1.f+fabs(chroma[indx-u+1][c]-chroma[indx+u-1][c])+fabs(chroma[indx-u+1][c]-chroma[indx-w+3][c])+fabs(chroma[indx+u-1][c]-chroma[indx-w+3][c]));
|
|
f[2]=1.f/(float)(1.f+fabs(chroma[indx+u-1][c]-chroma[indx-u+1][c])+fabs(chroma[indx+u-1][c]-chroma[indx+w+3][c])+fabs(chroma[indx-u+1][c]-chroma[indx+w-3][c]));
|
|
f[3]=1.f/(float)(1.f+fabs(chroma[indx+u+1][c]-chroma[indx-u-1][c])+fabs(chroma[indx+u+1][c]-chroma[indx+w-3][c])+fabs(chroma[indx-u-1][c]-chroma[indx+w+3][c]));
|
|
g[0]=1.325f * chroma[indx-u-1][c] - 0.175f*chroma[indx-w-3][c] - 0.075f*chroma[indx-w-1][c] - 0.075f*chroma[indx-u-3][c];
|
|
g[1]=1.325f * chroma[indx-u+1][c] - 0.175f*chroma[indx-w+3][c] - 0.075f*chroma[indx-w+1][c] - 0.075f*chroma[indx-u+3][c];
|
|
g[2]=1.325f * chroma[indx+u-1][c] - 0.175f*chroma[indx+w-3][c] - 0.075f*chroma[indx+w-1][c] - 0.075f*chroma[indx+u-3][c];
|
|
g[3]=1.325f * chroma[indx+u+1][c] - 0.175f*chroma[indx+w+3][c] - 0.075f*chroma[indx+w+1][c] - 0.075f*chroma[indx+u+3][c];
|
|
|
|
assert(indx>=0 && indx<u*u && c>=0 && c<2);
|
|
chroma[indx][c]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3]);
|
|
}
|
|
for (int row=rowMin; row<rowMax; row++)
|
|
for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin+1)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col+1)/2; col<colMax; col+=2,indx+=2)
|
|
for(int d=0;d<=1;c=1-c,d++){
|
|
f[0]= 1.f/(float)(1.f + fabs(chroma[indx-u][c]-chroma[indx+u][c])+fabs(chroma[indx-u][c]-chroma[indx-w][c])+fabs(chroma[indx+u][c]-chroma[indx-w][c]));
|
|
f[1]= 1.f/(float)(1.f + fabs(chroma[indx+1][c]-chroma[indx-1][c])+fabs(chroma[indx+1][c]-chroma[indx+3][c])+fabs(chroma[indx-1][c]-chroma[indx+3][c]));
|
|
f[2]= 1.f/(float)(1.f + fabs(chroma[indx-1][c]-chroma[indx+1][c])+fabs(chroma[indx-1][c]-chroma[indx-3][c])+fabs(chroma[indx+1][c]-chroma[indx-3][c]));
|
|
f[3]= 1.f/(float)(1.f + fabs(chroma[indx+u][c]-chroma[indx-u][c])+fabs(chroma[indx+u][c]-chroma[indx+w][c])+fabs(chroma[indx-u][c]-chroma[indx+w][c]));
|
|
|
|
g[0]= 0.875f * chroma[indx-u][c] + 0.125f * chroma[indx-w][c];
|
|
g[1]= 0.875f * chroma[indx+1][c] + 0.125f * chroma[indx+3][c];
|
|
g[2]= 0.875f * chroma[indx-1][c] + 0.125f * chroma[indx-3][c];
|
|
g[3]= 0.875f * chroma[indx+u][c] + 0.125f * chroma[indx+w][c];
|
|
|
|
assert(indx>=0 && indx<u*u && c>=0 && c<2);
|
|
chroma[indx][c]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3]);
|
|
}
|
|
|
|
for(int row=rowMin; row<rowMax; row++)
|
|
for(int col=colMin,indx=row*CACHESIZE+col; col<colMax; col++,indx++){
|
|
assert(indx>=0 && indx<u*u);
|
|
|
|
image[indx][0] = chroma[indx][0] + image[indx][1];
|
|
image[indx][2] = chroma[indx][1] + image[indx][1];
|
|
}
|
|
}
|
|
|
|
// DCB demosaicing main routine (sharp version)
|
|
void RawImageSource::dcb_demosaic(int iterations, bool dcb_enhance)
|
|
{
|
|
double currentProgress=0.0;
|
|
if(plistener) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb]));
|
|
plistener->setProgress (currentProgress);
|
|
}
|
|
|
|
int wTiles = W/TILESIZE + (W%TILESIZE?1:0);
|
|
int hTiles = H/TILESIZE + (H%TILESIZE?1:0);
|
|
int numTiles = wTiles * hTiles;
|
|
int tilesDone=0;
|
|
#ifdef _OPENMP
|
|
int nthreads = omp_get_max_threads();
|
|
float (**image)[4] = (float(**)[4]) calloc( nthreads,sizeof( void*) );
|
|
float (**image2)[3] = (float(**)[3]) calloc( nthreads,sizeof( void*) );
|
|
float (**image3)[3] = (float(**)[3]) calloc( nthreads,sizeof( void*) );
|
|
float (**chroma)[2] = (float (**)[2]) calloc( nthreads,sizeof( void*) );
|
|
for(int i=0; i<nthreads; i++){
|
|
image[i] = (float(*)[4]) calloc( CACHESIZE*CACHESIZE, sizeof **image);
|
|
image2[i]= (float(*)[3]) calloc( CACHESIZE*CACHESIZE, sizeof **image2);
|
|
image3[i]= (float(*)[3]) calloc( CACHESIZE*CACHESIZE, sizeof **image3);
|
|
chroma[i]= (float (*)[2]) calloc( CACHESIZE*CACHESIZE, sizeof **chroma);
|
|
}
|
|
#else
|
|
float (*image)[4] = (float(*)[4]) calloc( CACHESIZE*CACHESIZE, sizeof *image);
|
|
float (*image2)[3] = (float(*)[3]) calloc( CACHESIZE*CACHESIZE, sizeof *image2);
|
|
float (*image3)[3] = (float(*)[3]) calloc( CACHESIZE*CACHESIZE, sizeof *image3);
|
|
float (*chroma)[2] = (float (*)[2]) calloc( CACHESIZE*CACHESIZE, sizeof *chroma);
|
|
#endif
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for( int iTile=0; iTile < numTiles; iTile++){
|
|
int xTile = iTile % wTiles;
|
|
int yTile = iTile / wTiles;
|
|
int x0 = xTile*TILESIZE;
|
|
int y0 = yTile*TILESIZE;
|
|
|
|
#ifdef _OPENMP
|
|
int tid = omp_get_thread_num();
|
|
assert(tid<nthreads);
|
|
float (*tile)[4] = image[tid];
|
|
float (*buffer)[3] = image2[tid];
|
|
float (*buffer2)[3]= image3[tid];
|
|
float (*chrm)[2] = chroma[tid];
|
|
#else
|
|
float (*tile)[4] = image;
|
|
float (*buffer)[3] = image2;
|
|
float (*buffer2)[3]= image3;
|
|
float (*chrm)[2] = chroma;
|
|
#endif
|
|
|
|
fill_raw( tile, x0,y0,rawData );
|
|
if( !xTile || !yTile || xTile==wTiles-1 || yTile==hTiles-1)
|
|
fill_border(tile,6, x0, y0);
|
|
dcb_hid(tile,buffer,buffer2,x0,y0);
|
|
copy_to_buffer(buffer, tile);
|
|
for (int i=iterations; i>0;i--) {
|
|
dcb_hid2(tile,x0,y0);
|
|
dcb_hid2(tile,x0,y0);
|
|
dcb_hid2(tile,x0,y0);
|
|
dcb_map(tile,x0,y0);
|
|
dcb_correction(tile,x0,y0);
|
|
}
|
|
dcb_color(tile,x0,y0);
|
|
dcb_pp(tile,x0,y0);
|
|
dcb_map(tile,x0,y0);
|
|
dcb_correction2(tile,x0,y0);
|
|
dcb_map(tile,x0,y0);
|
|
dcb_correction(tile,x0,y0);
|
|
dcb_color(tile,x0,y0);
|
|
dcb_map(tile,x0,y0);
|
|
dcb_correction(tile,x0,y0);
|
|
dcb_map(tile,x0,y0);
|
|
dcb_correction(tile,x0,y0);
|
|
dcb_map(tile,x0,y0);
|
|
restore_from_buffer(tile, buffer);
|
|
dcb_color(tile,x0,y0);
|
|
if (dcb_enhance) {
|
|
dcb_refinement(tile,x0,y0);
|
|
dcb_color_full(tile,x0,y0,chrm);
|
|
}
|
|
|
|
for(int y=0;y<TILESIZE && y0+y<H;y++){
|
|
for (int j=0; j<TILESIZE && x0+j<W; j++){
|
|
red[y0+y][x0+j] = tile[(y+TILEBORDER)*CACHESIZE+TILEBORDER+j][0];
|
|
green[y0+y][x0+j] = tile[(y+TILEBORDER)*CACHESIZE+TILEBORDER+j][1];
|
|
blue[y0+y][x0+j] = tile[(y+TILEBORDER)*CACHESIZE+TILEBORDER+j][2];
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
if(omp_get_thread_num()==0)
|
|
#endif
|
|
{
|
|
if( plistener && double(tilesDone)/numTiles > currentProgress){
|
|
currentProgress+=0.1; // Show progress each 10%
|
|
plistener->setProgress (currentProgress);
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp atomic
|
|
#endif
|
|
tilesDone++;
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
for(int i=0; i<nthreads; i++){
|
|
free(image[i]);
|
|
free(image2[i]);
|
|
free(image3[i]);
|
|
free(chroma[i]);
|
|
}
|
|
#endif
|
|
free(image);
|
|
free(image2);
|
|
free(image3);
|
|
free(chroma);
|
|
|
|
if(plistener) plistener->setProgress (1.0);
|
|
}
|
|
|
|
const double xyz_rgb[3][3] = { // XYZ from RGB
|
|
{ 0.412453, 0.357580, 0.180423 },
|
|
{ 0.212671, 0.715160, 0.072169 },
|
|
{ 0.019334, 0.119193, 0.950227 } };
|
|
const float d65_white[3] = { 0.950456, 1, 1.088754 };
|
|
|
|
void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b, const int width, const int height, const int labWidth, const float xyz_cam[3][3])
|
|
{
|
|
static float cbrt[0x10000];
|
|
static bool cbrtinit = false;
|
|
if (!rgb) {
|
|
int i, j, k;
|
|
float r;
|
|
if(!cbrtinit) {
|
|
for (i=0; i < 0x10000; i++) {
|
|
r = i / 65535.f;
|
|
cbrt[i] = r > 0.008856f ? xcbrtf(r) : 7.787f*r + 16.f/116.f;
|
|
}
|
|
cbrtinit = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
int rgbOffset = (width - labWidth);
|
|
for(int i=0;i<height;i++) {
|
|
for(int j=0;j<labWidth;j++) {
|
|
float xyz[3] = {0.5f};
|
|
int c;
|
|
FORC3 {
|
|
xyz[0] += xyz_cam[0][c] * rgb[i*width+j][c];
|
|
xyz[1] += xyz_cam[1][c] * rgb[i*width+j][c];
|
|
xyz[2] += xyz_cam[2][c] * rgb[i*width+j][c];
|
|
}
|
|
xyz[0] = cbrt[CLIP((int) xyz[0])];
|
|
xyz[1] = cbrt[CLIP((int) xyz[1])];
|
|
xyz[2] = cbrt[CLIP((int) xyz[2])];
|
|
|
|
l[i*labWidth+j] = 116 * xyz[1] - 16;
|
|
a[i*labWidth+j] = 500 * (xyz[0] - xyz[1]);
|
|
b[i*labWidth+j] = 200 * (xyz[1] - xyz[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define fcol(row,col) xtrans[(row)%6][(col)%6]
|
|
|
|
void RawImageSource::xtransborder_interpolate (int border)
|
|
{
|
|
const int height = H, width = W;
|
|
|
|
char xtrans[6][6];
|
|
ri->getXtransMatrix(xtrans);
|
|
|
|
for (int row=0; row < height; row++)
|
|
for (int col=0; col < width; col++) {
|
|
if (col==border && row >= border && row < height-border)
|
|
col = width-border;
|
|
float sum[6] = {0.f};
|
|
for (int y=MAX(0,row-1); y <= MIN(row+1,height-1); y++)
|
|
for (int x=MAX(0,col-1); x <= MIN(col+1,width-1); x++) {
|
|
int f = fcol(y,x);
|
|
sum[f] += rawData[y][x];
|
|
sum[f+3]++;
|
|
}
|
|
|
|
switch(fcol(row,col)) {
|
|
case 0: red[row][col] = rawData[row][col];
|
|
green[row][col] = (sum[1]/sum[4]);
|
|
blue[row][col] = (sum[2]/sum[5]);
|
|
break;
|
|
case 1: if(sum[3]==0.f) { // at the 4 corner pixels it can happen, that we have only green pixels in 2x2 area
|
|
red[row][col] = green[row][col] = blue[row][col] = rawData[row][col];
|
|
} else {
|
|
red[row][col] = (sum[0]/sum[3]);
|
|
green[row][col] = rawData[row][col];
|
|
blue[row][col] = (sum[2]/sum[5]);
|
|
}
|
|
break;
|
|
case 2: red[row][col] = (sum[0]/sum[3]);
|
|
green[row][col] = (sum[1]/sum[4]);
|
|
blue[row][col] = rawData[row][col];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Frank Markesteijn's algorithm for Fuji X-Trans sensors
|
|
adapted to RT by Ingo Weyrich 2014
|
|
*/
|
|
|
|
#define TS 122 /* Tile Size */
|
|
|
|
void RawImageSource::xtrans_interpolate (int passes, bool useCieLab)
|
|
{
|
|
double progress = 0.0;
|
|
const bool plistenerActive = plistener;
|
|
|
|
if (plistenerActive) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "Xtrans"));
|
|
plistener->setProgress (progress);
|
|
}
|
|
|
|
char xtrans[6][6];
|
|
ri->getXtransMatrix(xtrans);
|
|
|
|
static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 },
|
|
patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 },
|
|
{ 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } },
|
|
dir[4] = { 1,TS,TS+1,TS-1 };
|
|
|
|
short allhex[2][3][3][8];
|
|
|
|
// sgrow/sgcol is the offset in the sensor matrix of the solitary
|
|
// green pixels
|
|
ushort sgrow, sgcol;
|
|
|
|
const int height = H, width = W;
|
|
|
|
if (settings->verbose)
|
|
printf("%d-pass X-Trans interpolation using %s conversion...\n", passes, useCieLab ? "lab" : "yuv");
|
|
|
|
xtransborder_interpolate(6);
|
|
|
|
float xyz_cam[3][3];
|
|
{
|
|
float rgb_cam[3][4];
|
|
ri->getRgbCam(rgb_cam);
|
|
int k;
|
|
for (int i=0; i < 3; i++)
|
|
for (int j=0; j < 3; j++)
|
|
for (xyz_cam[i][j] = k=0; k < 3; k++)
|
|
xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i];
|
|
}
|
|
|
|
/* Map a green hexagon around each non-green pixel and vice versa: */
|
|
{
|
|
int gint, d, h, v, ng, row, col, c;
|
|
|
|
for (row=0; row < 3; row++)
|
|
for (col=0; col < 3; col++) {
|
|
gint = fcol(row,col) == 1;
|
|
for (ng=d=0; d < 10; d+=2) {
|
|
if (fcol(row+orth[d]+6,col+orth[d+2]+6) == 1)
|
|
ng=0;
|
|
else
|
|
ng++;
|
|
if (ng == 4) {
|
|
// if there are four non-green pixels adjacent in cardinal
|
|
// directions, this is the solitary green pixel
|
|
sgrow = row;
|
|
sgcol = col;
|
|
}
|
|
if (ng == gint+1)
|
|
FORC(8) {
|
|
v = orth[d]*patt[gint][c*2] + orth[d+1]*patt[gint][c*2+1];
|
|
h = orth[d+2]*patt[gint][c*2] + orth[d+3]*patt[gint][c*2+1];
|
|
allhex[0][row][col][c^(gint*2 & d)] = h + v*width;
|
|
allhex[1][row][col][c^(gint*2 & d)] = h + v*TS;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if(plistenerActive) {
|
|
progress += 0.05;
|
|
plistener->setProgress(progress);
|
|
}
|
|
|
|
|
|
double progressInc = 36.0*(1.0-progress)/((H*W)/((TS-16)*(TS-16)));
|
|
const int ndir = 4 << (passes > 1);
|
|
cielab (0,0,0,0,0,0,0,0);
|
|
struct s_minmaxgreen {
|
|
float min;
|
|
float max;
|
|
};
|
|
|
|
int RightShift[6];
|
|
for(int row=0;row<6;row++) {
|
|
// count number of green pixels in three cols
|
|
int greencount = 0;
|
|
for(int col=0;col<3;col++)
|
|
greencount += (fcol(row,col) == 1);
|
|
RightShift[row] = (greencount == 2);
|
|
}
|
|
|
|
|
|
#pragma omp parallel
|
|
{
|
|
int progressCounter = 0;
|
|
short *hex;
|
|
int c, d, f, h, i, v, mrow, mcol;
|
|
int pass;
|
|
float color[3][8], g, val;
|
|
float (*rgb)[TS][TS][3], (*rix)[3];
|
|
float (*lab)[TS-8][TS-8];
|
|
float (*drv)[TS-10][TS-10], diff[6], tr;
|
|
s_minmaxgreen (*greenminmaxtile)[TS];
|
|
uint8_t (*homo)[TS][TS];
|
|
uint8_t (*homosum)[TS][TS];
|
|
float *buffer;
|
|
buffer = (float *) malloc ((TS*TS*(ndir*3+11)+128)*sizeof(float));
|
|
rgb = (float(*)[TS][TS][3]) buffer;
|
|
lab = (float (*) [TS-8][TS-8])(buffer + TS*TS*(ndir*3));
|
|
drv = (float (*)[TS-10][TS-10]) (buffer + TS*TS*(ndir*3+3));
|
|
homo = (uint8_t (*)[TS][TS]) (lab); // we can reuse the lab-buffer because they are not used together
|
|
greenminmaxtile = (s_minmaxgreen(*)[TS]) (lab); // we can reuse the lab-buffer because they are not used together
|
|
homosum = (uint8_t (*)[TS][TS]) (drv); // we can reuse the drv-buffer because they are not used together
|
|
|
|
#pragma omp for collapse(2) schedule(dynamic) nowait
|
|
for (int top=3; top < height-19; top += TS-16)
|
|
for (int left=3; left < width-19; left += TS-16) {
|
|
int mrow = MIN (top+TS, height-3);
|
|
int mcol = MIN (left+TS, width-3);
|
|
memset(rgb,0,TS*TS*3*sizeof(float));
|
|
for (int row=top; row < mrow; row++)
|
|
for (int col=left; col < mcol; col++) {
|
|
rgb[0][row-top][col-left][fcol(row,col)] = rawData[row][col];
|
|
}
|
|
FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb);
|
|
|
|
/* Set green1 and green3 to the minimum and maximum allowed values: */
|
|
for (int row=top; row < mrow; row++) {
|
|
float minval=FLT_MAX;
|
|
float maxval=0.f;
|
|
int shiftindex = RightShift[(row)%6];
|
|
for (int col=left; col < mcol; col++) {
|
|
if (fcol(row,col) == 1) {
|
|
minval=FLT_MAX;
|
|
maxval=0.f;
|
|
continue;
|
|
}
|
|
float *pix = &rawData[row][col];
|
|
hex = allhex[0][row % 3][col % 3];
|
|
if (maxval==0.f)
|
|
FORC(6) {
|
|
val = pix[hex[c]];
|
|
if (minval > val)
|
|
minval = val;
|
|
if (maxval < val)
|
|
maxval = val;
|
|
}
|
|
greenminmaxtile[row-top][(col-left)>>shiftindex].min = minval;
|
|
greenminmaxtile[row-top][(col-left)>>shiftindex].max = maxval;
|
|
switch ((row-sgrow) % 3) {
|
|
case 1: if (row < mrow-1) {
|
|
row++;
|
|
shiftindex = RightShift[(row)%6];
|
|
col--;
|
|
}
|
|
break;
|
|
case 2: minval=FLT_MAX;
|
|
maxval=0.f;
|
|
if ((col+=2) < mcol-1 && row > top+1) {
|
|
row--;
|
|
shiftindex = RightShift[(row)%6];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Interpolate green horizontally, vertically, and along both diagonals: */
|
|
for (int row=top; row < mrow; row++) {
|
|
// find first non-green pixel
|
|
int leftstart = left;
|
|
for(;leftstart<mcol;leftstart++)
|
|
if(fcol(row,leftstart)!=1)
|
|
break;
|
|
const int shiftindex = RightShift[(row)%6];
|
|
const int coloffset = (shiftindex == 1 ? 3:1);
|
|
for (int col=leftstart; col < mcol; col+=coloffset) {
|
|
if (fcol(row,col) == 1)
|
|
continue;
|
|
float *pix = &rawData[row][col];
|
|
hex = allhex[0][row % 3][col % 3];
|
|
color[1][0] = 0.6796875f * (pix[hex[1]] + pix[hex[0]]) -
|
|
0.1796875f * (pix[2*hex[1]] + pix[2*hex[0]]);
|
|
color[1][1] = 0.87109375f * pix[hex[3]] + pix[hex[2]] * 0.12890625f +
|
|
0.359375f * (pix[0] - pix[-hex[2]]);
|
|
FORC(2)
|
|
color[1][2+c] = 0.640625f * pix[hex[4+c]] + 0.359375f * pix[-2*hex[4+c]] + 0.12890625f *
|
|
(2.f*pix[0] - pix[3*hex[4+c]] - pix[-3*hex[4+c]]);
|
|
FORC(4)
|
|
rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = LIM(color[1][c],greenminmaxtile[row-top][(col-left)>>shiftindex].min,greenminmaxtile[row-top][(col-left)>>shiftindex].max);
|
|
}
|
|
}
|
|
for (pass=0; pass < passes; pass++) {
|
|
if (pass == 1)
|
|
memcpy (rgb+=4, buffer, 4*sizeof *rgb);
|
|
|
|
/* Recalculate green from interpolated values of closer pixels: */
|
|
if (pass) {
|
|
for (int row=top+2; row < mrow-2; row++) {
|
|
int leftstart = left+2;
|
|
for(;leftstart<mcol-2;leftstart++)
|
|
if(fcol(row,leftstart)!=1)
|
|
break;
|
|
const int shiftindex = RightShift[(row)%6];
|
|
const int coloffset = (shiftindex == 1 ? 3:1);
|
|
for (int col=leftstart; col < mcol-2; col+=coloffset) {
|
|
if ((f = fcol(row,col)) == 1)
|
|
continue;
|
|
hex = allhex[1][row % 3][col % 3];
|
|
for (d=3; d < 6; d++) {
|
|
rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left];
|
|
val = rix[-2*hex[d]][1] + 2*(rix[hex[d]][1] - rix[hex[d]][f])
|
|
- rix[-2*hex[d]][f] + 3*rix[0][f];
|
|
rix[0][1] = LIM((float)(val*.33333333f),greenminmaxtile[row-top][(col-left)>>shiftindex].min,greenminmaxtile[row-top][(col-left)>>shiftindex].max);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Interpolate red and blue values for solitary green pixels: */
|
|
for (int row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3)
|
|
for (int col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) {
|
|
rix = &rgb[0][row-top][col-left];
|
|
h = fcol(row,col+1);
|
|
memset (diff, 0, sizeof diff);
|
|
for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) {
|
|
for (c=0; c < 2; c++, h^=2) {
|
|
g = rix[0][1] + rix[0][1] - rix[i<<c][1] - rix[-i<<c][1];
|
|
color[h][d] = g + rix[i<<c][h] + rix[-i<<c][h];
|
|
if (d > 1)
|
|
diff[d] += SQR (rix[i<<c][1] - rix[-i<<c][1]
|
|
- rix[i<<c][h] + rix[-i<<c][h]) + SQR(g);
|
|
}
|
|
if (d > 2 && (d & 1)) // 3, 5
|
|
if (diff[d-1] < diff[d])
|
|
FORC(2)
|
|
color[c*2][d] = color[c*2][d-1];
|
|
if ((d & 1) || d < 2) { // d: 0, 1, 3, 5
|
|
FORC(2)
|
|
rix[0][c*2] = CLIP(0.5f*color[c*2][d]);
|
|
rix += TS*TS;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Interpolate red for blue pixels and vice versa: */
|
|
for (int row=top+3; row < mrow-3; row++) {
|
|
int leftstart = left+3;
|
|
for(;leftstart<mcol-1;leftstart++)
|
|
if(fcol(row,leftstart)!=1)
|
|
break;
|
|
const int coloffset = (RightShift[(row)%6] == 1 ? 3:1);
|
|
c = (row-sgrow) % 3 ? TS:1;
|
|
h = 3 * (c ^ TS ^ 1);
|
|
for (int col=leftstart; col < mcol-3; col+=coloffset) {
|
|
if ((f = 2-fcol(row,col)) == 1)
|
|
continue;
|
|
rix = &rgb[0][row-top][col-left];
|
|
for (d=0; d < 4; d++, rix += TS*TS) {
|
|
i = d > 1 || ((d ^ c) & 1) ||
|
|
((fabsf(rix[0][1]-rix[c][1])+fabsf(rix[0][1]-rix[-c][1])) < 2.f*(fabsf(rix[0][1]-rix[h][1])+fabsf(rix[0][1]-rix[-h][1]))) ? c:h;
|
|
|
|
rix[0][f] = CLIP(0.5f*(rix[i][f] + rix[-i][f] +
|
|
rix[0][1] + rix[0][1] - rix[i][1] - rix[-i][1]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Fill in red and blue for 2x2 blocks of green: */
|
|
for (int row=top+2; row < mrow-2; row++)
|
|
if ((row-sgrow) % 3) {
|
|
for (int col=left+2; col < mcol-2; col++)
|
|
if ((col-sgcol) % 3) {
|
|
rix = &rgb[0][row-top][col-left];
|
|
hex = allhex[1][row%3][col % 3];
|
|
for (d=0; d < ndir; d+=2, rix += TS*TS)
|
|
if (hex[d] + hex[d+1]) {
|
|
g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1];
|
|
for (c=0; c < 4; c+=2)
|
|
rix[0][c] = CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])*0.33333333f);
|
|
} else {
|
|
g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1];
|
|
for (c=0; c < 4; c+=2)
|
|
rix[0][c] = CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])*0.5f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// end of multipass part
|
|
rgb = (float(*)[TS][TS][3]) buffer;
|
|
mrow -= top;
|
|
mcol -= left;
|
|
|
|
if(useCieLab) {
|
|
/* Convert to CIELab and differentiate in all directions: */
|
|
// Original dcraw algorithm uses CIELab as perceptual space
|
|
// (presumably coming from original AHD) and converts taking
|
|
// camera matrix into account. We use this in RT.
|
|
for (d=0; d < ndir; d++) {
|
|
float *l = &lab[0][0][0];
|
|
float *a = &lab[1][0][0];
|
|
float *b = &lab[2][0][0];
|
|
cielab(&rgb[d][4][4],l,a,b,TS,mrow-8,TS-8,xyz_cam);
|
|
int f = dir[d & 3];
|
|
f = f == 1 ? 1 : f-8;
|
|
for (int row=5; row < mrow-5; row++)
|
|
for (int col=5; col < mcol-5; col++) {
|
|
float *l = &lab[0][row-4][col-4];
|
|
float *a = &lab[1][row-4][col-4];
|
|
float *b = &lab[2][row-4][col-4];
|
|
|
|
g = 2*l[0] - l[f] - l[-f];
|
|
drv[d][row-5][col-5] = SQR(g)
|
|
+ SQR((2*a[0] - a[f] - a[-f] + g*2.1551724f))
|
|
+ SQR((2*b[0] - b[f] - b[-f] - g*0.86206896f));
|
|
}
|
|
|
|
}
|
|
} else {
|
|
// Now use YPbPr which requires much
|
|
// less code and is nearly indistinguishable. It assumes the
|
|
// camera RGB is roughly linear.
|
|
//
|
|
for (d=0; d < ndir; d++) {
|
|
float (*yuv)[TS-8][TS-8] = lab; // we use the lab buffer, which has the same dimensions
|
|
for (int row=4; row < mrow-4; row++)
|
|
for (int col=4; col < mcol-4; col++) {
|
|
// use ITU-R BT.2020 YPbPr, which is great, but could use
|
|
// a better/simpler choice? note that imageop.h provides
|
|
// dt_iop_RGB_to_YCbCr which uses Rec. 601 conversion,
|
|
// which appears less good with specular highlights
|
|
float y = 0.2627f * rgb[d][row][col][0] + 0.6780f * rgb[d][row][col][1] + 0.0593f * rgb[d][row][col][2];
|
|
yuv[0][row-4][col-4] = y;
|
|
yuv[1][row-4][col-4] = (rgb[d][row][col][2]-y)*0.56433f;
|
|
yuv[2][row-4][col-4] = (rgb[d][row][col][0]-y)*0.67815f;
|
|
}
|
|
int f=dir[d & 3];
|
|
f = f == 1 ? 1 : f-8;
|
|
for (int row=5; row < mrow-5; row++)
|
|
for (int col=5; col < mcol-5; col++) {
|
|
float *y = &yuv[0][row-4][col-4];
|
|
float *u = &yuv[1][row-4][col-4];
|
|
float *v = &yuv[2][row-4][col-4];
|
|
drv[d][row-5][col-5] = SQR(2*y[0] - y[f] - y[-f])
|
|
+ SQR(2*u[0] - u[f] - u[-f])
|
|
+ SQR(2*v[0] - v[f] - v[-f]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Build homogeneity maps from the derivatives: */
|
|
memset(homo, 0, ndir*TS*TS*sizeof(uint8_t));
|
|
for (int row=6; row < mrow-6; row++)
|
|
for (int col=6; col < mcol-6; col++) {
|
|
for (tr=FLT_MAX, d=0; d < ndir; d++)
|
|
tr = (drv[d][row-5][col-5] < tr ? drv[d][row-5][col-5] : tr);
|
|
tr *= 8;
|
|
for (d=0; d < ndir; d++)
|
|
for (v=-1; v <= 1; v++)
|
|
for (h=-1; h <= 1; h++)
|
|
homo[d][row][col] += (drv[d][row+v-5][col+h-5] <= tr ? 1:0) ;
|
|
}
|
|
|
|
if (height-top < TS+4)
|
|
mrow = height-top+2;
|
|
if (width-left < TS+4)
|
|
mcol = width-left+2;
|
|
|
|
|
|
/* Build 5x5 sum of homogeneity maps */
|
|
for(d=0;d<ndir;d++) {
|
|
for (int row = MIN(top,8); row < mrow-8; row++) {
|
|
int v5sum[5] = {0};
|
|
const int startcol = MIN(left,8);
|
|
for(v=-2;v<=2;v++)
|
|
for(h=-2;h<=2;h++)
|
|
v5sum[2+h] += homo[d][row+v][startcol+h];
|
|
int blocksum = v5sum[0] + v5sum[1] + v5sum[2] + v5sum[3] + v5sum[4];
|
|
homosum[d][row][startcol] = blocksum;
|
|
int voffset = -1;
|
|
// now we can subtract a column of five from blocksum and get new colsum of 5
|
|
for (int col = startcol+1; col < mcol-8; col++) {
|
|
int colsum = homo[d][row-2][col+2];
|
|
for(v=-1;v<=2;v++)
|
|
colsum += homo[d][row+v][col+2];
|
|
voffset ++;
|
|
voffset = voffset == 5 ? 0 : voffset; // faster than voffset %= 5;
|
|
blocksum -= v5sum[voffset];
|
|
blocksum += colsum;
|
|
v5sum[voffset] = colsum;
|
|
homosum[d][row][col] = blocksum;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Average the most homogenous pixels for the final result: */
|
|
for (int row = MIN(top,8); row < mrow-8; row++)
|
|
for (int col = MIN(left,8); col < mcol-8; col++) {
|
|
uint8_t hm[8];
|
|
uint8_t maxval = 0;
|
|
for (d=0; d < 4; d++) {
|
|
hm[d] = homosum[d][row][col];
|
|
maxval = (maxval < hm[d] ? hm[d] : maxval);
|
|
}
|
|
for (; d < ndir; d++) {
|
|
hm[d] = homosum[d][row][col];
|
|
maxval = (maxval < hm[d] ? hm[d] : maxval);
|
|
if (hm[d-4] < hm[d])
|
|
hm[d-4] = 0;
|
|
else if (hm[d-4] > hm[d])
|
|
hm[d] = 0;
|
|
}
|
|
maxval -= maxval >> 3;
|
|
float avg[4] = {0.f};
|
|
for (d=0; d < ndir; d++)
|
|
if (hm[d] >= maxval) {
|
|
FORC3 avg[c] += rgb[d][row][col][c];
|
|
avg[3]++;
|
|
}
|
|
|
|
red[row+top][col+left] = (avg[0]/avg[3]);
|
|
green[row+top][col+left] = (avg[1]/avg[3]);
|
|
blue[row+top][col+left] = (avg[2]/avg[3]);
|
|
}
|
|
|
|
if(plistenerActive && ((++progressCounter) % 32 == 0)) {
|
|
#ifdef _OPENMP
|
|
#pragma omp critical (xtransdemosaic)
|
|
#endif
|
|
{
|
|
progress += progressInc;
|
|
progress = min(1.0,progress);
|
|
plistener->setProgress (progress);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
free(buffer);
|
|
}
|
|
|
|
}
|
|
|
|
#undef TS
|
|
|
|
void RawImageSource::fast_xtrans_interpolate ()
|
|
{
|
|
if (settings->verbose)
|
|
printf("fast X-Trans interpolation...\n");
|
|
|
|
double progress = 0.0;
|
|
const bool plistenerActive = plistener;
|
|
|
|
if (plistenerActive) {
|
|
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "fast Xtrans"));
|
|
plistener->setProgress (progress);
|
|
}
|
|
|
|
const int height = H, width = W;
|
|
|
|
xtransborder_interpolate (1);
|
|
char xtrans[6][6];
|
|
ri->getXtransMatrix(xtrans);
|
|
|
|
#pragma omp parallel for
|
|
for(int row=1;row<height-1;row++) {
|
|
for(int col=1;col<width-1;col++) {
|
|
float sum[3] = {0.f};
|
|
for(int v=-1;v<=1;v++) {
|
|
for(int h=-1;h<=1;h++) {
|
|
sum[fcol(row+v,col+h)] += rawData[row+v][(col+h)];
|
|
}
|
|
}
|
|
switch(fcol(row,col)) {
|
|
case 0: red[row][col] = rawData[row][col];
|
|
green[row][col] = sum[1] *0.2f;
|
|
blue[row][col] = sum[2] *0.33333333f;
|
|
break;
|
|
case 1: red[row][col] = sum[0] * 0.5f;
|
|
green[row][col] = rawData[row][col];
|
|
blue[row][col] = sum[2] * 0.5f;
|
|
break;
|
|
case 2: red[row][col] = sum[0] * 0.33333333f;
|
|
green[row][col] = sum[1] *0.2f;
|
|
blue[row][col] = rawData[row][col];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plistenerActive) {
|
|
plistener->setProgress (1.0);
|
|
}
|
|
}
|
|
#undef fcol
|
|
|
|
|
|
|
|
#undef TILEBORDER
|
|
#undef TILESIZE
|
|
#undef CACHESIZE
|
|
} /* namespace */
|