Pixelshift: Added per channel brightness equalization

This commit is contained in:
heckflosse
2017-04-10 20:39:00 +02:00
parent 14f544fcc2
commit e043e792db
10 changed files with 134 additions and 34 deletions

View File

@@ -304,6 +304,29 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D<uint8_t> &ma
}
}
void calcFrameBrightnessFactor(unsigned int frame, uint32_t datalen, LUT<uint32_t> *histo[4], float brightnessFactor[4])
{
float medians[4];
for(int i = 0; i < 4; ++i) {
//find median of histogram
uint32_t median = 0, count = 0;
while (count < datalen / 2) {
count += (*histo[i])[median];
++median;
}
const float weight = (count - datalen / 2.f) / (*histo[i])[median - 1];
medians[i] = rtengine::intp(weight, (float)(median - 2), (float)(median - 1));
}
for(int i = 0; i < 4; ++i) {
brightnessFactor[i] = medians[frame] / medians[i];
}
}
}
using namespace std;
@@ -372,7 +395,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
multi_array2D<float,3> redTmp(W,H);
multi_array2D<float,3> greenTmp(W,H);
multi_array2D<float,3> blueTmp(W,H);
for(int i=0, frameIndex = 0;i<4;++i) {
for(unsigned int i=0, frameIndex = 0;i<4;++i) {
if(i != currFrame) {
if(bayerParams.pixelShiftLmmse) {
lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex], bayerParams.lmmse_iterations);
@@ -487,12 +510,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
const bool checkNonGreenCross2 = bayerParams.pixelShiftNonGreenCross2;
const float threshold = bayerParams.pixelShiftSum + 9.f;
const bool experimental0 = bayerParams.pixelShiftExp0;
const bool automatic = bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Automatic;
#else
constexpr float threshold = 3.f + 9.f;
#endif
const bool holeFill = bayerParams.pixelShiftHoleFill;
const bool equalBrightness = bayerParams.pixelShiftEqualBright;
const bool equalChannel = bayerParams.pixelShiftEqualBrightChannel;
const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmoothFactor > 0. && !showOnlyMask;
const float smoothFactor = 1.0 - bayerParams.pixelShiftSmoothFactor;
@@ -741,24 +764,38 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
// calculate average green brightness for each frame
float greenBrightness[4] = {1.f, 1.f, 1.f, 1.f};
float redBrightness[4] = {1.f, 1.f, 1.f, 1.f};
float blueBrightness[4] = {1.f, 1.f, 1.f, 1.f};
if(equalBrightness) {
LUT<uint32_t> *histo[4];
LUT<uint32_t> *histogreen[4];
LUT<uint32_t> *histored[4];
LUT<uint32_t> *histoblue[4];
for(int i = 0; i < 4; ++i) {
histo[i] = new LUT<uint32_t>(65536);
histo[i]->clear();
histogreen[i] = new LUT<uint32_t>(65536);
histogreen[i]->clear();
histored[i] = new LUT<uint32_t>(65536);
histored[i]->clear();
histoblue[i] = new LUT<uint32_t>(65536);
histoblue[i]->clear();
}
#ifdef _OPENMP
#pragma omp parallel
#endif
{
LUT<uint32_t> *histoThr[4];
LUT<uint32_t> *histogreenThr[4];
LUT<uint32_t> *historedThr[4];
LUT<uint32_t> *histoblueThr[4];
for(int i = 0; i < 4; ++i) {
histoThr[i] = new LUT<uint32_t>(65536);
histoThr[i]->clear();
histogreenThr[i] = new LUT<uint32_t>(65536);
histogreenThr[i]->clear();
historedThr[i] = new LUT<uint32_t>(65536);
historedThr[i]->clear();
histoblueThr[i] = new LUT<uint32_t>(65536);
histoblueThr[i]->clear();
}
#ifdef _OPENMP
@@ -766,44 +803,51 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
#endif
for(int i = winy + 1; i < winh - 1; ++i) {
int j = winx + 1;
int c = FC(i, j);
bool bluerow = (c + FC(i, j + 1)) == 3;
for(int j = winx + 1, offset = FC(i, j) & 1; j < winw - 1; ++j, offset ^= 1) {
(*histoThr[1 - offset])[(*rawDataFrames[1 - offset])[i - offset + 1][j]]++;
(*histoThr[3 - offset])[(*rawDataFrames[3 - offset])[i + offset][j + 1]]++;
(*histogreenThr[1 - offset])[(*rawDataFrames[1 - offset])[i - offset + 1][j]]++;
(*histogreenThr[3 - offset])[(*rawDataFrames[3 - offset])[i + offset][j + 1]]++;
if(bluerow) {
(*historedThr[2 - offset])[(*rawDataFrames[2 - offset])[i + 1][j - offset + 1]]++;
(*histoblueThr[(offset << 1) + offset])[(*rawDataFrames[(offset << 1) + offset])[i][j + offset]]++;
} else {
(*historedThr[(offset << 1) + offset])[(*rawDataFrames[(offset << 1) + offset])[i][j + offset]]++;
(*histoblueThr[2 - offset])[(*rawDataFrames[2 - offset])[i + 1][j - offset + 1]]++;
}
}
}
#pragma omp critical
{
for(int i = 0; i < 4; ++i) {
(*histo[i]) += (*histoThr[i]);
delete histoThr[i];
(*histogreen[i]) += (*histogreenThr[i]);
delete histogreenThr[i];
(*histored[i]) += (*historedThr[i]);
delete historedThr[i];
(*histoblue[i]) += (*histoblueThr[i]);
delete histoblueThr[i];
}
}
}
float medians[4];
calcFrameBrightnessFactor(frame, (winh - 2) * (winw - 2) / 4, histored, redBrightness);
calcFrameBrightnessFactor(frame, (winh - 2) * (winw - 2) / 4, histoblue, blueBrightness);
calcFrameBrightnessFactor(frame, (winh - 2) * (winw - 2) / 2, histogreen, greenBrightness);
for(int i = 0; i < 4; ++i) {
//find median of histogram
uint32_t median = 0, count = 0;
uint32_t datalen = (winh - 2) * (winw - 2) / 2;
while (count < datalen / 2) {
count += (*histo[i])[median];
++median;
}
const float weight = (count - datalen / 2.f) / (*histo[i])[median - 1];
medians[i] = intp(weight, (float)(median - 2), (float)(median - 1));
delete histo[i];
}
for(int i = 0; i < 4; ++i) {
greenBrightness[i] = medians[frame] / medians[i];
delete histored[i];
delete histoblue[i];
delete histogreen[i];
}
#ifdef PIXELSHIFTDEV
std::cout << "brightness factors by median : " << greenBrightness[0] << " " << greenBrightness[1] << " " << greenBrightness[2] << " " << greenBrightness[3] << std::endl;
std::cout << "blue brightness factors by median : " << blueBrightness[0] << " " << blueBrightness[1] << " " << blueBrightness[2] << " " << blueBrightness[3] << std::endl;
std::cout << "red brightness factors by median : " << redBrightness[0] << " " << redBrightness[1] << " " << redBrightness[2] << " " << redBrightness[3] << std::endl;
std::cout << "green brightness factors by median : " << greenBrightness[0] << " " << greenBrightness[1] << " " << greenBrightness[2] << " " << greenBrightness[3] << std::endl;
#endif
}
@@ -814,6 +858,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
array2D<float> psG2(winw + 32, winh);
array2D<float> psBlue(winw + 32, winh);
if(!equalChannel) {
for(int i = 0; i < 4; ++i ) {
redBrightness[i] = blueBrightness[i] = greenBrightness[i];
}
}
// fill channels psRed, psG1, psG2 and psBlue
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16)
@@ -824,6 +874,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
float *greenDest2 = psG2[i];
float *nonGreenDest0 = psRed[i];
float *nonGreenDest1 = psBlue[i];
float ngbright[2][4] = {{redBrightness[0],redBrightness[1],redBrightness[2],redBrightness[3]},
{blueBrightness[0],blueBrightness[1],blueBrightness[2],blueBrightness[3]}
};
int ng = 0;
int j = winx + 1;
int c = FC(i, j);
@@ -831,6 +885,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
// row with blue pixels => swap destination pointers for non green pixels
std::swap(nonGreenDest0, nonGreenDest1);
std::swap(greenDest1, greenDest2);
ng ^= 1;
}
// offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop
@@ -840,8 +895,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA
// store the values from the 4 frames into 4 different temporary planes
greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset];
greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset];
nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * greenBrightness[(offset << 1) + offset];
nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * greenBrightness[2 - offset];
nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * ngbright[ng][(offset << 1) + offset];
nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * ngbright[ng^1][2 - offset];
offset ^= 1; // 0 => 1 or 1 => 0
}
}