benchmark-foreground-extract.py 6.17 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python

#   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 SIOX algorithm
#   (http://www.siox.org). 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 also http://www.siox.org/details.html for trimaps.
#
#   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 2 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, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


import os, re, struct, sys, time

from gimpfu import *


46
def benchmark (folder, save_output):
47
48
49
50
51
52
53
    folder = os.path.abspath (folder)
    if not os.path.exists (folder):
        gimp.message("Folder '" + folder + "' doesn't exist.\n")
        return;
    
    total_unclassified = 0
    total_misclassified = 0
Sven Neumann's avatar
Sven Neumann committed
54
    total_time = 0.0
55

56
    images = os.path.join (folder, "images")
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    for name in os.listdir (images):

        try:
            gimp.delete (image_display)
            gimp.delete (mask_display)
        except UnboundLocalError:
            pass

        image_name = os.path.join (images, name)

        # FIXME: improve this!
        name = re.sub (r'\.jpg$', '', name)
        name = re.sub (r'\.JPG$', '', name)
        name = re.sub (r'\.bmp$', '', name)

72
73
        mask_name = os.path.join (folder, "cm_bmp", name + '.png')
        truth_name = os.path.join (folder, "truth", name + '.bmp')
74
75
76
77
78

        image = pdb.gimp_file_load (image_name, image_name)
        image_layer = image.active_layer;

        mask = pdb.gimp_file_load (mask_name, mask_name)
79
        convert_grayscale (mask)
80
81
82
        mask_layer = mask.active_layer;

        truth = pdb.gimp_file_load (truth_name, truth_name)
83
84
	convert_grayscale (truth)
        truth_layer = truth.active_layer;
85
86
87

	gimp.tile_cache_ntiles (2 * mask_layer.width / gimp.tile_width () + 1)

88
        unclassified = unclassified_pixels (mask_layer, truth_layer)
89
90
91

        sys.stderr.write (os.path.basename (image_name))

Sven Neumann's avatar
Sven Neumann committed
92
	start = time.time ()
Sven Neumann's avatar
Sven Neumann committed
93
94
95
        pdb.gimp_drawable_foreground_extract (image_layer,
					      FOREGROUND_EXTRACT_SIOX,
					      mask_layer)
Sven Neumann's avatar
Sven Neumann committed
96
	end = time.time ()
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

        sys.stderr.write (" ")

	mask_layer.flush ()

        # Ignore errors when creating image displays;
        # allows us to be used without a display.
        try:
            image_display = pdb.gimp_display_new (image)
            mask_display = pdb.gimp_display_new (mask)

            gimp.displays_flush ()
            time.sleep (1.0)
        except:
            pass

        gimp.delete (image)

115
        misclassified = misclassified_pixels (mask_layer, truth_layer)
116

Sven Neumann's avatar
Sven Neumann committed
117
        sys.stderr.write ("%d %d %.2f%% %.3fs\n" %
118
			  (unclassified, misclassified,
Sven Neumann's avatar
Sven Neumann committed
119
120
			   (misclassified * 100.0 / unclassified),
			   end - start))
121
122
123

	total_unclassified += unclassified
	total_misclassified += misclassified
Sven Neumann's avatar
Sven Neumann committed
124
	total_time += end - start
125
126
127

        gimp.delete (truth)

128
129
130
131
132
133
134
	if save_output:
	    filename = os.path.join (folder, "output", name + '.png')
	    pdb.gimp_file_save (mask, mask_layer, filename, filename)

        gimp.delete (mask)

    # for loop ends
135
136
137
138
139
140
141

    try:
	gimp.delete (image_display)
	gimp.delete (mask_display)
    except UnboundLocalError:
	pass

Sven Neumann's avatar
Sven Neumann committed
142
    sys.stderr.write ("Total: %d %d %.2f%% %.3fs\n" %
143
		      (total_unclassified, total_misclassified,
Sven Neumann's avatar
Sven Neumann committed
144
145
		       (total_misclassified * 100.0 / total_unclassified),
		       total_time))
146

147
148
149
def convert_grayscale (image):
    if image.base_type != GRAY:
	pdb.gimp_image_convert_grayscale (image)
150

151
152
153
154

def unclassified_pixels (mask, truth):
    (mean, std_dev, median, pixels,
     count, percentile) = pdb.gimp_histogram (mask, HISTOGRAM_VALUE, 1, 254)
155
156
157
158

    return count


159
def misclassified_pixels (mask, truth):
160
161
162
163
164
165
166
167
    image = truth.image

    copy = pdb.gimp_layer_new_from_drawable (mask, image)
    copy.name = "Difference"
    copy.mode = DIFFERENCE_MODE

    image.add_layer (copy, -1)

168
169
170
171
172
173
174
175
176
177
178
179
180
    # 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.

    (mean, std_dev, median, pixels,
     count, percentile) = pdb.gimp_histogram (image.flatten (),
					      HISTOGRAM_VALUE, 255, 255)
181
182
183
184
185

    return count


register (
Sven Neumann's avatar
Sven Neumann committed
186
    "benchmark_foreground_extract",
187
188
189
190
191
192
193
    "Foreground Extraction Benchmark",
    "Foreground Extraction Benchmark",
    "Sven Neumann",
    "Sven Neumann",
    "2005",
    "<Toolbox>/Xtns/Benchmark/Foreground Extraction",
    "",
194
195
196
    [ (PF_FILE,   "image_folder", "Image folder",
                  "~/segmentation/msbench/imagedata"),
      (PF_TOGGLE, "save_output",  "Save output images", False) ],
197
198
199
200
    [],
    benchmark)

main ()