diff --git a/rtdata/languages/default b/rtdata/languages/default
index c66c3a64d..9399982d8 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -1654,6 +1654,11 @@ TP_RAW_IMAGENUM;Some raw files might embed several sub-images (HDR, Pixel-Shift,
TP_RAW_LABEL;Demosaicing
TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps
TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio.
+TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection
+TP_RAW_PIXELSHIFTMOTION_TOOLTIP;No tooltip available atm
+TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction
+TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid
+TP_RAW_PIXELSHIFTSHOWMOTION;Show motion
TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix
TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster.
TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix
diff --git a/rtdata/rt_splash_5.png b/rtdata/rt_splash_5.png
new file mode 100644
index 000000000..be996e119
Binary files /dev/null and b/rtdata/rt_splash_5.png differ
diff --git a/rtdata/rt_splash_5.svg b/rtdata/rt_splash_5.svg
new file mode 100644
index 000000000..d5f7ac4f3
--- /dev/null
+++ b/rtdata/rt_splash_5.svg
@@ -0,0 +1,1772 @@
+
+
+
+
diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc
index a68157b65..7e25f907f 100644
--- a/rtengine/pixelshift.cc
+++ b/rtengine/pixelshift.cc
@@ -1,6 +1,13 @@
////////////////////////////////////////////////////////////////
//
-// simple pentax pixelshift algorithm
+// pentax pixelshift algorithm with motion detection
+//
+// 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
//
//
@@ -23,58 +30,184 @@
#include "rawimagesource.h"
#include "../rtgui/multilangmgr.h"
#include "procparams.h"
-#include "opthelper.h"
#define BENCHMARK
#include "StopWatch.h"
+
+namespace
+{
+
+float greenDiff(float a, float b)
+{
+ // calculate the difference between to green samples
+ // add a small epsilon to avoid division by zero
+ return std::fabs(a - b) / (std::max(a, b) + 0.0001f);
+
+}
+
+}
+
using namespace std;
using namespace rtengine;
-void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh)
+void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize)
{
-BENCHFUN
- double progress = 0.0;
- const bool plistenerActive = plistener;
+ BENCHFUN
if (plistener) {
plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]));
- plistener->setProgress (progress);
+ plistener->setProgress(0.0);
}
- const int bord = 4;
+ // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel
+ const float motionThreshold = 1.f - (motion / 100.f);
+
+ unsigned int offsX = 0, offsY = 0;
+ if(detectMotion && !showMotion) {
+ // if motion correction is enabled 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;
+ }
+ }
#ifdef _OPENMP
- #pragma omp parallel for
+ #pragma omp parallel for schedule(dynamic,16)
#endif
- for(int i = bord; i < winh - bord; ++i) {
- float *greenDest = green[i];
- float *nonGreenDest0 = red[i];
- float *nonGreenDest1 = blue[i];
- int j = bord;
- int c = FC(i,j);
- if (c == 2 || ((c&1) && FC(i,j+1) == 2)) {
+
+ 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);
+
+ 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);
}
- if(c&1) {
- greenDest[j] = (riFrames[0]->data[i][j] + riFrames[2]->data[i+1][j+1]) / 2.f;
- nonGreenDest0[j] = riFrames[3]->data[i][j+1];
- nonGreenDest1[j] = riFrames[1]->data[i+1][j];
- j++;
+
+ // 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];
+ // motion detection checks the grid around the pixel for differences in green channels
+ if(detectMotion) {
+ if(gridSize == 3) {
+ // compute maximum of differences for first two columns of 3x3 grid
+ greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]),
+ greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j])
+ );
+ greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]),
+ greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1]),
+ greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1])
+ );
+ } else if(gridSize == 5) {
+ // compute maximum of differences for first four columns of 5x5 grid
+ greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1]),
+ greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1]),
+ greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1])
+ );
+ greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j]),
+ greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]),
+ greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j]),
+ greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j])
+ );
+ greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1]),
+ greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1]),
+ greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1])
+ );
+ greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2]),
+ greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2]),
+ greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2]),
+ greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2])
+ );
+ }
}
- for(; j< winw - bord; j+=2) {
- nonGreenDest0[j] = riFrames[0]->data[i][j];
- greenDest[j] = (riFrames[3]->data[i][j+1] + riFrames[1]->data[i+1][j] ) / 2.f;
- nonGreenDest1[j] = riFrames[2]->data[i+1][j+1];
- greenDest[j+1] = (riFrames[0]->data[i][j+1] + riFrames[2]->data[i+1][j+2]) / 2.f;
- nonGreenDest0[j+1] = riFrames[3]->data[i][j+2];
- nonGreenDest1[j+1] = riFrames[1]->data[i+1][j+1];
+
+ 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;
+
+ for(; j < winw - (border + offsX); ++j) {
+ offset ^= 1; // 0 => 1 or 1 => 0
+
+ if(detectMotion) {
+ bool skipNext = false;
+ float gridMax;
+ if(gridSize == 1) {
+ // compute difference for current pixel and skip next pixel, that's the method from dcrawps
+ gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]);
+ skipNext = !showMotion;
+ } else if(gridSize == 3) {
+ // compute maximum of differences for third column of 3x3 grid and save at position lastIndex
+ greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2]),
+ greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2])
+ );
+ gridMax = 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] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3]),
+ greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3]),
+ greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3]),
+ greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3])
+ );
+ gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]);
+ }
+ // adjust index for next column
+ lastIndex ++;
+ lastIndex = lastIndex == gridSize ? 0 : lastIndex;
+
+ if (gridMax > motionThreshold) {
+ // at least one of the tested pixels of the grid is detected as motion
+ if(showMotion) {
+ // if showMotion is enabled make the pixel green
+ greenDest[j] = 10000.f;
+ nonGreenDest0[j] = nonGreenDest1[j] = 0.f;
+ }
+ if(skipNext) {
+ // treat the horizontally next pixel also as motion
+ j++;
+ offset ^= 1;
+ }
+ // do not set the motion pixel values. They have already been set by demosaicer or showMotion
+ continue;
+ }
+ }
+
+ // motion correction disabled or no motion detected => combine the values from the four pixelshift frames
+ greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f;
+ nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset];
+ nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1];
}
}
- if(plistenerActive) {
- plistener->setProgress(1.00);
+ if(plistener) {
+ plistener->setProgress(1.0);
}
-
}
-#undef TS
-#undef CLF
diff --git a/rtengine/procevents.h b/rtengine/procevents.h
index 69cda228a..24469cead 100644
--- a/rtengine/procevents.h
+++ b/rtengine/procevents.h
@@ -471,6 +471,7 @@ enum ProcEvent {
EvLskal = 441,
EvOBPCompens = 442,
EvRawImageNum = 443,
+ EvDemosaicPixelshiftMotion = 444,
NUMOFEVENTS
};
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 2a7b41847..466b25d82 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -885,6 +885,9 @@ void RAWParams::setDefaults()
bayersensor.dcb_enhance = true;
//bayersensor.all_enhance = false;
bayersensor.lmmse_iterations = 2;
+ bayersensor.pixelshiftMotion = 70;
+ bayersensor.pixelshiftMotionCorrection = 3;
+ bayersensor.pixelshiftShowMotion = false;
bayersensor.black0 = 0.0;
bayersensor.black1 = 0.0;
bayersensor.black2 = 0.0;
@@ -3364,6 +3367,18 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b
keyFile.set_integer ("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations );
}
+ if (!pedited || pedited->raw.bayersensor.pixelshiftMotion) {
+ keyFile.set_integer ("RAW Bayer", "PixelShiftMotion", raw.bayersensor.pixelshiftMotion );
+ }
+
+ if (!pedited || pedited->raw.bayersensor.pixelshiftMotionCorrection) {
+ keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelshiftMotionCorrection );
+ }
+
+ if (!pedited || pedited->raw.bayersensor.pixelshiftShowMotion) {
+ keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelshiftShowMotion );
+ }
+
//if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance );
if (!pedited || pedited->raw.xtranssensor.method) {
@@ -7422,6 +7437,30 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited)
}
}
+ if (keyFile.has_key ("RAW Bayer", "PixelShiftMotion")) {
+ raw.bayersensor.pixelshiftMotion = keyFile.get_integer("RAW Bayer", "PixelShiftMotion");
+
+ if (pedited) {
+ pedited->raw.bayersensor.pixelshiftMotion = true;
+ }
+ }
+
+ if (keyFile.has_key ("RAW Bayer", "PixelShiftMotionCorrection")) {
+ raw.bayersensor.pixelshiftMotionCorrection = keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrection");
+
+ if (pedited) {
+ pedited->raw.bayersensor.pixelshiftMotionCorrection = true;
+ }
+ }
+
+ if (keyFile.has_key ("RAW Bayer", "PixelShiftShowMotion")) {
+ raw.bayersensor.pixelshiftShowMotion = keyFile.get_boolean("RAW Bayer", "PixelShiftShowMotion");
+
+ if (pedited) {
+ pedited->raw.bayersensor.pixelshiftShowMotion = true;
+ }
+ }
+
//if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; }
}
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 35a4f1932..3f5951cf8 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -1182,6 +1182,9 @@ public:
int greenthresh;
int dcb_iterations;
int lmmse_iterations;
+ int pixelshiftMotion;
+ int pixelshiftMotionCorrection;
+ bool pixelshiftShowMotion;
bool dcb_enhance;
//bool all_enhance;
};
diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc
index 37cf2618e..f4760d44e 100644
--- a/rtengine/rawimagesource.cc
+++ b/rtengine/rawimagesource.cc
@@ -1549,6 +1549,7 @@ Stop1.stop();
if(riFrames[0]->get_width() != riFrames[1]->get_width() || riFrames[0]->get_height() != riFrames[1]->get_height()) {
numFrames = 1;
}
+ pixelShiftColoursScaled = false;
}
if (plistener) {
@@ -1757,7 +1758,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
printf( "Flat Field Correction:%s\n", rif->get_filename().c_str());
}
- copyOriginalPixels(raw, ri, rid, rif);
+ copyOriginalPixels(raw, ri, rid, rif, rawData);
//FLATFIELD end
@@ -1798,7 +1799,10 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
}
- scaleColors( 0, 0, W, H, raw); //+ + raw parameters for black level(raw.blackxx)
+ scaleColors( 0, 0, W, H, raw, rawData); //+ + raw parameters for black level(raw.blackxx)
+ if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] && !pixelShiftColoursScaled) {
+ scaleColors_pixelshift( 0, 0, W, H, raw);
+ }
// Correct vignetting of lens profile
if (!hasFlatField && lensProf.useVign) {
@@ -1958,11 +1962,11 @@ void RawImageSource::demosaic(const RAWParams &raw)
} else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) {
amaze_demosaic_RT (0, 0, W, H);
} else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) {
+ if(raw.bayersensor.pixelshiftMotion > 0) {
+ amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction
+ }
if(numFrames == 4) {
- pixelshift_simple(0, 0, W, H);
- scaleColors_pixelshift( 0, 0, W, H, raw);
- } else { // for non pixelshift files use amaze if pixelshift is selected
- amaze_demosaic_RT (0, 0, W, H);
+ pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection);
}
} else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) {
dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance);
@@ -3010,7 +3014,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile
/* Copy original pixel data and
* subtract dark frame (if present) from current image and apply flat field correction (if present)
*/
-void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile )
+void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile, array2D &rawData )
{
// TODO: Change type of black[] to float to avoid conversions
unsigned short black[4] = {
@@ -3341,7 +3345,7 @@ SSEFUNCTION void RawImageSource::cfaboxblur(RawImage *riFlatFile, float* cfablur
// Scale original pixels into the range 0 65535 using black offsets and multipliers
-void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const RAWParams &raw)
+void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData)
{
chmax[0] = chmax[1] = chmax[2] = chmax[3] = 0; //channel maxima
float black_lev[4] = {0.f};//black level
@@ -3555,17 +3559,12 @@ void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int wi
for (int row = winy; row < winy + winh; row ++)
{
for (int col = winx; col < winx + winw; col++) {
- float redval = (red[row][col] - cblacksom[0]) * scale_mul[0];
- tmpchmax[0] = max(tmpchmax[0], redval);
- red[row][col] = redval;
-
- float greenval = (green[row][col] - cblacksom[1]) * scale_mul[1];
- tmpchmax[1] = max(tmpchmax[1], greenval);
- green[row][col] = greenval;
-
- float blueval = (blue[row][col] - cblacksom[2]) * scale_mul[2];
- tmpchmax[2] = max(tmpchmax[2], blueval);
- blue[row][col] = blueval;
+ int c = FC(row,col);
+ for(int frame = 0; frame < 4; ++frame) {
+ float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c];
+ tmpchmax[c] = max(tmpchmax[c], val);
+ riFrames[frame]->data[row][col] = val;
+ }
}
}
@@ -3578,6 +3577,7 @@ void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int wi
chmax[2] = max(tmpchmax[2], chmax[2]);
}
}
+ pixelShiftColoursScaled = true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h
index 560314802..648e5ec77 100644
--- a/rtengine/rawimagesource.h
+++ b/rtengine/rawimagesource.h
@@ -81,6 +81,7 @@ protected:
int threshold;
array2D rawData; // holds preprocessed pixel values, rowData[i][j] corresponds to the ith row and jth column
+ array2D *rawDataFrames[16] = {nullptr};
// the interpolated green plane:
array2D green;
@@ -128,9 +129,9 @@ public:
}
void processFlatField(const RAWParams &raw, RawImage *riFlatFile, unsigned short black[4]);
- void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile );
+ void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData );
void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW);
- void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw); // raw for cblack
+ void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData); // raw for cblack
void scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw);
@@ -205,6 +206,7 @@ public:
ri = riFrames[currFrame];
}
protected:
+ bool pixelShiftColoursScaled = false;
typedef unsigned short ushort;
void processFalseColorCorrection (Imagefloat* i, const int steps);
inline void convert_row_to_YIQ (const float* const r, const float* const g, const float* const b, float* Y, float* I, float* Q, const int W);
@@ -261,7 +263,7 @@ protected:
void xtransborder_interpolate (int border);
void xtrans_interpolate (const int passes, const bool useCieLab);
void fast_xtrans_interpolate ();
- void pixelshift_simple(int winx, int winy, int winw, int winh);
+ void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int method);
void hflip (Imagefloat* im);
void vflip (Imagefloat* im);
diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc
index 33e988674..643c9e075 100644
--- a/rtengine/refreshmap.cc
+++ b/rtengine/refreshmap.cc
@@ -470,7 +470,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
RETINEX, // EvRetinexgaintransmission
RETINEX, // EvLskal
OUTPUTPROFILE, // EvOBPCompens
- DARKFRAME // EvRawImageNum
+ DARKFRAME, // EvRawImageNum
+ DEMOSAIC // EvDemosaicPixelshiftMotion
};
diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h
index 67d883080..5e2f04d05 100644
--- a/rtengine/rt_math.h
+++ b/rtengine/rt_math.h
@@ -74,6 +74,13 @@ inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d)
return std::max(d, std::max(c, std::max(a, b)));
}
+template
+inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d, const _Tp& e)
+{
+ return max(max(a,b,c),std::max(d,e));
+}
+
+
template
inline _Tp intp(_Tp a, _Tp b, _Tp c)
{
diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc
index 639eabc02..92351be2b 100644
--- a/rtgui/bayerprocess.cc
+++ b/rtgui/bayerprocess.cc
@@ -81,6 +81,34 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA
lmmseOptions->pack_start(*lmmseIterations);
pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4);
+ pixelShiftOptions = Gtk::manage (new Gtk::VBox ());
+ pixelShiftOptions->set_border_width(4);
+ pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION")));
+ pixelShiftOptions->pack_start(*pixelShiftShowMotion);
+
+ pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70));
+ pixelShiftMotion->setAdjusterListener (this);
+ pixelShiftMotion->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP"));
+
+ if (pixelShiftMotion->delay < options.adjusterMaxDelay) {
+ pixelShiftMotion->delay = options.adjusterMaxDelay;
+ }
+ pixelShiftMotion->show();
+ pixelShiftOptions->pack_start(*pixelShiftMotion);
+
+ pixelShiftMotionCorrection = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION"), 1, 5, 2, 3));
+ pixelShiftMotionCorrection->setAdjusterListener (this);
+ pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP"));
+
+ if (pixelShiftMotionCorrection->delay < options.adjusterMaxDelay) {
+ pixelShiftMotionCorrection->delay = options.adjusterMaxDelay;
+ }
+
+ pixelShiftMotionCorrection->show();
+ pixelShiftOptions->pack_start(*pixelShiftMotionCorrection);
+ pack_start( *pixelShiftOptions, Gtk::PACK_SHRINK, 4);
+
+
pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 );
ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 ));
ccSteps->setAdjusterListener (this);
@@ -102,6 +130,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA
methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) );
imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) );
dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true);
+ pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true);
//allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true);
}
@@ -129,8 +158,11 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params
ccSteps->setEditedState (pedited->raw.bayersensor.ccSteps ? Edited : UnEdited);
dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited);
dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance);
+ pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion);
//allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance);
lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited);
+ pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited);
+ pixelShiftMotionCorrection->setEditedState ( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited);
if(!pedited->raw.bayersensor.method) {
method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name
@@ -144,8 +176,11 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params
dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations);
dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance);
+ pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion);
ccSteps->setValue (pp->raw.bayersensor.ccSteps);
lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations);
+ pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion);
+ pixelShiftMotionCorrection->setValue (pp->raw.bayersensor.pixelshiftMotionCorrection);
if (!batchMode) {
if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] ||
@@ -160,6 +195,12 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params
} else {
lmmseOptions->hide();
}
+ if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::pixelshift_simple] ||
+ method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) {
+ pixelShiftOptions->show();
+ } else {
+ pixelShiftOptions->hide();
+ }
// Flase color suppression is applied to all demozaicing method, so don't hide anything
/*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] ||
@@ -188,6 +229,9 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe
pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active();
//pp->raw.bayersensor.all_enhance = allEnhance->get_active();
pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue();
+ pp->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getIntValue();
+ pp->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getIntValue();
+ pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active();
int currentRow = method->get_active_row_number();
if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) {
@@ -208,6 +252,9 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe
pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent();
//pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent();
pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState ();
+ pedited->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getEditedState ();
+ pedited->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getEditedState ();
+ pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent();
}
}
@@ -219,25 +266,34 @@ void BayerProcess::setBatchMode(bool batchMode)
imageNumber->set_active(4);
dcbOptions->hide();
lmmseOptions->hide();
+ pixelShiftOptions->hide();
ToolPanel::setBatchMode (batchMode);
ccSteps->showEditedCB ();
dcbIterations->showEditedCB ();
lmmseIterations->showEditedCB ();
+ pixelShiftMotion->showEditedCB ();
+ pixelShiftMotionCorrection->showEditedCB ();
}
void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited)
{
dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations);
lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations);
+ pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelshiftMotion);
+ pixelShiftMotionCorrection->setDefault( defParams->raw.bayersensor.pixelshiftMotionCorrection);
ccSteps->setDefault (defParams->raw.bayersensor.ccSteps);
if (pedited) {
dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited);
lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited);
+ pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited);
+ pixelShiftMotionCorrection->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited);
ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited);
} else {
dcbIterations->setDefaultEditedState( Irrelevant );
lmmseIterations->setDefaultEditedState( Irrelevant );
+ pixelShiftMotion->setDefaultEditedState( Irrelevant );
+ pixelShiftMotionCorrection->setDefaultEditedState( Irrelevant );
ccSteps->setDefaultEditedState(Irrelevant );
}
}
@@ -251,6 +307,10 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval)
listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() );
} else if (a == lmmseIterations) {
listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() );
+ } else if (a == pixelShiftMotion) {
+ listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() );
+ } else if (a == pixelShiftMotionCorrection) {
+ listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() );
}
}
}
@@ -271,6 +331,12 @@ void BayerProcess::methodChanged ()
lmmseOptions->hide();
}
+ if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift_simple) {
+ pixelShiftOptions->show();
+ } else {
+ pixelShiftOptions->hide();
+ }
+
Glib::ustring methodName = "";
bool ppreq = false;
@@ -316,6 +382,26 @@ void BayerProcess::dcbEnhanceChanged ()
}
}
+void BayerProcess::pixelShiftShowMotionChanged ()
+{
+ if (batchMode) {
+ if (pixelShiftShowMotion->get_inconsistent()) {
+ pixelShiftShowMotion->set_inconsistent (false);
+ pixelShiftShowMotionconn.block (true);
+ pixelShiftShowMotion->set_active (false);
+ pixelShiftShowMotionconn.block (false);
+ } else if (lastDCBen) {
+ pixelShiftShowMotion->set_inconsistent (true);
+ }
+
+ lastDCBen = pixelShiftShowMotion->get_active ();
+ }
+
+ if (listener) {
+ listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftShowMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED"));
+ }
+}
+
/*void BayerProcess::allEnhanceChanged ()
{
if (batchMode) {
diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h
index bba4bd51d..404324ed6 100644
--- a/rtgui/bayerprocess.h
+++ b/rtgui/bayerprocess.h
@@ -41,11 +41,14 @@ protected:
//Gtk::CheckButton* allEnhance;
Gtk::VBox *lmmseOptions;
Adjuster* lmmseIterations;
-
+ Gtk::VBox *pixelShiftOptions;
+ Adjuster* pixelShiftMotion;
+ Adjuster* pixelShiftMotionCorrection;
+ Gtk::CheckButton* pixelShiftShowMotion;
bool lastDCBen;
int oldMethod;
//bool lastALLen;
- sigc::connection methodconn, imagenumberconn, dcbEnhconn; //,allEnhconn;
+ sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn; //,allEnhconn;
public:
BayerProcess ();
@@ -59,6 +62,7 @@ public:
void imageNumberChanged ();
void adjusterChanged (Adjuster* a, double newval);
void dcbEnhanceChanged();
+ void pixelShiftShowMotionChanged();
//void allEnhanceChanged();
};
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index ebb31ef1d..6a020cd8b 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -370,6 +370,9 @@ void ParamsEdited::set (bool v)
raw.bayersensor.dcbEnhance = v;
//raw.bayersensor.allEnhance = v;
raw.bayersensor.lmmseIterations = v;
+ raw.bayersensor.pixelshiftMotion = v;
+ raw.bayersensor.pixelshiftMotionCorrection = v;
+ raw.bayersensor.pixelshiftShowMotion = v;
raw.bayersensor.greenEq = v;
raw.bayersensor.linenoise = v;
raw.xtranssensor.method = v;
@@ -866,6 +869,9 @@ void ParamsEdited::initFrom (const std::vector
raw.bayersensor.dcbEnhance = raw.bayersensor.dcbEnhance && p.raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance;
//raw.bayersensor.allEnhance = raw.bayersensor.allEnhance && p.raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance;
raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations;
+ raw.bayersensor.pixelshiftMotion = raw.bayersensor.pixelshiftMotion && p.raw.bayersensor.pixelshiftMotion == other.raw.bayersensor.pixelshiftMotion;
+ raw.bayersensor.pixelshiftMotionCorrection = raw.bayersensor.pixelshiftMotionCorrection && p.raw.bayersensor.pixelshiftMotionCorrection == other.raw.bayersensor.pixelshiftMotionCorrection;
+ raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion;
raw.bayersensor.greenEq = raw.bayersensor.greenEq && p.raw.bayersensor.greenthresh == other.raw.bayersensor.greenthresh;
raw.bayersensor.linenoise = raw.bayersensor.linenoise && p.raw.bayersensor.linenoise == other.raw.bayersensor.linenoise;
raw.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method;
@@ -2278,6 +2284,18 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
toEdit.raw.bayersensor.lmmse_iterations = mods.raw.bayersensor.lmmse_iterations;
}
+ if (raw.bayersensor.pixelshiftMotion) {
+ toEdit.raw.bayersensor.pixelshiftMotion = mods.raw.bayersensor.pixelshiftMotion;
+ }
+
+ if (raw.bayersensor.pixelshiftMotionCorrection) {
+ toEdit.raw.bayersensor.pixelshiftMotionCorrection = mods.raw.bayersensor.pixelshiftMotionCorrection;
+ }
+
+ if (raw.bayersensor.pixelshiftShowMotion) {
+ toEdit.raw.bayersensor.pixelshiftShowMotion = mods.raw.bayersensor.pixelshiftShowMotion;
+ }
+
//if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance;
if (raw.bayersensor.greenEq) {
toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh;
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 4e9fa4eb4..5546c9857 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -692,6 +692,9 @@ public:
bool dcbIterations;
bool dcbEnhance;
bool lmmseIterations;
+ bool pixelshiftMotion;
+ bool pixelshiftMotionCorrection;
+ bool pixelshiftShowMotion;
//bool allEnhance;
bool greenEq;
bool linenoise;