[gimp] Port benchmark-foreground-extract.py to python 3.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Port benchmark-foreground-extract.py to python 3.
- Date: Sun, 20 Sep 2020 22:21:51 +0000 (UTC)
commit a07576b2193055a294acb9904f5f57bb35f2d443
Author: Elad Shahar <dawn ever gmail com>
Date: Wed Jan 8 00:16:40 2020 +0200
Port benchmark-foreground-extract.py to python 3.
Note by reviewer (Jehan): merging this port as it was in GIMP 2.10
anyway, but is this even still needed code? This plug-in is not even
available on stable release, it looks like for-development only
benchmark, and I'm not sure if it's relevant anymore, especially in our
GEGL-fueled new world.
Please anyone who knows a bit more on the history of this plug-in and
the evolution of our gimp_drawable_foreground_extract() algorithm, feel
free to weigh in and tell us what this was for exactly and if it's still
relevant.
.../plug-ins/benchmark-foreground-extract.py | 197 ----------------
plug-ins/python/Makefile.am | 7 +-
plug-ins/python/benchmark-foreground-extract.py | 250 +++++++++++++++++++++
plug-ins/python/meson.build | 2 +-
4 files changed, 257 insertions(+), 199 deletions(-)
---
diff --git a/plug-ins/python/Makefile.am b/plug-ins/python/Makefile.am
index 19091ab643..73f7ce7e93 100644
--- a/plug-ins/python/Makefile.am
+++ b/plug-ins/python/Makefile.am
@@ -35,7 +35,8 @@ spyro_plus_SCRIPTS = spyro-plus.py
## python-eval.py
if GIMP_UNSTABLE
-## benchmark-foreground-extract.py
+benchmark_foreground_extractdir = $(gimpplugindir)/plug-ins/benchmark-foreground-extract
+benchmark_foreground_extract_SCRIPTS = benchmark-foreground-extract.py
## clothify.py
## shadow_bevel.py
## sphere.py
@@ -53,6 +54,10 @@ EXTRA_DIST = \
py-slice.py \
spyro-plus.py
+if GIMP_UNSTABLE
+EXTRA_DIST += benchmark-foreground-extract.py
+endif
+
# Python interpreter file.
pyinterpdir = $(gimpplugindir)/interpreters
diff --git a/plug-ins/python/benchmark-foreground-extract.py b/plug-ins/python/benchmark-foreground-extract.py
new file mode 100755
index 0000000000..90806a5d9d
--- /dev/null
+++ b/plug-ins/python/benchmark-foreground-extract.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python3
+
+# Foreground Extraction Benchmark
+# Copyright 2005 Sven Neumann <sven gimp org>
+#
+"""
+ This is a from-scratch implementation of the benchmark proposed in
+ "GrabCut": interactive foreground extraction using iterated graph
+ cuts published in the Proceedings of the 2004 SIGGRAPH Conference.
+
+ No guarantee is made that this benchmark produces the same results
+ as the cited benchmark but the goal is that it does. So if you find
+ any bugs or inaccuracies in this code, please let us know.
+
+ The benchmark has been adapted work with the MATTING algorithm,
+ which is (currently) the only
+ implementation of gimp_drawable_foreground_extract(). If other
+ implementations are being added, this benchmark should be changed
+ accordingly.
+
+ You will need a set of test images to run this benchmark, preferably
+ the original set of 50 images. Some of these images are from the
+ Berkeley Segmentation Dataset
+ http://www.cs.berkeley.edu/projects/vision/grouping/segbench/ .
+ See http://www.siox.org/details.html to download trimaps.
+ See https://web.archive.org/web/20050209123253/http://research.microsoft.com/vision/cambridge/segmentation/
+ and download the "Labelling - Lasso" file.
+"""
+# This program 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 <https://www.gnu.org/licenses/>.
+
+import os, re, struct, sys, time
+
+import gi
+gi.require_version('Gimp', '3.0')
+from gi.repository import Gimp
+from gi.repository import GObject
+from gi.repository import GLib
+from gi.repository import Gio
+
+
+def benchmark (procedure, args, data):
+ if args.length() != 3:
+ error = 'Wrong parameters given'
+ return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
+ GLib.Error(error))
+ run_mode = args.index(0)
+ folder = args.index(1)
+ save_output = args.index(2)
+
+ folder = os.path.abspath(os.path.expanduser(folder))
+ if not os.path.exists(folder):
+ error = "Folder '" + folder + "' doesn't exist.\n"
+ return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
+ GLib.Error(error))
+
+ total_unclassified = 0
+ total_misclassified = 0
+ total_time = 0.0
+
+ images = os.path.join(folder, "images")
+ for name in os.listdir(images):
+
+ try:
+ image_display.delete()
+ mask_display.delete()
+ except NameError:
+ pass
+
+ image_name = os.path.join (images, name)
+
+ # Remove suffix, assuming it has three characters
+ name = re.sub(r'\....$', '', name)
+
+ mask_name = os.path.join(folder, "cm_bmp", name + '.png')
+ truth_name = os.path.join(folder, "truth", name + '.bmp')
+
+ image = Gimp.file_load(run_mode, Gio.file_new_for_path(image_name))
+ image_layer = image.get_active_layer()
+
+ mask = Gimp.file_load(run_mode, Gio.file_new_for_path(mask_name))
+ convert_grayscale(mask)
+ mask_layer = mask.get_active_layer()
+
+ truth = Gimp.file_load(run_mode, Gio.file_new_for_path(truth_name))
+ convert_grayscale(truth)
+ truth_layer = truth.get_active_layer()
+
+ unclassified = unclassified_pixels(mask_layer, truth_layer)
+
+ sys.stderr.write(os.path.basename (image_name))
+
+ start = time.time()
+ image_layer.foreground_extract(Gimp.ForegroundExtractMode.MATTING, mask_layer)
+ end = time.time()
+
+ sys.stderr.write(" ")
+
+ # This line was in the gimp 2 implementation, and probably isn't needed anymore.
+ # mask_layer.flush ()
+
+ # Ignore errors when creating image displays;
+ # allows us to be used without a display.
+ try:
+ image_display = Gimp.Display.new(image)
+ mask_display = Gimp.Display.new(mask)
+
+ Gimp.displays_flush()
+ time.sleep(1.0)
+ except:
+ pass
+
+ image.delete()
+
+ misclassified = misclassified_pixels (mask_layer, truth_layer)
+
+ sys.stderr.write("%d %d %.2f%% %.3fs\n" %
+ (unclassified, misclassified,
+ (misclassified * 100.0 / unclassified),
+ end - start))
+
+ total_unclassified += unclassified
+ total_misclassified += misclassified
+ total_time += end - start
+
+ truth.delete()
+
+ if save_output:
+ filename = os.path.join(folder, "output", name + '.png')
+ Gimp.file_save(Gimp.RunMode.NONINTERACTIVE, mask, mask_layer, Gio.file_new_for_path(filename))
+
+ mask.delete()
+
+ # for loop ends
+
+ try:
+ image_display.delete()
+ mask_display.delete()
+ except NameError:
+ pass
+
+ sys.stderr.write("Total: %d %d %.2f%% %.3fs\n" %
+ (total_unclassified, total_misclassified,
+ (total_misclassified * 100.0 / total_unclassified),
+ total_time))
+
+ return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
+
+
+def convert_grayscale(image):
+ if not image.get_effective_color_profile().is_gray():
+ image.convert_grayscale()
+
+
+def unclassified_pixels(mask, truth):
+ (result, mean, std_dev, median, pixels,
+ count, percentile) = mask.histogram(Gimp.HistogramChannel.VALUE, 2/256.0, 254/256.0)
+
+ return count
+
+
+def misclassified_pixels(mask, truth):
+ image = truth.get_image()
+
+ copy = Gimp.Layer.new_from_drawable(mask, image)
+ copy.set_name("Difference")
+ copy.set_mode(Gimp.LayerMode.DIFFERENCE_LEGACY)
+
+ image.insert_layer(copy, None, -1)
+
+ # The assumption made here is that the output of
+ # foreground_extract is a strict black and white mask. The truth
+ # however may contain unclassified pixels. These are considered
+ # unknown, a strict segmentation isn't possible here.
+ #
+ # The result of using the Difference mode as done here is that
+ # pure black pixels in the result can be considered correct.
+ # White pixels are wrong. Gray values were unknown in the truth
+ # and thus are not counted as wrong.
+
+ flat_image = image.flatten()
+ (result, mean, std_dev, median, pixels,
+ count, percentile) = flat_image.histogram(Gimp.HistogramChannel.VALUE, 254/256.0, 1.0)
+
+ return count
+
+
+PROCNAME = "python-fu-benchmark-foreground-extract"
+
+class BenchmarkForegroundExtract(Gimp.PlugIn):
+
+ ## Parameters ##
+ __gproperties__ = {
+ "run-mode": (Gimp.RunMode,
+ "Run mode",
+ "The run mode",
+ Gimp.RunMode.NONINTERACTIVE,
+ GObject.ParamFlags.READWRITE),
+ "image_folder": (str,
+ "Image Folder",
+ "Image Folder",
+ "~/segmentation/msbench/imagedata",
+ GObject.ParamFlags.READWRITE),
+ "save_output": (bool,
+ "Save output images",
+ "Save output images",
+ False,
+ GObject.ParamFlags.READWRITE)
+ }
+
+ ## GimpPlugIn virtual methods ##
+ def do_query_procedures(self):
+ self.set_translation_domain("gimp30-python",
+ Gio.file_new_for_path(Gimp.locale_directory()))
+ return [PROCNAME]
+
+ def do_create_procedure(self, name):
+ procedure = None
+ if name == PROCNAME:
+ procedure = Gimp.Procedure.new(self, name,
+ Gimp.PDBProcType.PLUGIN,
+ benchmark, None)
+ procedure.set_documentation(
+ "Benchmark and regression test for Foreground Extraction",
+ globals()["__doc__"], # This includes the docstring, on the top of the file
+ name)
+ procedure.set_menu_label("Foreground Extraction")
+ procedure.set_attribution("Sven Neumann",
+ "Sven Neumann",
+ "2005")
+ procedure.add_menu_path("<Image>/Filters/Extensions/Benchmark")
+
+ procedure.add_argument_from_property(self, "run-mode")
+ procedure.add_argument_from_property(self, "image_folder")
+ procedure.add_argument_from_property(self, "save_output")
+
+ return procedure
+
+
+Gimp.main(BenchmarkForegroundExtract.__gtype__, sys.argv)
diff --git a/plug-ins/python/meson.build b/plug-ins/python/meson.build
index d45d152bcc..b21cfbda75 100644
--- a/plug-ins/python/meson.build
+++ b/plug-ins/python/meson.build
@@ -19,7 +19,7 @@ plugins = [
if not stable
plugins += [
- # { 'name': 'benchmark-foreground-extract', },
+ { 'name': 'benchmark-foreground-extract' }
# { 'name': 'clothify', },
# { 'name': 'shadow_bevel', },
# { 'name': 'sphere', },
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]