Focus Mask (beta) and shortcuts for preview modes (issue 1172)
Preview Red channel: r Preview Blue channel: b Preview Green channel: g Preview Luminosity: v Preview Focus Mask: Shift-F Before-After: changed to Shift-B
This commit is contained in:
@@ -476,11 +476,11 @@ MAIN_TOOLTIP_HIDEHP;Show/hide the left panel (including the history) <b>l</b>
|
||||
MAIN_TOOLTIP_INDCLIPPEDH;Clipped highlight indication (Key <)
|
||||
MAIN_TOOLTIP_INDCLIPPEDS;Clipped shadow indication (Key >)
|
||||
MAIN_TOOLTIP_PREFERENCES;Set preferences
|
||||
MAIN_TOOLTIP_PREVIEWB;Preview <b>Blue channel</b>
|
||||
MAIN_TOOLTIP_PREVIEWFOCUSMASK;Preview <b>Focus Mask</b>
|
||||
MAIN_TOOLTIP_PREVIEWG;Preview <b>Green channel</b>
|
||||
MAIN_TOOLTIP_PREVIEWL;Preview <b>Luminosity</b>\n0.299*R + 0.587*G + 0.114*B
|
||||
MAIN_TOOLTIP_PREVIEWR;Preview <b>Red channel</b>
|
||||
MAIN_TOOLTIP_PREVIEWB;Preview <b>Blue channel</b>\n<b>-b</b>
|
||||
MAIN_TOOLTIP_PREVIEWFOCUSMASK;Preview <b>Focus Mask</b> <i>(beta)</i> <b>Shift-F</b>\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 <b>Green channel</b>\n<b>-g</b>
|
||||
MAIN_TOOLTIP_PREVIEWL;Preview <b>Luminosity</b>\n0.299*R + 0.587*G + 0.114*B\n<b>-v</b>
|
||||
MAIN_TOOLTIP_PREVIEWR;Preview <b>Red channel</b>\n<b>-r</b>
|
||||
MAIN_TOOLTIP_QINFO;Quick info on the image <b>I</b>
|
||||
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 <b>l</b>
|
||||
MAIN_TOOLTIP_SHOWHIDERP1;Show/hide the right panel <b>Alt-l</b>
|
||||
MAIN_TOOLTIP_SHOWHIDETP1;Show/hide the top panel <b>Shift-l</b>
|
||||
MAIN_TOOLTIP_THRESHOLD;Threshold
|
||||
MAIN_TOOLTIP_TOGGLE;Toggle <b>before</b>/<b>after</b> view <b>B</b>
|
||||
MAIN_TOOLTIP_TOGGLE;Toggle <b>before</b>/<b>after</b> view <b>Shift-B</b>
|
||||
NAVIGATOR_B_NA;B = n/a
|
||||
NAVIGATOR_B_VALUE;B = %1
|
||||
NAVIGATOR_G_NA;G = n/a
|
||||
|
@@ -696,7 +696,7 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (showcs || showch || showR || showG || showB || showL /*|| showFocusMask*/) {
|
||||
if (showcs || showch || showR || showG || showB || showL || showFocusMask) {
|
||||
Glib::RefPtr<Gdk::Pixbuf> tmp = cropHandler.cropPixbuf->copy ();
|
||||
guint8* pix = tmp->get_pixels();
|
||||
guint8* pixWrkSpace = cropHandler.cropPixbuftrue->get_pixels();
|
||||
@@ -710,63 +710,156 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr) {
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int i=0; i<tmp->get_height(); i++) {
|
||||
for (int i=0; i<tmp->get_height(); i++) {
|
||||
guint8* curr = pix + i*pixRowStride;
|
||||
guint8* currWS = pixWrkSpace + i*pixWSRowStride;
|
||||
|
||||
int delta; bool changedHL; bool changedSH;
|
||||
|
||||
for (int j=0; j<tmp->get_width(); j++) {
|
||||
// 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 (showFocusMask){ // modulate preview to display focus mask
|
||||
|
||||
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; }
|
||||
//*************
|
||||
// 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 (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; }
|
||||
//TODO: dynamically determine appropriate values based on image analysis
|
||||
blur_radius=4;;
|
||||
focus_thresh=80;
|
||||
|
||||
if (changedSH) {
|
||||
if (showclippedAll) {
|
||||
delta = 255 - (delta * ShawdowFac);
|
||||
curr[0]=curr[1]=curr[2]=delta; // indicate clipped shadows in gray
|
||||
blur_radius2 = blur_radius/4; // Band2
|
||||
focus_thresh2 = focus_thresh/2; // Band 2 threshold
|
||||
|
||||
if (j>blur_radius && j<tmp->get_width()-blur_radius
|
||||
&& i>blur_radius && i<tmp->get_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
delta *= ShawdowFac;
|
||||
curr[2]=255; curr[0]=curr[1]=delta; // indicate clipped shadows in blue
|
||||
}
|
||||
}
|
||||
} //if (showcs)
|
||||
//*************
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
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 <focus_thresh)){ // this excludes false positives due to high contrast edges
|
||||
|
||||
curr[1]=255;
|
||||
curr[0]=0;
|
||||
curr[2]=0;
|
||||
|
||||
}*/
|
||||
|
||||
//detection method 2: detect focus in texture
|
||||
// key point is std deviation on lower scale is higher than for the larger scale
|
||||
// plus some boundary conditions
|
||||
if (focus_thresh > 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
//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<Cairo::Context> 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
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#define _PREVIEWMODEPANEL_
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include "adjuster.h"//dev
|
||||
|
||||
class ImageArea;
|
||||
class PreviewModePanel : public Gtk::HBox {
|
||||
|
Reference in New Issue
Block a user