[gegl] global-matting: resynced with rggjan's repo
- From: Ãyvind KolÃs <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] global-matting: resynced with rggjan's repo
- Date: Mon, 2 Apr 2012 21:17:43 +0000 (UTC)
commit 376e3fef0cd33039f710508f67bded202f542583
Author: Jan RÃegg <rggjan gmail com>
Date: Mon Mar 26 21:38:43 2012 +0200
global-matting: resynced with rggjan's repo
! Changed matting reference image
! Fixed Copyright
+ Added levels to gegl chant for matting
+ Better adaption to gimp HACKORDNUNG
c Adapted user message
c Cleanup
- Removed unused function
! Fixed nasty memory bug
operations/common/matting-global.c | 542 ++++++++++-------------
tests/compositions/matting-global.xml | 7 +-
tests/compositions/reference/matting-global.png | Bin 52292 -> 1241155 bytes
3 files changed, 236 insertions(+), 313 deletions(-)
---
diff --git a/operations/common/matting-global.c b/operations/common/matting-global.c
index 94ec815..802ce0a 100644
--- a/operations/common/matting-global.c
+++ b/operations/common/matting-global.c
@@ -13,66 +13,51 @@
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
*
- * Copyright 2010 Danny Robson <danny blubinc net>
- * Based off 2006 Anat Levin
+ * Copyright 2011 Jan RÃegg <rggjan gmail com>
*/
#include "config.h"
#include <glib/gi18n-lib.h>
+#include <math.h>
#ifdef GEGL_CHANT_PROPERTIES
-gegl_chant_int (epsilon, _("Epsilon"),
- -9, -1, -6,
- _("Log of the error weighting"))
-gegl_chant_int (radius, _("Radius"),
- 1, 3, 1,
- _("Radius of the processing window"))
-gegl_chant_double (threshold, _("Threshold"),
- 0.0, 0.1, 0.02,
- _("Alpha threshold for multilevel processing"))
-gegl_chant_double (lambda, _("Lambda"),
- 0.0, 100.0, 100.0, _("Trimap influence factor"))
-gegl_chant_int (levels, _("Levels"),
- 0, 8, 4,
- _("Number of downsampled levels to use"))
-gegl_chant_int (active_levels, _("Active Levels"),
- 0, 8, 2,
- _("Number of levels to perform solving"))
+gegl_chant_int (iterations, _("Iterations"), 1, G_MAXINT, 10,
+ _("Number of iterations"))
+
#else
#define GEGL_CHANT_TYPE_COMPOSER
-#define GEGL_CHANT_C_FILE "matting-global.c"
+#define GEGL_CHANT_C_FILE "matting-global.c"
#include "gegl-chant.h"
#include "gegl-debug.h"
-#include <stdlib.h>
-
-#include <stdio.h>
-#include <math.h>
#define max(a,b) \
- ({ __typeof__ (a) _a = (a); \
- __typeof__ (b) _b = (b); \
- _a > _b ? _a : _b; })
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
#define min(a,b) \
- ({ __typeof__ (a) _a = (a); \
- __typeof__ (b) _b = (b); \
- _a > _b ? _b : _a; })
-
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _b : _a; })
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#define ASSERT(condition) \
- if(unlikely(!(condition))) { \
- printf("Error at line %i\n", __LINE__); \
- exit(1);\
- }
+ if(unlikely(!(condition))) { \
+ printf("Error at line %i\n", __LINE__); \
+ exit(1);\
+ }
+// Shortcut for doing things in all three channels
#define COLOR(expr) {int c; for (c = 0; c < 3; c++) { expr; }}
+// Save all important memories to output image buffer to save memory
+#define FG_DISTANCE(output, index) (output[index*4+0])
+#define BG_DISTANCE(output, index) (output[index*4+1])
#define FG_INDEX(output, index) (*((int*)(&output[index*4+2])))
#define BG_INDEX(output, index) (*((int*)(&output[index*4+3])))
@@ -89,7 +74,8 @@ static const gchar *FORMAT_INPUT = "R'G'B' float";
static const gchar *FORMAT_OUTPUT = "R'G'B'A float";
static void
-matting_prepare (GeglOperation *operation) {
+matting_prepare (GeglOperation *operation)
+{
gegl_operation_set_format (operation, "input", babl_format (FORMAT_INPUT));
gegl_operation_set_format (operation, "aux", babl_format (FORMAT_AUX));
gegl_operation_set_format (operation, "output", babl_format (FORMAT_OUTPUT));
@@ -98,7 +84,8 @@ matting_prepare (GeglOperation *operation) {
static GeglRectangle
matting_get_required_for_output (GeglOperation *operation,
const gchar *input_pad,
- const GeglRectangle *roi) {
+ const GeglRectangle *roi)
+{
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation,
"input");
return result;
@@ -106,7 +93,8 @@ matting_get_required_for_output (GeglOperation *operation,
static GeglRectangle
matting_get_cached_region (GeglOperation * operation,
- const GeglRectangle * roi) {
+ const GeglRectangle * roi)
+{
return *gegl_operation_source_get_bounding_box (operation, "input");
}
@@ -123,40 +111,47 @@ typedef struct {
} ColorSample;
#define SQUARE(x) ((x)*(x))
-static inline float get_alpha (Color F, Color B, Color I) {
+static inline float get_alpha (Color F, Color B, Color I)
+{
int c;
float result = 0;
float div = 0;
- for (c = 0; c < 3; c++) {
- result += (I[c] - B[c]) * (F[c] - B[c]);
- div += SQUARE(F[c] - B[c]);
- }
+ for (c = 0; c < 3; c++)
+ {
+ result += (I[c] - B[c]) * (F[c] - B[c]);
+ div += SQUARE(F[c] - B[c]);
+ }
return min(max(result / div, 0), 1);
}
-static inline float get_color_cost (Color F, Color B, Color I, float alpha) {
+static inline float get_color_cost (Color F, Color B, Color I, float alpha)
+{
int c;
float result = 0;
- for (c = 0; c < 3; c++) {
- result += SQUARE(I[c] - (alpha * F[c] + (1 - alpha) * B[c]));
- }
+ for (c = 0; c < 3; c++)
+ {
+ result += SQUARE(I[c] - (alpha * F[c] + (1 - alpha) * B[c]));
+ }
// TODO(rggjan): Remove sqrt to get faster code?
// TODO(rggjan): Remove 255
return sqrt(result) * 255;
}
-static inline int get_distance_squared(ColorSample s, int x, int y) {
+static inline int get_distance_squared(ColorSample s, int x, int y)
+{
return SQUARE(s.pos.x - x) + SQUARE(s.pos.y - y);
}
-static inline float get_distance (ColorSample s, int x, int y) {
+static inline float get_distance (ColorSample s, int x, int y)
+{
// TODO(rggjan): Remove sqrt to get faster code?
return sqrt(get_distance_squared(s, x, y));
}
-static inline float get_distance_cost (ColorSample s, int x, int y, float *best_distance) {
+static inline float get_distance_cost (ColorSample s, int x, int y, float *best_distance)
+{
float new_distance = get_distance(s, x, y);
if (new_distance < *best_distance)
@@ -165,148 +160,61 @@ static inline float get_distance_cost (ColorSample s, int x, int y, float *best_
return new_distance / *best_distance;
}
-static inline float get_cost (ColorSample foreground, ColorSample background, Color I, int x, int y, float *best_fg_distance, float *best_bg_distance, Color avgf, Color avgb, float devf, float devb) {
- float cost = 0;
- //printf("I: %f/%f/%f at %i,%i\n", I[0], I[1], I[2], x, y);
- //printf("best: %f/%f\n", best_fg_distance, best_bg_distance);
- //printf("F: %f/%f/%f at %i,%i\n", foreground.color[0], foreground.color[1], foreground.color[2], foreground.pos[0], foreground.pos[1]);
- //printf("B: %f/%f/%f at %i,%i\n", background.color[0], background.color[1], background.color[2], background.pos[0], background.pos[1]);
-
-// COLOR(cost += SQUARE(foreground.color[c] - avgf[c]) / devf);
-// COLOR(cost += SQUARE(background.color[c] - avgb[c]) / devb);
- //cost *= 255;
-
- cost += get_color_cost(foreground.color, background.color, I,
- get_alpha(foreground.color, background.color, I));
- //printf("cost1: %f\n", cost);
+static inline float get_cost (ColorSample foreground, ColorSample background, Color I, int x, int y, float *best_fg_distance, float *best_bg_distance)
+{
+ float cost = get_color_cost(foreground.color, background.color, I,
+ get_alpha(foreground.color, background.color, I));
cost += get_distance_cost(foreground, x, y, best_fg_distance);
- //printf("costf: %f\n", get_distance_cost(foreground, x, y, best_fg_distance));
cost += get_distance_cost(background, x, y, best_bg_distance);
- //printf("costb: %f\n", get_distance_cost(foreground, x, y, best_bg_distance));
return cost;
}
-static inline void get_average (GArray *foreground_samples, GArray *background_samples, gfloat *input, gfloat *output, int x, int y, int w, int h, float *avgf, float *avgb, float *devf, float *devb) {
- int xdiff, ydiff;
- int fg_count = 0;
- int bg_count = 0;
-
-/* COLOR(avgf[c] = 0);
- COLOR(avgb[c] = 0);
- *devf = 0;
- *devb = 0;*/
-
- // Get average
- for (ydiff = -1; ydiff <= 1; ydiff++) {
- // Borders
- if (y+ydiff < 0 || y+ydiff >= h)
- continue;
- for (xdiff = -1; xdiff <= 1; xdiff++) {
- int i = (y + ydiff) * w + x + xdiff;
- // Borders
- if (x+xdiff < 0 || x+xdiff >= w)
- continue;
-
- // Distance to background != 0
- if (output[i * 4 + 1] != 0) {
- ColorSample foreground = g_array_index(foreground_samples, ColorSample, FG_INDEX(output, i));
- COLOR(avgf[c] += foreground.color[c]);
- fg_count++;
- }
-
- // Distance to foreground != 0
- if (output[i * 4 + 0] != 0) {
- ColorSample background = g_array_index(background_samples, ColorSample, BG_INDEX(output, i));
- COLOR(avgb[c] += background.color[c]);
- bg_count++;
- }
- }
- }
-
- ASSERT(fg_count > 0);
- ASSERT(bg_count > 0);
-
- COLOR(avgf[c] /= fg_count);
- COLOR(avgb[c] /= bg_count);
-
-// COLOR(printf("%f ", avgf[c]));
-// printf("\n\n");
-
- // get deviation
- for (ydiff = -1; ydiff <= 1; ydiff++) {
- // Borders
- if (y+ydiff < 0 || y+ydiff >= h)
- continue;
- for (xdiff = -1; xdiff <= 1; xdiff++) {
- int i = (y + ydiff) * w + x + xdiff;
- // Borders
- if (x+xdiff < 0 || x+xdiff >= w)
- continue;
-
- // Distance to background != 0
- if (output[i * 4 + 1] != 0) {
- ColorSample foreground = g_array_index(foreground_samples, ColorSample, FG_INDEX(output, i));
- COLOR(*devf += SQUARE(avgf[c] - foreground.color[c]) / fg_count);
- }
-
- // Distance to foreground != 0
- if (output[i * 4 + 0] != 0) {
- ColorSample background = g_array_index(background_samples, ColorSample, BG_INDEX(output, i));
- COLOR(*devb += SQUARE(avgb[c] - background.color[c]) / bg_count);
- }
- }
- }
-}
-
static inline void do_propagate(GArray *foreground_samples, GArray *background_samples, gfloat *input, gfloat *output, guchar *trimap, int x, int y, int w, int h) {
int index_orig = y * w + x;
int index_new;
- Color avgf = {0, 0, 0};
- Color avgb = {0, 0, 0};
-
- float devf = 0;
- float devb = 0;
-
- get_average(foreground_samples, background_samples, input, output, x, y, w, h, avgf, avgb, &devf, &devb);
-
- if (!(trimap[index_orig] == 0 || trimap[index_orig] == 255)) {
- int xdiff, ydiff;
- float best_cost = FLT_MAX;
- float *best_fg_distance = &output[index_orig * 4 + 0];
- float *best_bg_distance = &output[index_orig * 4 + 1];
-
- for (ydiff = -1; ydiff <= 1; ydiff++) {
- // Borders
- if (y+ydiff < 0 || y+ydiff >= h)
- continue;
- for (xdiff = -1; xdiff <= 1; xdiff++) {
- // Borders
- if (x+xdiff < 0 || x+xdiff >= w)
- continue;
-
- index_new = (y + ydiff) * w + (x + xdiff);
-
- if (!(trimap[index_new] == 0 || trimap[index_new] == 255)) {
- int fi = FG_INDEX(output, index_new);
- int bi = BG_INDEX(output, index_new);
-
- ColorSample foreground = g_array_index(foreground_samples, ColorSample, fi);
- ColorSample background = g_array_index(background_samples, ColorSample, bi);
+ if (!(trimap[index_orig] == 0 || trimap[index_orig] == 255))
+ {
+ int xdiff, ydiff;
+ float best_cost = FLT_MAX;
+ float *best_fg_distance = &output[index_orig * 4 + 0];
+ float *best_bg_distance = &output[index_orig * 4 + 1];
- float cost = get_cost(foreground, background, &input[index_orig * 3], x, y, best_fg_distance, best_bg_distance, avgf, avgb, devf, devb);
- if (cost < best_cost) {
- FG_INDEX(output, index_orig) = fi;
- BG_INDEX(output, index_orig) = bi;
- best_cost = cost;
- }
+ for (ydiff = -1; ydiff <= 1; ydiff++)
+ {
+ // Borders
+ if (y+ydiff < 0 || y+ydiff >= h)
+ continue;
+ for (xdiff = -1; xdiff <= 1; xdiff++)
+ {
+ // Borders
+ if (x+xdiff < 0 || x+xdiff >= w)
+ continue;
+
+ index_new = (y + ydiff) * w + (x + xdiff);
+
+ if (!(trimap[index_new] == 0 || trimap[index_new] == 255))
+ {
+ int fi = FG_INDEX(output, index_new);
+ int bi = BG_INDEX(output, index_new);
+
+ ColorSample foreground = g_array_index(foreground_samples, ColorSample, fi);
+ ColorSample background = g_array_index(background_samples, ColorSample, bi);
+
+ float cost = get_cost(foreground, background, &input[index_orig * 3], x, y, best_fg_distance, best_bg_distance);
+ if (cost < best_cost)
+ {
+ FG_INDEX(output, index_orig) = fi;
+ BG_INDEX(output, index_orig) = bi;
+ best_cost = cost;
+ }
+ }
+ }
}
- }
}
- }
}
-static inline void do_random_search(GArray *foreground_samples, GArray *background_samples, gfloat *input, gfloat *output, int x, int y, int w, int h) {
+static inline void do_random_search(GArray *foreground_samples, GArray *background_samples, gfloat *input, gfloat *output, int x, int y, int w) {
int dist_f = foreground_samples->len;
int dist_b = background_samples->len;
int index = y * w + x;
@@ -317,53 +225,52 @@ static inline void do_random_search(GArray *foreground_samples, GArray *backgrou
int start_fi = best_fi;
int start_bi = best_bi;
- Color avgf = {0, 0, 0};
- Color avgb = {0, 0, 0};
-
- float devf = 0;
- float devb = 0;
-
// Get current best result
- float *best_fg_distance = &output[index * 4 + 0];
- float *best_bg_distance = &output[index * 4 + 1];
+ float *best_fg_distance = &FG_DISTANCE(output, index);
+ float *best_bg_distance = &BG_DISTANCE(output, index);
ColorSample foreground = g_array_index(foreground_samples, ColorSample, best_fi);
ColorSample background = g_array_index(background_samples, ColorSample, best_bi);
- float best_cost;
-
- // Get average cost
- get_average(foreground_samples, background_samples, input, output, x, y, w, h, avgf, avgb, &devf, &devb);
- best_cost = get_cost(foreground, background, &input[index * 3], x, y, best_fg_distance, best_bg_distance, avgf, avgb, devf, devb);
-
- //printf("Got best cost: %i\n", best_cost);
- while (dist_f > 0 && dist_b > 0) {
- int fi, bi;
- float cost;
- ColorSample background, foreground;
- fi = (start_fi + (rand() % (dist_f * 2 + 1)) - dist_f) % foreground_samples->len;
- bi = (start_bi + (rand() % (dist_b * 2 + 1)) - dist_b) % background_samples->len;
- background = g_array_index(background_samples, ColorSample, bi);
- foreground = g_array_index(foreground_samples, ColorSample, fi);
- cost = get_cost(foreground, background, &input[index * 3], x, y, best_fg_distance, best_bg_distance, avgf, avgb, devf, devb);
- if (cost < best_cost) {
- best_cost = cost;
- best_fi = fi;
- best_bi = bi;
+ // Get cost
+ float best_cost = get_cost(foreground, background, &input[index * 3], x, y, best_fg_distance, best_bg_distance);
+
+ while (dist_f > 0 || dist_b > 0)
+ {
+ // Get new indices to check
+ int fl = foreground_samples->len;
+ int bl = background_samples->len;
+ int fi = (start_fi + (rand() % (dist_f * 2 + 1)) + fl - dist_f) % fl;
+ int bi = (start_bi + (rand() % (dist_b * 2 + 1)) + fl - dist_b) % bl;
+
+ ColorSample foreground = g_array_index(foreground_samples, ColorSample, fi);
+ ColorSample background = g_array_index(background_samples, ColorSample, bi);
+
+ float cost = get_cost(foreground, background, &input[index * 3], x, y, best_fg_distance, best_bg_distance);
+
+ if (cost < best_cost)
+ {
+ best_cost = cost;
+ best_fi = fi;
+ best_bi = bi;
+ }
+ dist_f /= 2;
+ dist_b /= 2;
}
- dist_f /= 2;
- dist_b /= 2;
- }
FG_INDEX(output, index) = best_fi;
BG_INDEX(output, index) = best_bi;
}
-static gint color_compare(gconstpointer p1, gconstpointer p2) {
+// Compare color intensities
+static gint color_compare(gconstpointer p1, gconstpointer p2)
+{
ColorSample *s1 = (ColorSample*) p1;
ColorSample *s2 = (ColorSample*) p2;
+
float sum1 = s1->color[0] + s1->color[1] + s1->color[2];
float sum2 = s2->color[0] + s2->color[1] + s2->color[2];
+
return ((sum1 > sum2) - (sum2 > sum1));
}
@@ -376,7 +283,7 @@ matting_process (GeglOperation *operation,
int level)
{
- //const GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ const GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
gfloat *input = NULL;
guchar *trimap = NULL;
gfloat *output = NULL;
@@ -412,130 +319,151 @@ matting_process (GeglOperation *operation,
unknown_positions = g_array_new(FALSE, FALSE, sizeof(Position));
// Get mask
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- int mask = trimap[y * w + x];
- for (ydiff = -1; ydiff <= 1; ydiff++) {
- // Borders
- if (y+ydiff < 0 || y+ydiff >= h)
- continue;
-
- for (xdiff = -1; xdiff <= 1; xdiff++) {
- // Borders
- if (x+xdiff < 0 || x+xdiff >= w)
- continue;
-
- neighbour_mask = trimap[(y + ydiff) * w + x + xdiff];
- if (neighbour_mask != mask && (mask == 0 || mask == 255)) {
- int index = y*w+x;
- ColorSample s;
- s.pos.x = x;
- s.pos.y = y;
- COLOR(s.color[c] = input[index * 3 + c])
-
- if (mask == 255) {
- g_array_append_val(foreground_samples, s);
- output[index*4+0] = 0;
- output[index*4+1] = FLT_MAX;
- } else {
- g_array_append_val(background_samples, s);
- output[index*4+0] = FLT_MAX;
- output[index*4+1] = 0;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int mask = trimap[y * w + x];
+ for (ydiff = -1; ydiff <= 1; ydiff++)
+ {
+ // Borders
+ if (y+ydiff < 0 || y+ydiff >= h)
+ continue;
+
+ for (xdiff = -1; xdiff <= 1; xdiff++)
+ {
+ // Borders
+ if (x+xdiff < 0 || x+xdiff >= w)
+ continue;
+
+ neighbour_mask = trimap[(y + ydiff) * w + x + xdiff];
+ if (neighbour_mask != mask && (mask == 0 || mask == 255))
+ {
+ int index = y*w+x;
+ ColorSample s;
+ s.pos.x = x;
+ s.pos.y = y;
+ COLOR(s.color[c] = input[index*3 + c]);
+
+ if (mask == 255)
+ {
+ g_array_append_val(foreground_samples, s);
+ FG_DISTANCE(output, index) = 0;
+ BG_DISTANCE(output, index) = FLT_MAX;
+ }
+ else
+ {
+ g_array_append_val(background_samples, s);
+ FG_DISTANCE(output, index) = 0;
+ BG_DISTANCE(output, index) = FLT_MAX;
+ }
+
+ // Go to next pixel
+ xdiff = 1;
+ ydiff = 1;
+ }
+ }
}
-
- // Go to next pixel
- xdiff = 1;
- ydiff = 1;
- }
}
- }
}
- }
- // Initialize
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- int index = y * w + x;
-
- if (trimap[index] != 0 && trimap[index] != 255) {
- Position p;
- p.x = x;
- p.y = y;
- g_array_append_val(unknown_positions, p);
- output[index * 4 + 0] = FLT_MAX;
- output[index * 4 + 1] = FLT_MAX;
- FG_INDEX(output, index) = rand() % foreground_samples->len;
- BG_INDEX(output, index) = rand() % background_samples->len;
- }
+ // Initialize unknowns
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int index = y * w + x;
+
+ if (trimap[index] != 0 && trimap[index] != 255)
+ {
+ Position p;
+ p.x = x;
+ p.y = y;
+ g_array_append_val(unknown_positions, p);
+ FG_DISTANCE(output, index) = FLT_MAX;
+ BG_DISTANCE(output, index) = FLT_MAX;
+ FG_INDEX(output, index) = rand() % foreground_samples->len;
+ BG_INDEX(output, index) = rand() % background_samples->len;
+ }
+ }
}
- }
g_array_sort(foreground_samples, color_compare);
g_array_sort(background_samples, color_compare);
- for (i = 0; i < 10; i++) {
- int j;
+ // Do real iterations
+ for (i = 0; i < o->iterations; i++)
+ {
+ unsigned j;
- printf("Iteration %i\n", i);
+ GEGL_NOTE (GEGL_DEBUG_PROCESS, "Iteration %i", i);
- for (j=0; j<unknown_positions->len; j++) {
- Position p = g_array_index(unknown_positions, Position, j);
- int x = p.x;
- int y = p.y;
- do_random_search(foreground_samples, background_samples, input, output, x, y, w, h);
- }
+ for (j=0; j<unknown_positions->len; j++)
+ {
+ Position p = g_array_index(unknown_positions, Position, j);
+ do_random_search(foreground_samples, background_samples, input, output, p.x, p.y, w);
+ }
- for (j=0; j<unknown_positions->len; j++) {
- Position p = g_array_index(unknown_positions, Position, j);
- int x = p.x;
- int y = p.y;
- do_propagate(foreground_samples, background_samples, input, output, trimap, x, y, w, h);
+ for (j=0; j<unknown_positions->len; j++)
+ {
+ Position p = g_array_index(unknown_positions, Position, j);
+ do_propagate(foreground_samples, background_samples, input, output, trimap, p.x, p.y, w, h);
+ }
}
-
- }
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- int index = y * w + x;
- if (trimap[index] == 0 || trimap[index] == 255) {
- // Use known values
- output[index * 4 + 0] = input[index * 3 + 0];
- output[index * 4 + 1] = input[index * 3 + 1];
- output[index * 4 + 2] = input[index * 3 + 2];
-
- if (trimap[index] == 0) {
- output[index * 4 + 3] = 0;
- } else if (trimap[index] == 255) {
- output[index * 4 + 3] = 1;
- }
- } else {
- int c;
- ColorSample background, foreground;
- foreground = g_array_index(foreground_samples, ColorSample, FG_INDEX(output, index));
- background = g_array_index(background_samples, ColorSample, BG_INDEX(output, index));
+ // Fill results in
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int index = y * w + x;
+ if (trimap[index] == 0 || trimap[index] == 255)
+ {
+ // Use known values
+ output[index * 4 + 0] = input[index * 3 + 0];
+ output[index * 4 + 1] = input[index * 3 + 1];
+ output[index * 4 + 2] = input[index * 3 + 2];
+
+ if (trimap[index] == 0)
+ {
+ output[index * 4 + 3] = 0;
+ }
+ else if (trimap[index] == 255)
+ {
+ output[index * 4 + 3] = 1;
+ }
+ }
+ else
+ {
+ ColorSample background, foreground;
+ foreground = g_array_index(foreground_samples, ColorSample, FG_INDEX(output, index));
+ background = g_array_index(background_samples, ColorSample, BG_INDEX(output, index));
- output[index * 4 + 3] = get_alpha(foreground.color, background.color, &input[index * 3]);
+ output[index * 4 + 3] = get_alpha(foreground.color, background.color, &input[index * 3]);
- for (c = 0; c < 3; c++) {
- output[index * 4 + c] = foreground.color[c];
+ COLOR(output[index * 4 + c] = foreground.color[c]);
+ }
}
- }
}
- }
+ // Save to buffer
gegl_buffer_set (output_buf, result, 0, babl_format (FORMAT_OUTPUT), output,
GEGL_AUTO_ROWSTRIDE);
success = TRUE;
+
+ // Free memory
g_free (input);
g_free (trimap);
g_free (output);
g_array_free(foreground_samples, FALSE);
g_array_free(background_samples, FALSE);
g_array_free(unknown_positions, FALSE);
+
return success;
}
-static void gegl_chant_class_init (GeglChantClass *klass) {
+static void gegl_chant_class_init (GeglChantClass *klass)
+{
GeglOperationClass *operation_class;
GeglOperationComposerClass *composer_class;
@@ -551,9 +479,9 @@ static void gegl_chant_class_init (GeglChantClass *klass) {
"name" , "gegl:matting-global",
"categories" , "misc",
"description",
- _("Given a sparse user supplied tri-map and an input image, create a "
- "foreground alpha mat. Set white as selected, black as unselected, "
- "for the tri-map."),
+ _("Given a sparse user supplied tri-map and an input image, create a "
+ "foreground alpha matte. Set white as foreground, black as background "
+ "for the tri-map. Everything else will be treated as unknown and filled in."),
NULL);
}
#endif
diff --git a/tests/compositions/matting-global.xml b/tests/compositions/matting-global.xml
index 88ed5db..77c8205 100644
--- a/tests/compositions/matting-global.xml
+++ b/tests/compositions/matting-global.xml
@@ -1,11 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<gegl>
- <node operation='gegl:matting-global'>
- <params>
- <param name='levels'>1</param>
- <param name='active_levels'>1</param>
- </params>
-
+ <node operation='gegl:matting-global' iterations='10'>
<node operation='gegl:load'>
<params>
<param name='path'>data/matting-global_scribble.png</param>
diff --git a/tests/compositions/reference/matting-global.png b/tests/compositions/reference/matting-global.png
index f367c08..7beac95 100644
Binary files a/tests/compositions/reference/matting-global.png and b/tests/compositions/reference/matting-global.png differ
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]