diff --git a/rtdata/languages/default b/rtdata/languages/default
index f1b84ed4a..9ad5e57e3 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -476,11 +476,11 @@ MAIN_TOOLTIP_HIDEHP;Show/hide the left panel (including the history) l
MAIN_TOOLTIP_INDCLIPPEDH;Clipped highlight indication (Key <)
MAIN_TOOLTIP_INDCLIPPEDS;Clipped shadow indication (Key >)
MAIN_TOOLTIP_PREFERENCES;Set preferences
-MAIN_TOOLTIP_PREVIEWB;Preview Blue channel
-MAIN_TOOLTIP_PREVIEWFOCUSMASK;Preview Focus Mask
-MAIN_TOOLTIP_PREVIEWG;Preview Green channel
-MAIN_TOOLTIP_PREVIEWL;Preview Luminosity\n0.299*R + 0.587*G + 0.114*B
-MAIN_TOOLTIP_PREVIEWR;Preview Red channel
+MAIN_TOOLTIP_PREVIEWB;Preview Blue channel\n-b
+MAIN_TOOLTIP_PREVIEWFOCUSMASK;Preview Focus Mask (beta) Shift-F\nMore accurate on images with shallow depth of field, low noise and at higher zoom levels\nTo improve detection accuracy for higher noise images evaluate at smaller zoom 10-30%
+MAIN_TOOLTIP_PREVIEWG;Preview Green channel\n-g
+MAIN_TOOLTIP_PREVIEWL;Preview Luminosity\n0.299*R + 0.587*G + 0.114*B\n-v
+MAIN_TOOLTIP_PREVIEWR;Preview Red channel\n-r
MAIN_TOOLTIP_QINFO;Quick info on the image I
MAIN_TOOLTIP_SAVEAS;Save image to a selected folder
MAIN_TOOLTIP_SAVE;Save image to the default folder
@@ -488,7 +488,7 @@ MAIN_TOOLTIP_SHOWHIDELP1;Show/hide the left panel l
MAIN_TOOLTIP_SHOWHIDERP1;Show/hide the right panel Alt-l
MAIN_TOOLTIP_SHOWHIDETP1;Show/hide the top panel Shift-l
MAIN_TOOLTIP_THRESHOLD;Threshold
-MAIN_TOOLTIP_TOGGLE;Toggle before/after view B
+MAIN_TOOLTIP_TOGGLE;Toggle before/after view Shift-B
NAVIGATOR_B_NA;B = n/a
NAVIGATOR_B_VALUE;B = %1
NAVIGATOR_G_NA;G = n/a
diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc
index 3875811d0..b426debd8 100644
--- a/rtgui/cropwindow.cc
+++ b/rtgui/cropwindow.cc
@@ -696,7 +696,7 @@ void CropWindow::expose (Cairo::RefPtr cr) {
}
#endif
- if (showcs || showch || showR || showG || showB || showL /*|| showFocusMask*/) {
+ if (showcs || showch || showR || showG || showB || showL || showFocusMask) {
Glib::RefPtr tmp = cropHandler.cropPixbuf->copy ();
guint8* pix = tmp->get_pixels();
guint8* pixWrkSpace = cropHandler.cropPixbuftrue->get_pixels();
@@ -710,63 +710,156 @@ void CropWindow::expose (Cairo::RefPtr cr) {
#ifdef _OPENMP
#pragma omp parallel for
#endif
- for (int i=0; iget_height(); i++) {
+ for (int i=0; iget_height(); i++) {
guint8* curr = pix + i*pixRowStride;
guint8* currWS = pixWrkSpace + i*pixWSRowStride;
int delta; bool changedHL; bool changedSH;
for (int j=0; jget_width(); j++) {
- // we must compare clippings in working space, since the cropPixbuf is in sRGB, with mon profile
+
+
+ if (showFocusMask){ // modulate preview to display focus mask
- changedHL=false;
- changedSH=false;
+ //*************
+ // Copyright (c) 2011 Michael Ezra michael@michaelezra.com
+ // determine if pixel is in the sharp area of the image using
+ // standard deviation analysis on two different scales
+ int blur_radius, blur_radius2;
+ float curL;
+ guint8* currIndex;
+ float avg_L, avg_L2;
+ float sum_L, sum_L2;
+ float sumsq_L, sumsq_L2; //sum of deviations squared
+ float stdDev_L, stdDev_L2;
+ float focus_gradation, focus_coef;
+ float focus_thresh, focus_thresh2;
+ int kernel_size, kernel_size2;// count of pixels in the blur kernel
+ float opacity = 0.9;//TODO: implement opacity
+ //TODO: evaluate effects of altering sampling frequency
- if (showch) {
- delta=0; changedHL=false;
- if (currWS[0]>=options.highlightThreshold && showclippedR) { delta += 255-currWS[0]; changedHL=true; }
- if (currWS[1]>=options.highlightThreshold && showclippedG) { delta += 255-currWS[1]; changedHL=true; }
- if (currWS[2]>=options.highlightThreshold && showclippedB) { delta += 255-currWS[2]; changedHL=true; }
+ //TODO: dynamically determine appropriate values based on image analysis
+ blur_radius=4;;
+ focus_thresh=80;
- if (changedHL) {
- delta *= HighlightFac;
- if (showclippedAll) curr[0]=curr[1]=curr[2]=delta; // indicate clipped highlights in gray
- else {curr[0]=255; curr[1]=curr[2]=delta;} // indicate clipped highlights in red
- }
- }
- if (showcs) {
- delta=0; changedSH=false;
+ blur_radius2 = blur_radius/4; // Band2
+ focus_thresh2 = focus_thresh/2; // Band 2 threshold
- if (currWS[0]<=options.shadowThreshold && showclippedR) { delta += currWS[0]; changedSH=true; }
- if (currWS[1]<=options.shadowThreshold && showclippedG) { delta += currWS[1]; changedSH=true; }
- if (currWS[2]<=options.shadowThreshold && showclippedB) { delta += currWS[2]; changedSH=true; }
-
- if (changedSH) {
- if (showclippedAll) {
- delta = 255 - (delta * ShawdowFac);
- curr[0]=curr[1]=curr[2]=delta; // indicate clipped shadows in gray
+ if (j>blur_radius && jget_width()-blur_radius
+ && i>blur_radius && iget_height()-blur_radius){ //stay within image area
+ // calculate average in +-blur_radius pixels area around the current pixel
+ // speed up: calculate sum of squares in the same loops
+
+ sum_L = 0; sum_L2=0;
+ sumsq_L = 0; sumsq_L2 = 0;
+ for (int kh=-blur_radius; kh<=blur_radius;kh++){
+ for (int k=-blur_radius; k<=blur_radius;k++){
+ //1 pixel step is equivalent to 3-bytes step
+ currIndex = currWS+3*k + kh*pixWSRowStride;
+ curL = 0.299*(currIndex)[0]+0.587*(currIndex)[1]+0.114*(currIndex)[2];
+ sum_L += curL;
+ sumsq_L += pow(curL,2);
+
+ // Band2 @ blur_radius2
+ if (kh>=-blur_radius2 && kh<=blur_radius2 && k>=-blur_radius2 && k<=blur_radius2){
+ sum_L2 += curL;
+ sumsq_L2 += pow(curL,2);
+ }
+ }
+ }
+ //*************
+ // averages
+ kernel_size= pow(2*blur_radius+1,2); // consider -1: Bessel's correction for the sample standard deviation (tried, did not make any visible difference)
+ kernel_size2= pow(2*blur_radius2+1,2);
+ avg_L = sum_L/kernel_size;
+ avg_L2 = sum_L2/kernel_size2;
+
+
+ stdDev_L = sqrt(sumsq_L/kernel_size - pow(avg_L,2));
+ stdDev_L2 = sqrt(sumsq_L2/kernel_size2 - pow(avg_L2,2));
+
+ //TODO: try to normalize by average L of the entire (preview) image
+
+ //detection method 1: detect focus in features
+ //there is no strict condition between stdDev_L and stdDev_L2 themselves
+/* if (stdDev_L2>focus_thresh2
+ && (stdDev_L stdDev_L2 //TODO: could vary this to bypass noise better
+ && stdDev_L2 > stdDev_L //this is the key to select fine detail within lower contrast on larger scale
+ && stdDev_L > focus_thresh/10 //options.highlightThreshold
+ ){
+ curr[0]=0;
+ curr[1]=255;
+ curr[2]=0;
}
- else {
- delta *= ShawdowFac;
- curr[2]=255; curr[0]=curr[1]=delta; // indicate clipped shadows in blue
- }
- }
- } //if (showcs)
-
- // modulate the preview of channels & L;
- if (!changedHL && !changedSH){ //This condition allows clipping indicators for RGB channels to remain in color
- if (showR) curr[1]=curr[2]=curr[0]; //Red channel in grayscale
- if (showG) curr[0]=curr[2]=curr[1]; //Green channel in grayscale
- if (showB) curr[0]=curr[1]=curr[2]; //Blue channel in grayscale
- if (showL) { //Luminosity
- // see http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness for more info
- //int L = (int)(0.212671*curr[0]+0.715160*curr[1]+0.072169*curr[2]);
- int L = (int)(0.299*curr[0]+0.587*curr[1]+0.114*curr[2]); //Lightness - this matches Luminosity mode in Photoshop CS5
- curr[0]=curr[1]=curr[2]=L;
}
}
- //if (showFocusMask){}; TODO add display of focus mask here
+
+ else { // !showFocusMask
+
+ // we must compare clippings in working space, since the cropPixbuf is in sRGB, with mon profile
+
+ changedHL=false;
+ changedSH=false;
+
+ if (showch) {
+ delta=0; changedHL=false;
+
+ if (currWS[0]>=options.highlightThreshold && showclippedR) { delta += 255-currWS[0]; changedHL=true; }
+ if (currWS[1]>=options.highlightThreshold && showclippedG) { delta += 255-currWS[1]; changedHL=true; }
+ if (currWS[2]>=options.highlightThreshold && showclippedB) { delta += 255-currWS[2]; changedHL=true; }
+
+ if (changedHL) {
+ delta *= HighlightFac;
+ if (showclippedAll) curr[0]=curr[1]=curr[2]=delta; // indicate clipped highlights in gray
+ else {curr[0]=255; curr[1]=curr[2]=delta;} // indicate clipped highlights in red
+ }
+ }
+ if (showcs) {
+ delta=0; changedSH=false;
+
+ if (currWS[0]<=options.shadowThreshold && showclippedR) { delta += currWS[0]; changedSH=true; }
+ if (currWS[1]<=options.shadowThreshold && showclippedG) { delta += currWS[1]; changedSH=true; }
+ if (currWS[2]<=options.shadowThreshold && showclippedB) { delta += currWS[2]; changedSH=true; }
+
+ if (changedSH) {
+ if (showclippedAll) {
+ delta = 255 - (delta * ShawdowFac);
+ curr[0]=curr[1]=curr[2]=delta; // indicate clipped shadows in gray
+ }
+ else {
+ delta *= ShawdowFac;
+ curr[2]=255; curr[0]=curr[1]=delta; // indicate clipped shadows in blue
+ }
+ }
+ } //if (showcs)
+
+ // modulate the preview of channels & L;
+ if (!changedHL && !changedSH){ //This condition allows clipping indicators for RGB channels to remain in color
+ if (showR) curr[1]=curr[2]=curr[0]; //Red channel in grayscale
+ if (showG) curr[0]=curr[2]=curr[1]; //Green channel in grayscale
+ if (showB) curr[0]=curr[1]=curr[2]; //Blue channel in grayscale
+ if (showL) { //Luminosity
+ // see http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness for more info
+ //int L = (int)(0.212671*curr[0]+0.715160*curr[1]+0.072169*curr[2]);
+ int L = (int)(0.299*curr[0]+0.587*curr[1]+0.114*curr[2]); //Lightness - this matches Luminosity mode in Photoshop CS5
+ curr[0]=curr[1]=curr[2]=L;
+ }
+ }
+ } // else (!showFocusMask)
+
+
/*
if (showch && (currWS[0]>=options.highlightThreshold || currWS[1]>=options.highlightThreshold || currWS[2]>=options.highlightThreshold))
@@ -782,7 +875,7 @@ void CropWindow::expose (Cairo::RefPtr cr) {
curr+=3; currWS+=3;
}
}
-
+//printf("zoomSteps[cropZoom].zoom=%d\n",zoomSteps[cropZoom].zoom);
iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), tmp, 0, 0, x+imgX, y+imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0);
}
else
diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc
index 34bb4fd8d..9611c06b5 100644
--- a/rtgui/editorpanel.cc
+++ b/rtgui/editorpanel.cc
@@ -827,7 +827,6 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) {
case GDK_I:
info->set_active (!info->get_active());
return true;
- case GDK_b:
case GDK_B:
beforeAfter->set_active (!beforeAfter->get_active());
return true;
@@ -843,6 +842,22 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) {
iarea->imageArea->zoomPanel->zoom11Clicked();
return true;
+ case GDK_r: //preview mode Red
+ iarea->imageArea->previewModePanel->toggleR();
+ return true;
+ case GDK_g: //preview mode Green
+ iarea->imageArea->previewModePanel->toggleG();
+ return true;
+ case GDK_b: //preview mode Blue
+ iarea->imageArea->previewModePanel->toggleB();
+ return true;
+ case GDK_v: //preview mode Luminosity
+ iarea->imageArea->previewModePanel->toggleL();
+ return true;
+ case GDK_F: //preview mode Focus Mask
+ iarea->imageArea->previewModePanel->toggleFocusMask();
+ return true;
+
case GDK_f:
iarea->imageArea->zoomPanel->zoomFitClicked();
return true;
@@ -852,7 +867,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) {
case GDK_greater:
iarea->imageArea->indClippedPanel->toggleClipped(false);
return true;
-//TODO add shortcuts for previewModePanel buttons
+
case GDK_F5:
openThm->openDefaultViewer(event->state & GDK_SHIFT_MASK ? 2 : 1);
return true;
diff --git a/rtgui/previewmodepanel.cc b/rtgui/previewmodepanel.cc
index 2c90439c5..640de2e7f 100644
--- a/rtgui/previewmodepanel.cc
+++ b/rtgui/previewmodepanel.cc
@@ -42,7 +42,6 @@ PreviewModePanel::PreviewModePanel (ImageArea* ia) : imageArea(ia) {
previewFocusMask = Gtk::manage (new Gtk::ToggleButton ("F"));
previewFocusMask->set_relief(Gtk::RELIEF_NONE);
previewFocusMask->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWFOCUSMASK"));
- previewFocusMask->hide();//TODO re-enable when Focus Mask is developed
previewR->set_active (false);
previewG->set_active (false);
@@ -54,7 +53,7 @@ PreviewModePanel::PreviewModePanel (ImageArea* ia) : imageArea(ia) {
pack_start (*previewG, Gtk::PACK_SHRINK, 0);
pack_start (*previewB, Gtk::PACK_SHRINK, 0);
pack_start (*previewL, Gtk::PACK_SHRINK, 0);
- //pack_start (*previewFocusMask, Gtk::PACK_SHRINK, 0); //TODO re-enable when Focus Mask is developed
+ pack_start (*previewFocusMask, Gtk::PACK_SHRINK, 0);
connR = previewR->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewR) );
connG = previewG->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewG) );
@@ -67,19 +66,19 @@ PreviewModePanel::PreviewModePanel (ImageArea* ia) : imageArea(ia) {
//TODO: use functions below for shortcuts
void PreviewModePanel::toggleR () {
-
+ previewR->set_active(!previewR->get_active());
}
void PreviewModePanel::toggleG () {
-
+ previewG->set_active(!previewG->get_active());
}
void PreviewModePanel::toggleB () {
-
+ previewB->set_active(!previewB->get_active());
}
void PreviewModePanel::toggleL () {
-
+ previewL->set_active(!previewL->get_active());
}
void PreviewModePanel::toggleFocusMask () {
-
+ previewFocusMask->set_active(!previewFocusMask->get_active());
}
void PreviewModePanel::buttonToggled (Gtk::ToggleButton* tbpreview) {
diff --git a/rtgui/previewmodepanel.h b/rtgui/previewmodepanel.h
index d7f10a1ba..cf908c787 100644
--- a/rtgui/previewmodepanel.h
+++ b/rtgui/previewmodepanel.h
@@ -19,6 +19,7 @@
#define _PREVIEWMODEPANEL_
#include
+#include "adjuster.h"//dev
class ImageArea;
class PreviewModePanel : public Gtk::HBox {