app/base/siox.[ch] expose all parameters of the SIOX algorithm. Provide

2005-08-06  Sven Neumann  <sven@gimp.org>

	* app/base/siox.[ch]
	* app/core/gimpdrawable-foreground-extract.[ch]: expose all
	parameters of the SIOX algorithm. Provide default values.

	* app/tools/gimpforegroundselectoptions.[ch]: added properties and
	user interface for all SIOX parameters.

	* app/tools/gimpforegroundselecttool.c: changed accordingly.

2005-08-06  Sven Neumann  <sven@gimp.org>

	* plug-ins/benchmark-foreground-extract.py: pass run-mode to PDB
	calls.
This commit is contained in:
Sven Neumann 2005-08-06 19:08:43 +00:00 committed by Sven Neumann
parent ee530652b4
commit d670b0e11e
10 changed files with 214 additions and 65 deletions

View File

@ -1,3 +1,14 @@
2005-08-06 Sven Neumann <sven@gimp.org>
* app/base/siox.[ch]
* app/core/gimpdrawable-foreground-extract.[ch]: expose all
parameters of the SIOX algorithm. Provide default values.
* app/tools/gimpforegroundselectoptions.[ch]: added properties and
user interface for all SIOX parameters.
* app/tools/gimpforegroundselecttool.c: changed accordingly.
2005-08-06 Sven Neumann <sven@gimp.org>
* app/tools/gimpforegroundselecttool.c: added a statusbar message

View File

@ -50,12 +50,16 @@
#include "tile-manager.h"
/* Amount of color dimensions in one point */
#define SIOX_DIMS 3
/* Thresholds in the mask:
* pixels < LOW are known background
* pixels > HIGH are known foreground
*/
#define LOW 1
#define HIGH 254
#define SIOX_LOW 1
#define SIOX_HIGH 254
/* #define DEBUG */
@ -783,7 +787,7 @@ siox_progress_update (SioxProgressFunc progress_callback,
* @y: vertical offset into the mask
* @width: width of working area on mask
* @height: height of working area on mask
* @limits: a three dimensional float array specifing the accuracy,
* @limits: a double array with three entries specifing the accuracy,
* a good value is: { 0.66, 1.25, 2.5 }
* @smoothness: boundary smoothness (a good value is 3)
*
@ -799,7 +803,7 @@ siox_foreground_extract (TileManager *pixels,
gint y,
gint width,
gint height,
const gfloat limits[SIOX_DIMS],
const gdouble limits[SIOX_DIMS],
gint smoothness,
SioxProgressFunc progress_callback,
gpointer progress_data)
@ -809,7 +813,7 @@ siox_foreground_extract (TileManager *pixels,
gpointer pr;
gint bpp;
gint row, col;
const gfloat clustersize = get_clustersize (limits);
gfloat clustersize;
gint surebgcount = 0;
gint surefgcount = 0;
gint i, j;
@ -818,6 +822,7 @@ siox_foreground_extract (TileManager *pixels,
lab *surefg;
lab *bgsig;
lab *fgsig;
gfloat flimits[3];
g_return_if_fail (pixels != NULL);
g_return_if_fail (mask != NULL && tile_manager_bpp (mask) == 1);
@ -831,6 +836,12 @@ siox_foreground_extract (TileManager *pixels,
siox_progress_update (progress_callback, progress_data, 0.0);
flimits[0] = limits[0];
flimits[1] = limits[1];
flimits[2] = limits[2];
clustersize = get_clustersize (flimits);
/* count given foreground and background pixels */
pixel_region_init (&mapPR, mask, x, y, width, height, FALSE);
@ -846,9 +857,9 @@ siox_foreground_extract (TileManager *pixels,
for (col = 0; col < mapPR.w; col++, m++)
{
if (*m < LOW)
if (*m < SIOX_LOW)
surebgcount++;
else if (*m > HIGH)
else if (*m > SIOX_HIGH)
surefgcount++;
}
@ -885,12 +896,12 @@ siox_foreground_extract (TileManager *pixels,
for (col = 0; col < srcPR.w; col++, m++, s += bpp)
{
if (*m < LOW)
if (*m < SIOX_LOW)
{
calc_lab (s, bpp, colormap, surebg + i);
i++;
}
else if (*m > HIGH)
else if (*m > SIOX_HIGH)
{
calc_lab (s, bpp, colormap, surefg + j);
j++;
@ -905,7 +916,7 @@ siox_foreground_extract (TileManager *pixels,
siox_progress_update (progress_callback, progress_data, 0.2);
/* Create color signature for the background */
bgsig = create_signature (surebg, surebgcount, limits, &bgsiglen);
bgsig = create_signature (surebg, surebgcount, flimits, &bgsiglen);
g_free (surebg);
if (bgsiglen < 1)
@ -917,7 +928,7 @@ siox_foreground_extract (TileManager *pixels,
siox_progress_update (progress_callback, progress_data, 0.3);
/* Create color signature for the foreground */
fgsig = create_signature (surefg, surefgcount, limits, &fgsiglen);
fgsig = create_signature (surefg, surefgcount, flimits, &fgsiglen);
g_free (surefg);
siox_progress_update (progress_callback, progress_data, 0.4);
@ -945,7 +956,7 @@ siox_foreground_extract (TileManager *pixels,
gboolean background = FALSE;
gfloat min, d;
if (*m < LOW || *m > HIGH)
if (*m < SIOX_LOW || *m > SIOX_HIGH)
continue;
calc_lab (s, bpp, colormap, &labpixel);

View File

@ -37,8 +37,11 @@
#define __SIOX_H__
/* Amount of color dimensions in one point */
#define SIOX_DIMS 3
#define SIOX_DEFAULT_SMOOTHNESS 3
#define SIOX_DEFAULT_GRANULARITY_L 0.66
#define SIOX_DEFAULT_GRANULARITY_A 1.25
#define SIOX_DEFAULT_GRANULARITY_B 2.5
typedef void (* SioxProgressFunc) (gpointer progress_data,
@ -54,7 +57,7 @@ void siox_foreground_extract (TileManager *pixels,
gint y,
gint width,
gint height,
const gfloat limits[SIOX_DIMS],
const gdouble limits[3],
gint smoothness,
SioxProgressFunc progress_callback,
gpointer progress_data);

View File

@ -45,24 +45,32 @@ gimp_drawable_foreground_extract (GimpDrawable *drawable,
GimpDrawable *mask,
GimpProgress *progress)
{
g_return_if_fail (GIMP_IS_DRAWABLE (mask));
const gint smoothness = SIOX_DEFAULT_SMOOTHNESS;
const gdouble limits[3] = { SIOX_DEFAULT_GRANULARITY_L,
SIOX_DEFAULT_GRANULARITY_A,
SIOX_DEFAULT_GRANULARITY_B };
gimp_drawable_foreground_extract_rect (drawable, mode, mask,
g_return_if_fail (GIMP_IS_DRAWABLE (mask));
g_return_if_fail (mode == GIMP_FOREGROUND_EXTRACT_SIOX);
gimp_drawable_foreground_extract_siox (drawable, mask,
0, 0,
gimp_item_width (GIMP_ITEM (mask)),
gimp_item_height (GIMP_ITEM (mask)),
smoothness, limits,
progress);
}
void
gimp_drawable_foreground_extract_rect (GimpDrawable *drawable,
GimpForegroundExtractMode mode,
GimpDrawable *mask,
gint x,
gint y,
gint width,
gint height,
GimpProgress *progress)
gimp_drawable_foreground_extract_siox (GimpDrawable *drawable,
GimpDrawable *mask,
gint x,
gint y,
gint width,
gint height,
gint smoothness,
const gdouble limits[3],
GimpProgress *progress)
{
GimpImage *gimage;
const guchar *colormap = NULL;
@ -102,24 +110,12 @@ gimp_drawable_foreground_extract_rect (GimpDrawable *drawable,
if (progress)
gimp_progress_start (progress, _("Foreground Extraction..."), FALSE);
switch (mode)
{
case GIMP_FOREGROUND_EXTRACT_SIOX:
{
const gfloat limits[SIOX_DIMS] = { 0.66, 1.25, 2.5 };
siox_foreground_extract (gimp_drawable_data (drawable), colormap,
offset_x, offset_y,
gimp_drawable_data (mask), x, y, width, height,
limits, 3,
(SioxProgressFunc) gimp_progress_set_value,
progress);
}
break;
default:
g_return_if_reached ();
}
siox_foreground_extract (gimp_drawable_data (drawable), colormap,
offset_x, offset_y,
gimp_drawable_data (mask), x, y, width, height,
limits, 3,
(SioxProgressFunc) gimp_progress_set_value,
progress);
if (progress)
gimp_progress_end (progress);

View File

@ -24,13 +24,16 @@ void gimp_drawable_foreground_extract (GimpDrawable *drawabl
GimpForegroundExtractMode mode,
GimpDrawable *mask,
GimpProgress *progress);
void gimp_drawable_foreground_extract_rect (GimpDrawable *drawable,
GimpForegroundExtractMode mode,
/* variant for SIOX that gives more control over the segmentation */
void gimp_drawable_foreground_extract_siox (GimpDrawable *drawable,
GimpDrawable *mask,
gint x,
gint y,
gint width,
gint height,
gint smoothness,
const gdouble limits[3],
GimpProgress *progress);
#endif /* __GIMP_DRAWABLE_FOREGROUND_EXTRACT_H__ */

View File

@ -25,6 +25,8 @@
#include "tools-types.h"
#include "base/siox.h"
#include "core/gimptoolinfo.h"
#include "gimpforegroundselectoptions.h"
@ -36,8 +38,13 @@
enum
{
PROP_0,
PROP_EXPANDED,
PROP_BACKGROUND,
PROP_STROKE_WIDTH
PROP_STROKE_WIDTH,
PROP_SMOOTHNESS,
PROP_GRANULARITY_L,
PROP_GRANULARITY_A,
PROP_GRANULARITY_B
};
@ -89,6 +96,10 @@ gimp_foreground_select_options_class_init (GimpForegroundSelectOptionsClass *kla
object_class->set_property = gimp_foreground_select_options_set_property;
object_class->get_property = gimp_foreground_select_options_get_property;
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_EXPANDED,
"expanded", NULL,
FALSE,
0);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_BACKGROUND,
"background", NULL,
FALSE,
@ -98,6 +109,28 @@ gimp_foreground_select_options_class_init (GimpForegroundSelectOptionsClass *kla
_("Size of the brush used for refinements"),
1, 32, 12,
0);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_SMOOTHNESS,
"smoothness",
_("Smaller values give a more accurate "
"selection border but may introduce holes "
"in the selection"),
0, 8, SIOX_DEFAULT_SMOOTHNESS,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_GRANULARITY_L,
"granularity-l",
_("Resolution for brightness component"),
0.0, 10.0, SIOX_DEFAULT_GRANULARITY_L,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_GRANULARITY_A,
"granularity-a",
_("Resolution for red/green component"),
0.0, 10.0, SIOX_DEFAULT_GRANULARITY_A,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_GRANULARITY_B,
"granularity-b",
_("Resolution for yellow/blue component"),
0.0, 10.0, SIOX_DEFAULT_GRANULARITY_B,
0);
}
static void
@ -110,12 +143,27 @@ gimp_foreground_select_options_set_property (GObject *object,
switch (property_id)
{
case PROP_EXPANDED:
options->expanded = g_value_get_boolean (value);
break;
case PROP_BACKGROUND:
options->background = g_value_get_boolean (value);
break;
case PROP_STROKE_WIDTH:
options->stroke_width = g_value_get_int (value);
break;
case PROP_SMOOTHNESS:
options->smoothness = g_value_get_int (value);
break;
case PROP_GRANULARITY_L:
options->limits[0] = g_value_get_double (value);
break;
case PROP_GRANULARITY_A:
options->limits[1] = g_value_get_double (value);
break;
case PROP_GRANULARITY_B:
options->limits[2] = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -132,12 +180,27 @@ gimp_foreground_select_options_get_property (GObject *object,
switch (property_id)
{
case PROP_EXPANDED:
g_value_set_boolean (value, options->expanded);
break;
case PROP_BACKGROUND:
g_value_set_boolean (value, options->background);
break;
case PROP_STROKE_WIDTH:
g_value_set_int (value, options->stroke_width);
break;
case PROP_SMOOTHNESS:
g_value_set_int (value, options->smoothness);
break;
case PROP_GRANULARITY_L:
g_value_set_double (value, options->limits[0]);
break;
case PROP_GRANULARITY_A:
g_value_set_double (value, options->limits[1]);
break;
case PROP_GRANULARITY_B:
g_value_set_double (value, options->limits[2]);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -147,14 +210,18 @@ gimp_foreground_select_options_get_property (GObject *object,
GtkWidget *
gimp_foreground_select_options_gui (GimpToolOptions *tool_options)
{
GtkWidget *vbox = gimp_selection_options_gui (tool_options);
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = gimp_selection_options_gui (tool_options);
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *scale;
GtkWidget *label;
GtkWidget *inner_frame;
GtkWidget *table;
gint row = 0;
frame = gimp_prop_boolean_radio_frame_new (G_OBJECT (tool_options),
"background",
/* foreground / background */
frame = gimp_prop_boolean_radio_frame_new (config, "background",
_("Interactive refinement"),
_("Mark background"),
_("Mark foreground"));
@ -162,24 +229,68 @@ gimp_foreground_select_options_gui (GimpToolOptions *tool_options)
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
scale = gimp_prop_hscale_new (G_OBJECT (tool_options), "stroke-width",
1.0, 5.0, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
gtk_box_pack_start (GTK_BOX (GTK_BIN (frame)->child), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
/* stroke width */
inner_frame = gtk_vbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (GTK_BIN (frame)->child),
inner_frame, FALSE, FALSE, 2);
gtk_widget_show (inner_frame);
hbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (GTK_BIN (frame)->child), hbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (inner_frame), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new (_("Small"));
label = gtk_label_new (_("Small brush"));
gimp_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
PANGO_ATTR_SCALE, PANGO_SCALE_SMALL,
-1);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
label = gtk_label_new (_("Large"));
label = gtk_label_new (_("Large brush"));
gimp_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
PANGO_ATTR_SCALE, PANGO_SCALE_SMALL,
-1);
gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
scale = gimp_prop_hscale_new (config, "stroke-width", 1.0, 5.0, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
gtk_box_pack_start (GTK_BOX (inner_frame), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
/* smoothness */
table = gtk_table_new (1, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table);
scale = gimp_prop_hscale_new (config, "smoothness", 0.1, 1.0, 0);
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
_("Smoothing:"), 0.0, 1.0, scale, 2, FALSE);
/* granularity */
frame = gimp_prop_expander_new (config, "expanded", _("Granularity"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
inner_frame = gimp_frame_new ("<expander>");
gtk_container_add (GTK_CONTAINER (frame), inner_frame);
gtk_widget_show (inner_frame);
table = gtk_table_new (3, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_container_add (GTK_CONTAINER (inner_frame), table);
gtk_widget_show (table);
gimp_prop_opacity_entry_new (config, "granularity-l",
GTK_TABLE (table), 0, row++, "L:");
gimp_prop_opacity_entry_new (config, "granularity-a",
GTK_TABLE (table), 0, row++, "a:");
gimp_prop_opacity_entry_new (config, "granularity-b",
GTK_TABLE (table), 0, row++, "b:");
return vbox;
}

View File

@ -38,8 +38,11 @@ struct _GimpForegroundSelectOptions
{
GimpSelectionOptions parent_instance;
gboolean expanded;
gboolean background;
gint stroke_width;
gint smoothness;
gdouble limits[3];
};

View File

@ -496,8 +496,10 @@ static void
gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
GimpDisplay *gdisp)
{
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (free_sel);
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (free_sel);
GimpForegroundSelectOptions *options;
GimpTool *tool = GIMP_TOOL (free_sel);
GimpImage *gimage = gdisp->gimage;
GimpDrawable *drawable = gimp_image_active_drawable (gimage);
GimpScanConvert *scan_convert;
@ -510,6 +512,8 @@ gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
if (! drawable)
return;
options = GIMP_FOREGROUND_SELECT_OPTIONS (tool->tool_info->tool_options);
gimp_set_busy (gimage->gimp);
scan_convert = gimp_scan_convert_new ();
@ -541,10 +545,11 @@ gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
for (list = fg_select->strokes; list; list = list->next)
gimp_foreground_select_tool_stroke (mask, list->data);
gimp_drawable_foreground_extract_rect (drawable,
GIMP_FOREGROUND_EXTRACT_SIOX,
gimp_drawable_foreground_extract_siox (drawable,
GIMP_DRAWABLE (mask),
x, y, width, height,
options->smoothness,
options->limits,
GIMP_PROGRESS (gdisp));
gimp_foreground_select_tool_set_mask (GIMP_FOREGROUND_SELECT_TOOL (free_sel),

View File

@ -1,3 +1,8 @@
2005-08-06 Sven Neumann <sven@gimp.org>
* plug-ins/benchmark-foreground-extract.py: pass run-mode to PDB
calls.
2005-08-03 Sven Neumann <sven@gimp.org>
* pygimp-rgb.c: added wrapper for gimp_rgb_luminance().

View File

@ -72,14 +72,14 @@ def benchmark (folder, save_output):
mask_name = os.path.join (folder, "cm_bmp", name + '.png')
truth_name = os.path.join (folder, "truth", name + '.bmp')
image = pdb.gimp_file_load (image_name, image_name)
image = pdb.gimp_file_load (RUN_NONINTERACTIVE, image_name, image_name)
image_layer = image.active_layer;
mask = pdb.gimp_file_load (mask_name, mask_name)
mask = pdb.gimp_file_load (RUN_NONINTERACTIVE, mask_name, mask_name)
convert_grayscale (mask)
mask_layer = mask.active_layer;
truth = pdb.gimp_file_load (truth_name, truth_name)
truth = pdb.gimp_file_load (RUN_NONINTERACTIVE, truth_name, truth_name)
convert_grayscale (truth)
truth_layer = truth.active_layer;
@ -125,7 +125,8 @@ def benchmark (folder, save_output):
if save_output:
filename = os.path.join (folder, "output", name + '.png')
pdb.gimp_file_save (mask, mask_layer, filename, filename)
pdb.gimp_file_save (RUN_NONINTERACTIVE,
mask, mask_layer, filename, filename)
gimp.delete (mask)