//////////////////////////////////////////////////////////////// // // pentax pixelshift algorithm with motion detection // // non adaptive mode is derived from dcrawps (https://github.com/tomtor/dcrawps), but with additional motion correction methods and adapted for RawTherapee data structures // // If motion correction is enabled only the pixels which are not detected as motion are set // That means for a complete image you have to demosaic one of the frames with a bayer demosaicer to fill red, green and blue // before calling pixelshift in case motion correction is enabled. // // copyright (c) Ingo Weyrich 2016 // // // pixelshift.cc 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. // // This program 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 this program. If not, see . // //////////////////////////////////////////////////////////////// #include #include "rawimagesource.h" #include "../rtgui/multilangmgr.h" #include "procparams.h" #define BENCHMARK #include "StopWatch.h" namespace { float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between two green samples if(adaptive) { float gDiff = a - b; gDiff *= eperIso; gDiff *= gDiff; float avg = (a + b) / 2.f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); float result = gDiff - stddev; if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask return std::fabs(a - b) / (std::max(a, b) + 0.01f); } else { return 0.f; } } else { float gDiff = std::fabs(a - b); // add a small epsilon to avoid division by zero float maxVal = std::max(a, b) + 0.01f; return gDiff / maxVal; } } float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between two nongreen samples float gDiff = a - b; gDiff *= eperIso; gDiff *= gDiff; float avg = (a + b) / 2.f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); float result = gDiff - stddev; if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask return std::fabs(a - b) / (std::max(a, b) + 0.01f); } else { return 0.f; } } float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // check non green cross float hDiff = (right + left) / 2.f - centre; hDiff *= eperIso; hDiff *= hDiff; float vDiff = (top + bottom) / 2.f - centre; vDiff *= eperIso; vDiff *= vDiff; float avg = (right + left + top + bottom) / 4.f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); float result = std::min(hDiff - stddev, vDiff - stddev); if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask return std::sqrt((result / (stddev + result + 0.01f))); } else { return 0.f; } } void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMask, float *maskDest, float *nonMaskDest0, float *nonMaskDest1) { if(showMotion) { if(!showOnlyMask) { // if showMotion is enabled colourize the pixel maskDest[index] = 1000.f + 25000.f * gridMax; nonMaskDest1[index] = nonMaskDest0[index] = 0.f; } else { maskDest[index] = nonMaskDest0[index] = nonMaskDest1[index] = 1000.f + 25000.f * gridMax; } } } } using namespace std; using namespace rtengine; void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) { BENCHFUN static const float nReadK3II[] = { 3.4f, // ISO 100 3.1f, // ISO 125 2.5f, // ISO 160 2.5f, // ISO 200 2.5f, // ISO 250 2.5f, // ISO 320 2.3f, // ISO 400 2.5f, // ISO 500 2.3f, // ISO 640 2.3f, // ISO 800 2.4f, // ISO 1000 2.3f, // ISO 1250 1.75f, // ISO 1600 1.75f, // ISO 2000 1.75f, // ISO 2500 1.75f, // ISO 3200 1.75f, // ISO 4000 1.75f, // ISO 5000 1.75f, // ISO 6400 1.75f, // ISO 8000 1.75f, // ISO 10000 1.5f, // ISO 12800 1.5f, // ISO 16000 1.5f, // ISO 20000 1.5f, // ISO 25600 1.5f, // ISO 32000 1.5f, // ISO 40000 1.5f, // ISO 51200 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) }; static const float ePerIsoK3II = 0.35f; static const float nReadK1[] = { 3.45f, // ISO 100 3.15f, // ISO 125 3.45f, // ISO 160 3.0f, // ISO 200 3.0f, // ISO 250 3.0f, // ISO 320 2.7f, // ISO 400 2.7f, // ISO 500 2.7f, // ISO 640 2.5f, // ISO 800 2.5f, // ISO 1000 2.5f, // ISO 1250 2.4f, // ISO 1600 2.4f, // ISO 2000 2.4f, // ISO 2500 2.4f, // ISO 3200 2.4f, // ISO 4000 2.4f, // ISO 5000 2.4f, // ISO 6400 2.4f, // ISO 8000 2.4f, // ISO 10000 2.4f, // ISO 12800 2.4f, // ISO 16000 2.4f, // ISO 20000 2.4f, // ISO 25600 2.4f, // ISO 32000 2.4f, // ISO 40000 2.4f, // ISO 51200 2.4f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) }; static const float ePerIsoK1 = 0.75f; static const float nReadK70[] = { 3.0f, // ISO 100 3.0f, // ISO 125 3.0f, // ISO 160 3.0f, // ISO 200 3.0f, // ISO 250 3.0f, // ISO 320 3.0f, // ISO 400 3.0f, // ISO 500 3.0f, // ISO 640 3.0f, // ISO 800 3.0f, // ISO 1000 3.0f, // ISO 1250 3.0f, // ISO 1600 3.0f, // ISO 2000 3.0f, // ISO 2500 3.0f, // ISO 3200 3.0f, // ISO 4000 3.0f, // ISO 5000 3.0f, // ISO 6400 3.0f, // ISO 8000 3.0f, // ISO 10000 3.0f, // ISO 12800 3.0f, // ISO 16000 3.0f, // ISO 20000 3.0f, // ISO 25600 3.0f, // ISO 32000 3.0f, // ISO 40000 3.0f, // ISO 51200 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) }; static const float ePerIsoK70 = 0.5f; if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); plistener->setProgress(0.0); } const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); int gridSize = 1; switch (gridSize_) { case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: gridSize = 1; break; case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3: gridSize = 3; break; case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: gridSize = 5; break; case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: gridSize = 7; } // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); if(detectMotion && !adaptive) { const float lutStrength = 2.f; log2Lut[0] = 0; for(int i = 2; i < 65536; i += 2) { log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; } } const float scaleGreen = 1.f / scale_mul[1]; float nRead; float eperIsoModel; int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); if(model.find("K-3") != string::npos) { nRead = nReadK3II[nReadIndex]; eperIsoModel = ePerIsoK3II; } else if(model.find("K-1") != string::npos) { nRead = nReadK1[nReadIndex]; eperIsoModel = ePerIsoK1; } else { nRead = nReadK70[nReadIndex]; eperIsoModel = ePerIsoK70; } nRead *= pow(2.f, nreadIso); eperIsoModel *= pow(2.f, eperIso); eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); prnu /= 100.f; stddevFactorGreen *= stddevFactorGreen; stddevFactorRed *= stddevFactorRed; stddevFactorBlue *= stddevFactorBlue; nRead *= nRead; // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); // For shades of green motion indicators const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); unsigned int offsX = 0, offsY = 0; // We have to adjust the offsets for the selected subframe we use for areas with motion switch (frame) { case 0: offsX = offsY = 0; break; case 1: offsX = 0; offsY = 1; break; case 2: offsX = offsY = 1; break; case 3: offsX = 1; offsY = 0; } const float thresh = adaptive ? 0.f : motionThreshold; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { float *greenDest = green[i + offsY]; float *nonGreenDest0 = red[i + offsY]; float *nonGreenDest1 = blue[i + offsY]; int j = winx + border - offsX; int c = FC(i, j); float scaleNonGreen0 = 1.f / scale_mul[0]; float scaleNonGreen2 = 1.f / scale_mul[2]; float eperIsoNonGreen0 = eperIso / scale_mul[0]; float eperIsoNonGreen2 = eperIso / scale_mul[2]; float stddevFactorNonGreen0 = stddevFactorRed; float stddevFactorNonGreen2 = stddevFactorBlue; if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels std::swap(nonGreenDest0, nonGreenDest1); std::swap(scaleNonGreen0, scaleNonGreen2); std::swap(eperIsoNonGreen0, eperIsoNonGreen2); std::swap(stddevFactorNonGreen0, stddevFactorNonGreen2); } // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop unsigned int offset = (c & 1); float greenDifMax[gridSize]; // green channel motion detection checks the grid around the pixel for differences in green channels if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); } else if(gridSize == 7) { // compute maximum of differences for first six columns of 7x7 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[4] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); greenDifMax[5] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); } } offset ^= 1; // 0 => 1 or 1 => 0 // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 int lastIndex = gridSize - 1; float korr = 0.f; for(; j < winw - (border + offsX); ++j) { offset ^= 1; // 0 => 1 or 1 => 0 if(detectMotion || adaptive) { bool skipNext = false; float gridMax; if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps gridMax = greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); skipNext = skip; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); } else if(gridSize == 7) { // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); } // adjust index for next column lastIndex ++; lastIndex = lastIndex == gridSize ? 0 : lastIndex; // increase motion detection dependent on brightness if(!adaptive) { korr = log2Lut[((int)((*rawDataFrames[1 - offset])[i - offset + 1][j] * scaleGreen)) >> 1]; } if (gridMax > thresh - korr) { // at least one of the tested pixels of the grid is detected as motion paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, nonGreenDest0, nonGreenDest1); if(skipNext) { // treat the horizontally next pixel also as motion j++; paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, nonGreenDest0, nonGreenDest1); offset ^= 1; } // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; } if(adaptive && checkNonGreenCross) { float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(diff > 0.f) { paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(diff > 0.f) { paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } if(adaptive && checkNonGreenHorizontal) { float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; float diffRight = ngRight - ngCentre; float diffLeft = ngLeft - ngCentre; if(diffRight * diffLeft >= 0.f) { float avg = (ngRight + ngLeft) / 2.f; float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(diff > 0.f) { paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } } ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; diffRight = ngRight - ngCentre; diffLeft = ngLeft - ngCentre; if(diffRight * diffLeft >= 0.f) { float avg = (ngRight + ngLeft) / 2.f; float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(diff > 0.f) { paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } } if(adaptive && checkNonGreenVertical) { float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; float diffTop = ngTop - ngCentre; float diffBottom = ngBottom - ngCentre; if(diffTop * diffBottom >= 0.f) { float avg = (ngTop + ngBottom) / 2.f; float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(diff > 0.f) { paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } } ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; diffTop = ngTop - ngCentre; diffBottom = ngBottom - ngCentre; if(diffTop * diffBottom >= 0.f) { float avg = (ngTop + ngBottom) / 2.f; float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(diff > 0.f) { paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } } } if(showMotion && showOnlyMask) { greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; continue; } // motion correction disabled or no motion detected => combine the values from the four pixelshift frames greenDest[j + offsX] = ((*rawDataFrames[1 - offset])[i - offset + 1][j] + (*rawDataFrames[3 - offset])[i + offset][j + 1]) / 2.f; nonGreenDest0[j + offsX] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; nonGreenDest1[j + offsX] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; } } if(plistener) { plistener->setProgress(1.0); } }