rawTherapee/rtengine/hlrecovery.cc

398 lines
13 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/>.
*/
namespace rtengine
{
template<class T> T** allocArray (int W, int H)
{
T** t = new T*[H];
for (int i = 0; i < H; i++) {
t[i] = new T[W];
}
return t;
}
void RawImageSource::updateHLRecoveryMap (bool needred, bool needgreen, bool needblue, bool full)
{
// detect maximal pixel values
unsigned short* red = new unsigned short[W];
unsigned short* blue = new unsigned short[W];
int maxr = 0, maxg = 0, maxb = 0;
for (int i = 32; i < H - 32; i++) {
interpolate_row_rb (red, blue, green[i - 1], green[i], green[i + 1], i);
for (int j = 32; j < W - 32; j++) {
if (red[j] > maxr) {
maxr = red[j];
}
if (green[i][j] > maxg) {
maxg = green[i][j];
}
if (blue[j] > maxb) {
maxb = blue[j];
}
}
}
delete [] red;
delete [] blue;
maxr = maxr * 19 / 20;
maxg = maxg * 19 / 20;
maxb = maxb * 19 / 20;
int max[3];
max[0] = maxr;
max[1] = maxg;
max[2] = maxb;
if( options.rtSettings.verbose ) {
printf ("HLRecoveryMap Maximum: R: %d, G: %d, B: %d\n", maxr, maxg, maxb);
}
// downscale image
int dw = W / SCALE;
int dh = H / SCALE;
Image16* ds = new Image16 (dw, dh);
// overburnt areas
int** rec[3];
for (int i = 0; i < 3; i++) {
rec[i] = allocArray<int> (dw, dh);
}
unsigned short* reds[SCALE];
unsigned short* blues[SCALE];
for (int i = 0; i < SCALE; i++) {
reds[i] = new unsigned short[W];
blues[i] = new unsigned short[W];
}
for (int i = 0; i < dh; i++) {
for (int j = 0; j < SCALE; j++) {
interpolate_row_rb (reds[j], blues[j], green[SCALE * i + j - 1], green[SCALE * i + j], green[SCALE * i + j + 1], SCALE * i + j);
}
for (int j = 0; j < dw; j++) {
int sumr = 0;
int cr = 0;
int sumg = 0;
int cg = 0;
int sumb = 0;
int cb = 0;
for (int x = 0; x < SCALE; x++)
for (int y = 0; y < SCALE; y++) {
int ix = SCALE * i + x;
int jy = SCALE * j + y;
sumr += reds[x][jy];
if (reds[x][jy] < maxr) {
cr++;
}
sumg += green[ix][jy];
if (green[ix][jy] < maxg) {
cg++;
}
sumb += blues[x][jy];
if (blues[x][jy] < maxb) {
cb++;
}
}
if (cr < SCALE * SCALE && needred) {
rec[0][i][j] = INT_MAX;
} else {
rec[0][i][j] = sumr / SCALE / SCALE;
}
if (cg < SCALE * SCALE && needgreen) {
rec[1][i][j] = INT_MAX;
} else {
rec[1][i][j] = sumg / SCALE / SCALE;
}
if (cb < SCALE * SCALE && needblue) {
rec[2][i][j] = INT_MAX;
} else {
rec[2][i][j] = sumb / SCALE / SCALE;
}
ds->r(i, j) = sumr / SCALE / SCALE;
ds->g(i, j) = sumg / SCALE / SCALE;
ds->b(i, j) = sumb / SCALE / SCALE;
}
}
for (int i = 0; i < SCALE; i++) {
delete [] reds[i];
delete [] blues[i];
}
// STEP I. recover color from the partially lost areas
bool phase2 = false;
for (int k = 0; k < 400; k++) {
if (k > 200) {
phase2 = true;
}
for (int i = 1; i < dh - 1; i++)
for (int j = 1; j < dw - 1; j++) {
for (int c = 0; c < 3; c++) {
// if channel c is lost
if (rec[c][i][j] == INT_MAX) {
double ratio[2] = {0.0, 0.0};
double w[2] = {0.0, 0.0};
int count[2] = {0, 0};
int ix = 0;
for (int m = 0; m < 3; m++) {
if (m == c) {
continue;
}
// if channel m is not lost at this point (or already recovered)
if (rec[m][i][j] != INT_MAX && rec[m][i][j] >= 0) {
for (int x = -1; x <= 1; x++)
for (int y = -1; y <= 1; y++)
// average m/c color ratios in the surrounding pixels
if (rec[m][i + x][j + y] >= 0 && rec[m][i + x][j + y] != INT_MAX && rec[c][i + x][j + y] > 0 && rec[c][i + x][j + y] != INT_MAX) {
double ww = 1.0;
if (!phase2 && (/*(double)(rec[m][i+x][j+y] - rec[m][i][j])/max[m]*(rec[m][i+x][j+y] - rec[m][i][j])/max[m] > 1.0/2 || */rec[c][i + x][j + y] < max[c] * 3 / 4)) {
continue;
}
w[ix] += ww;
ratio[ix] += ww * rec[m][i + x][j + y] / rec[c][i + x][j + y];
count[ix] ++;
}
}
ix++;
}
// compute new pixel values from the surrounding color ratios
double newc = 0.0;
int nc = 0;
ix = 0;
for (int m = 0; m < 3; m++) {
if (c == m) {
continue;
}
if (count[ix]) {
newc += (double)rec[m][i][j] / ratio[ix] * w[ix];
nc++;
}
ix++;
}
if (nc) {
rec[c][i][j] = - (int) (newc / nc);
}
}
}
}
bool change = false;
for (int i = 0; i < dh; i++)
for (int j = 0; j < dw; j++)
for (int c = 0; c < 3; c++) {
if (rec[c][i][j] < 0) {
rec[c][i][j] = -rec[c][i][j];
}
change = true;
}
if (!change) {
break;
}
}
printf ("Phase1 vege\n");
// STEP II. recover fully lost pixels
if (full) {
int maxY = (299 * max[0] + 587 * max[1] + 114 * max[2]) / 1000;
phase2 = false;
for (int k = 0; k < 600; k++) {
if (k > 200) {
phase2 = true;
}
for (int i = 1; i < dh - 1; i++)
for (int j = 1; j < dw - 1; j++) {
if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) {
int count = 0;
double yavg = 0, iavg = 0, qavg = 0, weight = 0.0;
for (int x = -1; x <= 1; x++)
for (int y = -1; y <= 1; y++)
if (rec[0][i + x][j + y] > 0 && rec[0][i + x][j + y] != INT_MAX && rec[1][i + x][j + y] > 0 && rec[1][i + x][j + y] != INT_MAX && rec[2][i + x][j + y] > 0 && rec[2][i + x][j + y] != INT_MAX) {
// convert to yiq
double Y = 0.299 * rec[0][i + x][j + y] + 0.587 * rec[1][i + x][j + y] + 0.114 * rec[2][i + x][j + y];
double I = 0.596 * rec[0][i + x][j + y] - 0.275 * rec[1][i + x][j + y] - 0.321 * rec[2][i + x][j + y];
double Q = 0.212 * rec[0][i + x][j + y] - 0.523 * rec[1][i + x][j + y] + 0.311 * rec[2][i + x][j + y];
if (Y > maxY * 7 / 10) {
double w = 1.0;// / (I*I+Q*Q);
yavg += Y * w;
iavg += I * w;
qavg += Q * w;
weight += w;
count++;
}
}
if ((!phase2 && count > 5) || (phase2 && count > 3)) {
double Y = yavg / weight;
double I = iavg / weight;
double Q = qavg / weight;
rec[0][i][j] = - (Y + 0.956 * I + 0.621 * Q);
rec[1][i][j] = - (Y - 0.272 * I - 0.647 * Q);
rec[2][i][j] = - (Y - 1.105 * I + 1.702 * Q);
}
}
}
bool change = false;
for (int i = 0; i < dh; i++)
for (int j = 0; j < dw; j++)
for (int c = 0; c < 3; c++) {
if (rec[c][i][j] < 0) {
rec[c][i][j] = -rec[c][i][j];
}
change = true;
}
if (!change) {
break;
}
}
}
int maxval = 0;
for (int i = 0; i < dh; i++)
for (int j = 0; j < dw; j++)
for (int c = 0; c < 3; c++)
if (rec[c][i][j] != INT_MAX && rec[c][i][j] > maxval) {
maxval = rec[c][i][j];
}
for (int i = 0; i < dh; i++)
for (int j = 0; j < dw; j++)
if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) {
rec[0][i][j] = maxval;
rec[1][i][j] = maxval;
rec[2][i][j] = maxval;
}
if (hrmap[0] != NULL) {
freeArray<float> (hrmap[0], dh);
freeArray<float> (hrmap[1], dh);
freeArray<float> (hrmap[2], dh);
}
hrmap[0] = allocArray<float> (dw, dh);
hrmap[1] = allocArray<float> (dw, dh);
hrmap[2] = allocArray<float> (dw, dh);
this->full = full;
for (int i = 0; i < dh; i++)
for (int j = 0; j < dw; j++) {
hrmap[0][i][j] = (double)rec[0][i][j] / ds->r(i, j);
hrmap[1][i][j] = (double)rec[1][i][j] / ds->g(i, j);
hrmap[2][i][j] = (double)rec[2][i][j] / ds->b(i, j);
}
/* for (int i=0; i<dh; i++)
for (int j=0; j<dh; j++) {
ds->r(i,j) = CLIP (rec[0][i][j]);
ds->g(i,j) = CLIP (rec[1][i][j]);
ds->b(i,j) = CLIP (rec[2][i][j]);
}
ds->save ("test.png");
*/
delete ds;
freeArray<int> (rec[0], dh);
freeArray<int> (rec[1], dh);
freeArray<int> (rec[2], dh);
printf ("HLMap vege\n");
}
void RawImageSource::hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int sx2, int skip)
{
int blr = (i + SCALE / 2) / SCALE - 1;
if (blr < 0 || blr >= H / SCALE - 1) {
return;
}
double mr1 = 1.0 - ((double)((i + SCALE / 2) % SCALE) / SCALE + 0.5 / SCALE);
int jx = 0;
int maxcol = W / SCALE;
for (int j = sx1, jx = 0; j < sx2; j += skip, jx++) {
int blc = (j + SCALE / 2) / SCALE - 1;
if (blc < 0 || blc >= maxcol - 1) {
continue;
}
double mc1 = 1.0 - ((double)((j + SCALE / 2) % SCALE) / SCALE + 0.5 / SCALE);
double mulr = mr1 * mc1 * hrmap[0][blr][blc] + mr1 * (1.0 - mc1) * hrmap[0][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[0][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[0][blr + 1][blc + 1];
double mulg = mr1 * mc1 * hrmap[1][blr][blc] + mr1 * (1.0 - mc1) * hrmap[1][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[1][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[1][blr + 1][blc + 1];
double mulb = mr1 * mc1 * hrmap[2][blr][blc] + mr1 * (1.0 - mc1) * hrmap[2][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[2][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[2][blr + 1][blc + 1];
red[jx] = CLIP(red[jx] * mulr);
green[jx] = CLIP(green[jx] * mulg);
blue[jx] = CLIP(blue[jx] * mulb);
}
}
}