/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * 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 . */ #include #include #include "rawimagesource.h" #include "rawimage.h" #include "rt_math.h" #include "color.h" #include "../rtgui/multilangmgr.h" #include "opthelper.h" #include "median.h" //#define BENCHMARK #include "StopWatch.h" #ifdef _OPENMP #include #endif using namespace std; namespace rtengine { #undef fc #define fc(row,col) \ (ri->get_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) #define FORCC for (unsigned int c=0; c < colors; c++) void RawImageSource::border_interpolate( int winw, int winh, int lborders, const array2D &rawData, array2D &red, array2D &green, array2D &blue) { 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 } } /*** * * 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 for more information. * ***/ // Adapted to RawTherapee by Jacques Desmis 3/2013 // SSE version by Ingo Weyrich 5/2013 #ifdef __SSE2__ 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(static_cast(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; if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_IGV"))); plistener->setProgress (0.0); } #ifdef _OPENMP #pragma omp parallel 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 = vmaxf(temp1v, ZEROV); temp2v = LVFU( rawData[row][col + 4] ); temp2v = vmaxf(temp2v, ZEROV); 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] = std::max(0.f, rawData[row][col]); //rawData = RT data col++; if(col < width) dest2[indx >> 1] = std::max(0.f, rawData[row][col]); //rawData = RT data } } #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 = vclampf(((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 = vclampf(((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 = vclampf(((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 = vclampf(((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 = vclampf(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 = vclampf(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 = median(d725v * LVFU(vdif[indx1]) + d1375v * LVFU(vdif[indx1 - v1]) + d1375v * LVFU(vdif[indx1 + v1]), LVFU(vdif[indx1 - v1]), LVFU(vdif[indx1 + v1])); evv = median(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 = median(0.725f * vdif[indx1] + 0.1375f * vdif[indx1 - v1] + 0.1375f * vdif[indx1 + v1], vdif[indx1 - v1], vdif[indx1 + v1]); ev = median(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 = median(LVFU(chr[c][(indx - v1 - h1) >> 1]), LVFU(chr[c][(indx - v3 - h1) >> 1]), LVFU(chr[c][(indx - v1 - h3) >> 1])); nevv = median(LVFU(chr[c][(indx - v1 + h1) >> 1]), LVFU(chr[c][(indx - v3 + h1) >> 1]), LVFU(chr[c][(indx - v1 + h3) >> 1])); swvv = median(LVFU(chr[c][(indx + v1 - h1) >> 1]), LVFU(chr[c][(indx + v3 - h1) >> 1]), LVFU(chr[c][(indx + v1 - h3) >> 1])); sevv = median(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 = median(chr[c][(indx - v1 - h1) >> 1], chr[c][(indx - v3 - h1) >> 1], chr[c][(indx - v1 - h3) >> 1]); nev = median(chr[c][(indx - v1 + h1) >> 1], chr[c][(indx - v3 + h1) >> 1], chr[c][(indx - v1 + h3) >> 1]); swv = median(chr[c][(indx + v1 - h1) >> 1], chr[c][(indx + v3 - h1) >> 1], chr[c][(indx + v1 - h3) >> 1]); sev = median(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], vmaxf(tempv, ZEROV)); 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 = vmaxf(tempv - c65535v * temp3v, ZEROV); _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 = vmaxf(tempv - c65535v * temp4v, ZEROV); _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], vmaxf(tempv, ZEROV)); 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 = vmaxf(tempv - c65535v * temp3v, ZEROV); _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 = vmaxf(tempv - c65535v * temp4v, ZEROV); _mm_storeu_ps( &blue[row][col + 4], temp4v); } for(; col < width - 7; col++, indx += 2) { red [row][col] = std::max(0.f, src1[indx >> 1] - 65535.f * redsrc0[indx >> 1]); green[row][col] = std::max(0.f, src1[indx >> 1]); blue [row][col] = std::max(0.f, src1[indx >> 1] - 65535.f * bluesrc0[indx >> 1]); col++; red [row][col] = std::max(0.f, src2[(indx + 1) >> 1] - 65535.f * redsrc1[(indx + 1) >> 1]); green[row][col] = std::max(0.f, src2[(indx + 1) >> 1]); blue [row][col] = std::max(0.f, src2[(indx + 1) >> 1] - 65535.f * bluesrc1[(indx + 1) >> 1]); } } }// End of parallelization border_interpolate(winw, winh, 8, rawData, red, green, blue); if (plistener) { plistener->setProgress (1.0); } free(chrarray); free(rgbarray); free(vdif); free(hdif); } #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); if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_IGV"))); plistener->setProgress (0.0); } #ifdef _OPENMP #pragma omp parallel 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] = std::max(0.f, rawData[row][col]); //rawData = RT data } #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 = median(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 = median(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 = median(chr[c][indx - v1 - h1], chr[c][indx - v3 - h1], chr[c][indx - v1 - h3]); nev = median(chr[c][indx - v1 + h1], chr[c][indx - v3 + h1], chr[c][indx - v1 + h3]); swv = median(chr[c][indx + v1 - h1], chr[c][indx + v3 - h1], chr[c][indx + v1 - h3]); sev = median(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 = median(chr[c][indx - v1 - h1], chr[c][indx - v3 - h1], chr[c][indx - v1 - h3]); nev = median(chr[c][indx - v1 + h1], chr[c][indx - v3 + h1], chr[c][indx - v1 + h3]); swv = median(chr[c][indx + v1 - h1], chr[c][indx + v3 - h1], chr[c][indx + v1 - h3]); sev = median(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); } } /* #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] = std::max(0.f, rgb[1][indx] - 65535.f * chr[0][indx]); green[row][col] = std::max(0.f, rgb[1][indx]); blue [row][col] = std::max(0.f, rgb[1][indx] - 65535.f * chr[1][indx]); } }// End of parallelization border_interpolate(winw, winh, 8, rawData, red, green, blue); if (plistener) { plistener->setProgress (1.0); } free(chrarray); free(rgbarray); free(vdif); free(hdif); } #endif void RawImageSource::nodemosaic(bool bw) { red(W, H); green(W, H); blue(W, H); #ifdef _OPENMP #pragma omp parallel for #endif 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; } } } } } /* * 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 192 #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 )[3], 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 )[3], int border, int x0, int y0) { unsigned f; float sum[8]; constexpr unsigned int colors = 3; // used in FORCC for (int row = y0; row < y0 + TILESIZE + TILEBORDER && row < H; row++) { for (int 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 (int y = row - 1; y != row + 2; y++) for (int 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 // change buffer[3] -> buffer[2], possibly to buffer[1] if split // into two loops, one for R and another for B, could also be smaller because // there is no need for green pixels pass // this would decrease the amount of needed memory // from megapixels*2 records to megapixels*0.5 // also don't know if float is needed as data is 1-65536 integer (I believe!!) // comment from Ingo: float is needed because rawdata in rt is float void RawImageSource::copy_to_buffer( float (*buffer)[2], float (*image)[3]) { for (int indx = 0; indx < CACHESIZE * CACHESIZE; indx++) { buffer[indx][0] = image[indx][0]; //R buffer[indx][1] = image[indx][2]; //B } } // restores red and blue // other comments like in copy_to_buffer void RawImageSource::restore_from_buffer(float (*image)[3], float (*buffer)[2]) { for (int indx = 0; indx < CACHESIZE * CACHESIZE; indx++) { image[indx][0] = buffer[indx][0]; //R image[indx][2] = buffer[indx][1]; //B } } // First pass green interpolation // remove entirely: bufferH and bufferV void RawImageSource::dcb_hid(float (*image)[3], int x0, int y0) { const int u = CACHESIZE; int rowMin, colMin, rowMax, colMax; dcb_initTileLimits(colMin, rowMin, colMax, rowMax, x0, y0, 2); // simple green bilinear in R and B 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 - 1 >= 0 && indx + u + 1 < u * u); image[indx][1] = 0.25f * (image[indx-1][1]+image[indx+1][1]+image[indx-u][1]+image[indx+u][1]); } } // missing colours are interpolated void RawImageSource::dcb_color(float (*image)[3], 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); //Jacek comment: one multiplication less image[indx][c] = image[indx][1] + ( image[indx + u + 1][c] + image[indx + u - 1][c] + image[indx - u + 1][c] + image[indx - u - 1][c] - (image[indx + u + 1][1] + image[indx + u - 1][1] + image[indx - u + 1][1] + image[indx - u - 1][1]) ) * 0.25f; /* original 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); //Jacek comment: two multiplications (in total) less image[indx][c] = image[indx][1] + (image[indx + 1][c] + image[indx - 1][c] - (image[indx + 1][1] + image[indx - 1][1])) * 0.5f; image[indx][d] = image[indx][1] + (image[indx + u][d] + image[indx - u][d] - (image[indx + u][1] + image[indx - u][1])) * 0.5f; /* original 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)[3], int x0, int y0) { const int 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 < CACHESIZE * CACHESIZE); //Jacek comment: one multiplication less image[indx][1] = image[indx][c] + (image[indx + v][1] + image[indx - v][1] + image[indx - 2][1] + image[indx + 2][1] - (image[indx + v][c] + image[indx - v][c] + image[indx - 2][c] + image[indx + 2][c])) * 0.25f; /* original 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] // seems at least 2 persons implemented some code, as this one has different coding style, could be unified // I don't know if *pix is faster than a loop working on image[] directly void RawImageSource::dcb_map(float (*image)[3], uint8_t *map, int x0, int y0) { const int u = 3 * 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); // comparing 4 * a to (b+c+d+e) instead of a to (b+c+d+e)/4 is faster because divisions are slow if ( 4 * (*pix) > ( (pix[-3] + pix[+3]) + (pix[-u] + pix[+u])) ) { map[indx] = ((min(pix[-3], pix[+3]) + (pix[-3] + pix[+3]) ) < (min(pix[-u], pix[+u]) + (pix[-u] + pix[+u]))); } else { map[indx] = ((max(pix[-3], pix[+3]) + (pix[-3] + pix[+3]) ) > (max(pix[-u], pix[+u]) + (pix[-u] + pix[+u]))); } } } } // interpolated green pixels are corrected using the map void RawImageSource::dcb_correction(float (*image)[3], uint8_t *map, 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 indx = row * CACHESIZE + colMin + (FC(y0 - TILEBORDER + row, x0 - TILEBORDER + colMin) & 1); indx < row * CACHESIZE + colMax; indx += 2) { // 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 * map[indx] + 2 * (map[indx + u] + map[indx - u] + map[indx + 1] + map[indx - 1]) + map[indx + v] + map[indx - v] + map[indx + 2] + map[indx - 2]; assert(indx >= 0 && indx < u * u); image[indx][1] = ((16.f - current) * (image[indx - 1][1] + image[indx + 1][1]) + current * (image[indx - u][1] + image[indx + u][1]) ) * 0.03125f; // 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 // again code with *pix, is this kind of calculating faster in C, than this what was commented? void RawImageSource::dcb_pp(float (*image)[3], 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++) { // float 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]; // float 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]; // float 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]; float (*pix)[3] = 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 += ( image[indx][1] - g1 ); 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)[3], uint8_t *map, 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 indx = row * CACHESIZE + colMin + (FC(y0 - TILEBORDER + row, x0 - TILEBORDER + colMin) & 1), c = FC(y0 - TILEBORDER + row, x0 - TILEBORDER + colMin + (FC(y0 - TILEBORDER + row, x0 - TILEBORDER + colMin) & 1)); indx < row * CACHESIZE + colMax; indx += 2) { // map values are uint8_t either 0 or 1. Adding them using integer instructions is perfectly valid and fast. Final result is converted to float then float current = 4 * map[indx] + 2 * (map[indx + u] + map[indx - u] + map[indx + 1] + map[indx - 1]) + map[indx + v] + map[indx - v] + map[indx + 2] + map[indx - 2]; assert(indx >= 0 && indx < u * u); // Jacek comment: works now, and has 3 float mults and 9 float adds image[indx][1] = image[indx][c] + ((16.f - current) * (image[indx - 1][1] + image[indx + 1][1] - (image[indx + 2][c] + image[indx - 2][c])) + current * (image[indx - u][1] + image[indx + u][1] - (image[indx + v][c] + image[indx - v][c]))) * 0.03125f; // 4 float mults and 9 float adds // Jacek comment: not mathematically identical to original /* image[indx][1] = 16.f * image[indx][c] + ((16.f - current) * ((image[indx - 1][1] + image[indx + 1][1]) - (image[indx + 2][c] + image[indx - 2][c])) + current * ((image[indx - u][1] + image[indx + u][1]) - (image[indx + v][c] + image[indx - v][c]))) * 0.03125f; */ // 7 float mults and 10 float adds // original code /* 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)[3], uint8_t *map, 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); float f0, f1, f2, g1, h0, h1, h2, 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 * map[indx] + 2 * (map[indx + u] + map[indx - u] + map[indx + 1] + map[indx - 1]) + map[indx + v] + map[indx - v] + map[indx - 2] + map[indx + 2]; float currPix = image[indx][c]; f0 = (float)(image[indx - u][1] + image[indx + u][1]) / (1.f + 2.f * currPix); f1 = 2.f * image[indx - u][1] / (1.f + image[indx - v][c] + currPix); f2 = 2.f * image[indx + u][1] / (1.f + image[indx + v][c] + currPix); g1 = f0 + f1 + f2; h0 = (float)(image[indx - 1][1] + image[indx + 1][1]) / (1.f + 2.f * currPix); h1 = 2.f * image[indx - 1][1] / (1.f + image[indx - 2][c] + currPix); h2 = 2.f * image[indx + 1][1] / (1.f + image[indx + 2][c] + currPix); g2 = h0 + h1 + h2; // new green value assert(indx >= 0 && indx < u * u); currPix *= (current * g1 + (16.f - current) * g2) / 48.f; // get rid of the overshot pixels float minVal = min(image[indx - 1][1], min(image[indx + 1][1], min(image[indx - u][1], image[indx + u][1]))); float maxVal = max(image[indx - 1][1], max(image[indx + 1][1], max(image[indx - u][1], image[indx + u][1]))); image[indx][1] = LIM(currPix, minVal, maxVal); } } // missing colours are interpolated using high quality algorithm by Luis Sanz Rodriguez void RawImageSource::dcb_color_full(float (*image)[3], 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] + 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] + 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] + 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] + chroma[indx + u + 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 / (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 / (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 / (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 / (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] = intp(0.875f, chroma[indx - u][c], chroma[indx - w][c]); g[1] = intp(0.875f, chroma[indx + 1][c], chroma[indx + 3][c]); g[2] = intp(0.875f, chroma[indx - 1][c], chroma[indx - 3][c]); g[3] = intp(0.875f, 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 void RawImageSource::dcb_demosaic(int iterations, bool dcb_enhance) { BENCHFUN double currentProgress = 0.0; if(plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_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; constexpr int cldf = 2; // factor to multiply cache line distance. 1 = 64 bytes, 2 = 128 bytes ... #ifdef _OPENMP #pragma omp parallel #endif { // assign working space char *buffer0 = (char *) malloc(5 * sizeof(float) * CACHESIZE * CACHESIZE + sizeof(uint8_t) * CACHESIZE * CACHESIZE + 3 * cldf * 64 + 63); // aligned to 64 byte boundary char *data = (char*)( ( uintptr_t(buffer0) + uintptr_t(63)) / 64 * 64); float (*tile)[3] = (float(*)[3]) data; float (*buffer)[2] = (float(*)[2]) ((char*)tile + sizeof(float) * CACHESIZE * CACHESIZE * 3 + cldf * 64); float (*chrm)[2] = (float(*)[2]) (buffer); // No overlap in usage of buffer and chrm means we can reuse buffer uint8_t *map = (uint8_t*) ((char*)buffer + sizeof(float) * CACHESIZE * CACHESIZE * 2 + cldf * 64); #ifdef _OPENMP #pragma omp for schedule(dynamic) nowait #endif for( int iTile = 0; iTile < numTiles; iTile++) { int xTile = iTile % wTiles; int yTile = iTile / wTiles; int x0 = xTile * TILESIZE; int y0 = yTile * TILESIZE; memset(tile, 0, CACHESIZE * CACHESIZE * sizeof * tile); memset(map, 0, CACHESIZE * CACHESIZE * sizeof * map); fill_raw( tile, x0, y0, rawData ); if( !xTile || !yTile || xTile == wTiles - 1 || yTile == hTiles - 1) { fill_border(tile, 6, x0, y0); } copy_to_buffer(buffer, tile); dcb_hid(tile, x0, y0); 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, map, x0, y0); dcb_correction(tile, map, x0, y0); } dcb_color(tile, x0, y0); dcb_pp(tile, x0, y0); dcb_map(tile, map, x0, y0); dcb_correction2(tile, map, x0, y0); dcb_map(tile, map, x0, y0); dcb_correction(tile, map, x0, y0); dcb_color(tile, x0, y0); dcb_map(tile, map, x0, y0); dcb_correction(tile, map, x0, y0); dcb_map(tile, map, x0, y0); dcb_correction(tile, map, x0, y0); dcb_map(tile, map, x0, y0); restore_from_buffer(tile, buffer); if (!dcb_enhance) dcb_color(tile, x0, y0); else { memset(chrm, 0, CACHESIZE * CACHESIZE * sizeof * chrm); dcb_refinement(tile, map, x0, y0); dcb_color_full(tile, x0, y0, chrm); } /* dcb_hid(tile, buffer, buffer2, x0, y0); dcb_color(tile, 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_full(tile, x0, y0, chrm); 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] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][0]); green[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][1]); blue[y0 + y][x0 + j] = std::max(0.f, 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++; } free(buffer0); } border_interpolate(W, H, 1, rawData, red, green, blue); if(plistener) { plistener->setProgress (1.0); } } #undef TILEBORDER #undef TILESIZE #undef CACHESIZE } /* namespace */