Pixelshift: Added per channel brightness equalization
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user