|
Packit Service |
2781ba |
/* This file is an image processing operation for GEGL
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2011 Jan Rüegg <rggjan@gmail.com>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
#include <glib/gi18n-lib.h>
|
|
Packit Service |
2781ba |
#include <math.h>
|
|
Packit Service |
df0201 |
#include <stdlib.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_chant_int (iterations, _("Iterations"), 1, G_MAXINT, 10,
|
|
Packit Service |
2781ba |
_("Number of iterations"))
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#else
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_TYPE_COMPOSER
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_C_FILE "matting-global.c"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl-chant.h"
|
|
Packit Service |
2781ba |
#include "gegl-debug.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define max(a,b) \
|
|
Packit Service |
2781ba |
({ __typeof__ (a) _a = (a); \
|
|
Packit Service |
2781ba |
__typeof__ (b) _b = (b); \
|
|
Packit Service |
2781ba |
_a > _b ? _a : _b; })
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define min(a,b) \
|
|
Packit Service |
2781ba |
({ __typeof__ (a) _a = (a); \
|
|
Packit Service |
2781ba |
__typeof__ (b) _b = (b); \
|
|
Packit Service |
2781ba |
_a > _b ? _b : _a; })
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define likely(x) __builtin_expect((x),1)
|
|
Packit Service |
2781ba |
#define unlikely(x) __builtin_expect((x),0)
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define ASSERT(condition) \
|
|
Packit Service |
2781ba |
if(unlikely(!(condition))) { \
|
|
Packit Service |
2781ba |
printf("Error at line %i\n", __LINE__); \
|
|
Packit Service |
2781ba |
exit(1);\
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Shortcut for doing things in all three channels
|
|
Packit Service |
2781ba |
#define COLOR(expr) {int c; for (c = 0; c < 3; c++) { expr; }}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Save all important memories to output image buffer to save memory
|
|
Packit Service |
2781ba |
#define FG_DISTANCE(output, index) (output[index*4+0])
|
|
Packit Service |
2781ba |
#define BG_DISTANCE(output, index) (output[index*4+1])
|
|
Packit Service |
2781ba |
#define FG_INDEX(output, index) (*((int*)(&output[index*4+2])))
|
|
Packit Service |
2781ba |
#define BG_INDEX(output, index) (*((int*)(&output[index*4+3])))
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* We don't use the babl_format_get_n_components function for these values,
|
|
Packit Service |
2781ba |
* as literal constants can be used for stack allocation of array sizes. They
|
|
Packit Service |
2781ba |
* are double checked in matting_process.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
#define COMPONENTS_AUX 1
|
|
Packit Service |
2781ba |
#define COMPONENTS_INPUT 3
|
|
Packit Service |
2781ba |
#define COMPONENTS_OUTPUT 4
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static const gchar *FORMAT_AUX = "Y u8";
|
|
Packit Service |
2781ba |
static const gchar *FORMAT_INPUT = "R'G'B' float";
|
|
Packit Service |
2781ba |
static const gchar *FORMAT_OUTPUT = "R'G'B'A float";
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
matting_prepare (GeglOperation *operation)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "input", babl_format (FORMAT_INPUT));
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "aux", babl_format (FORMAT_AUX));
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "output", babl_format (FORMAT_OUTPUT));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglRectangle
|
|
Packit Service |
2781ba |
matting_get_required_for_output (GeglOperation *operation,
|
|
Packit Service |
2781ba |
const gchar *input_pad,
|
|
Packit Service |
2781ba |
const GeglRectangle *roi)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation,
|
|
Packit Service |
2781ba |
"input");
|
|
Packit Service |
2781ba |
return result;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglRectangle
|
|
Packit Service |
2781ba |
matting_get_cached_region (GeglOperation * operation,
|
|
Packit Service |
2781ba |
const GeglRectangle * roi)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return *gegl_operation_source_get_bounding_box (operation, "input");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef float Color[3];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef struct {
|
|
Packit Service |
2781ba |
int x;
|
|
Packit Service |
2781ba |
int y;
|
|
Packit Service |
2781ba |
} Position;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef struct {
|
|
Packit Service |
2781ba |
Color color;
|
|
Packit Service |
2781ba |
Position pos;
|
|
Packit Service |
2781ba |
} ColorSample;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define SQUARE(x) ((x)*(x))
|
|
Packit Service |
2781ba |
static inline float get_alpha (Color F, Color B, Color I)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int c;
|
|
Packit Service |
2781ba |
float result = 0;
|
|
Packit Service |
2781ba |
float div = 0;
|
|
Packit Service |
2781ba |
for (c = 0; c < 3; c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
result += (I[c] - B[c]) * (F[c] - B[c]);
|
|
Packit Service |
2781ba |
div += SQUARE(F[c] - B[c]);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return min(max(result / div, 0), 1);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline float get_color_cost (Color F, Color B, Color I, float alpha)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int c;
|
|
Packit Service |
2781ba |
float result = 0;
|
|
Packit Service |
2781ba |
for (c = 0; c < 3; c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
result += SQUARE(I[c] - (alpha * F[c] + (1 - alpha) * B[c]));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// TODO(rggjan): Remove sqrt to get faster code?
|
|
Packit Service |
2781ba |
// TODO(rggjan): Remove 255
|
|
Packit Service |
2781ba |
return sqrt(result) * 255;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline int get_distance_squared(ColorSample s, int x, int y)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return SQUARE(s.pos.x - x) + SQUARE(s.pos.y - y);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline float get_distance (ColorSample s, int x, int y)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// TODO(rggjan): Remove sqrt to get faster code?
|
|
Packit Service |
2781ba |
return sqrt(get_distance_squared(s, x, y));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline float get_distance_cost (ColorSample s, int x, int y, float *best_distance)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
float new_distance = get_distance(s, x, y);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (new_distance < *best_distance)
|
|
Packit Service |
2781ba |
*best_distance = new_distance;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return new_distance / *best_distance;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline float get_cost (ColorSample foreground, ColorSample background, Color I, int x, int y, float *best_fg_distance, float *best_bg_distance)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
float cost = get_color_cost(foreground.color, background.color, I,
|
|
Packit Service |
2781ba |
get_alpha(foreground.color, background.color, I));
|
|
Packit Service |
2781ba |
cost += get_distance_cost(foreground, x, y, best_fg_distance);
|
|
Packit Service |
2781ba |
cost += get_distance_cost(background, x, y, best_bg_distance);
|
|
Packit Service |
2781ba |
return cost;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
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) {
|
|
Packit Service |
2781ba |
int index_orig = y * w + x;
|
|
Packit Service |
2781ba |
int index_new;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!(trimap[index_orig] == 0 || trimap[index_orig] == 255))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int xdiff, ydiff;
|
|
Packit Service |
2781ba |
float best_cost = FLT_MAX;
|
|
Packit Service |
2781ba |
float *best_fg_distance = &output[index_orig * 4 + 0];
|
|
Packit Service |
2781ba |
float *best_bg_distance = &output[index_orig * 4 + 1];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (ydiff = -1; ydiff <= 1; ydiff++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Borders
|
|
Packit Service |
2781ba |
if (y+ydiff < 0 || y+ydiff >= h)
|
|
Packit Service |
2781ba |
continue;
|
|
Packit Service |
2781ba |
for (xdiff = -1; xdiff <= 1; xdiff++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Borders
|
|
Packit Service |
2781ba |
if (x+xdiff < 0 || x+xdiff >= w)
|
|
Packit Service |
2781ba |
continue;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
index_new = (y + ydiff) * w + (x + xdiff);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!(trimap[index_new] == 0 || trimap[index_new] == 255))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int fi = FG_INDEX(output, index_new);
|
|
Packit Service |
2781ba |
int bi = BG_INDEX(output, index_new);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ColorSample foreground = g_array_index(foreground_samples, ColorSample, fi);
|
|
Packit Service |
2781ba |
ColorSample background = g_array_index(background_samples, ColorSample, bi);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
float cost = get_cost(foreground, background, &input[index_orig * 3], x, y, best_fg_distance, best_bg_distance);
|
|
Packit Service |
2781ba |
if (cost < best_cost)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
FG_INDEX(output, index_orig) = fi;
|
|
Packit Service |
2781ba |
BG_INDEX(output, index_orig) = bi;
|
|
Packit Service |
2781ba |
best_cost = cost;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void do_random_search(GArray *foreground_samples, GArray *background_samples, gfloat *input, gfloat *output, int x, int y, int w) {
|
|
Packit Service |
2781ba |
int dist_f = foreground_samples->len;
|
|
Packit Service |
2781ba |
int dist_b = background_samples->len;
|
|
Packit Service |
2781ba |
int index = y * w + x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
int best_fi = FG_INDEX(output, index);
|
|
Packit Service |
2781ba |
int best_bi = BG_INDEX(output, index);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
int start_fi = best_fi;
|
|
Packit Service |
2781ba |
int start_bi = best_bi;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Get current best result
|
|
Packit Service |
2781ba |
float *best_fg_distance = &FG_DISTANCE(output, index);
|
|
Packit Service |
2781ba |
float *best_bg_distance = &BG_DISTANCE(output, index);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ColorSample foreground = g_array_index(foreground_samples, ColorSample, best_fi);
|
|
Packit Service |
2781ba |
ColorSample background = g_array_index(background_samples, ColorSample, best_bi);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Get cost
|
|
Packit Service |
2781ba |
float best_cost = get_cost(foreground, background, &input[index * 3], x, y, best_fg_distance, best_bg_distance);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (dist_f > 0 || dist_b > 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Get new indices to check
|
|
Packit Service |
2781ba |
int fl = foreground_samples->len;
|
|
Packit Service |
2781ba |
int bl = background_samples->len;
|
|
Packit Service |
2781ba |
int fi = (start_fi + (rand() % (dist_f * 2 + 1)) + fl - dist_f) % fl;
|
|
Packit Service |
2781ba |
int bi = (start_bi + (rand() % (dist_b * 2 + 1)) + fl - dist_b) % bl;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ColorSample foreground = g_array_index(foreground_samples, ColorSample, fi);
|
|
Packit Service |
2781ba |
ColorSample background = g_array_index(background_samples, ColorSample, bi);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
float cost = get_cost(foreground, background, &input[index * 3], x, y, best_fg_distance, best_bg_distance);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (cost < best_cost)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
best_cost = cost;
|
|
Packit Service |
2781ba |
best_fi = fi;
|
|
Packit Service |
2781ba |
best_bi = bi;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
dist_f /= 2;
|
|
Packit Service |
2781ba |
dist_b /= 2;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
FG_INDEX(output, index) = best_fi;
|
|
Packit Service |
2781ba |
BG_INDEX(output, index) = best_bi;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Compare color intensities
|
|
Packit Service |
2781ba |
static gint color_compare(gconstpointer p1, gconstpointer p2)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
ColorSample *s1 = (ColorSample*) p1;
|
|
Packit Service |
2781ba |
ColorSample *s2 = (ColorSample*) p2;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
float sum1 = s1->color[0] + s1->color[1] + s1->color[2];
|
|
Packit Service |
2781ba |
float sum2 = s2->color[0] + s2->color[1] + s2->color[2];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return ((sum1 > sum2) - (sum2 > sum1));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
matting_process (GeglOperation *operation,
|
|
Packit Service |
2781ba |
GeglBuffer *input_buf,
|
|
Packit Service |
2781ba |
GeglBuffer *aux_buf,
|
|
Packit Service |
2781ba |
GeglBuffer *output_buf,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
int level)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
const GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit Service |
2781ba |
gfloat *input = NULL;
|
|
Packit Service |
2781ba |
guchar *trimap = NULL;
|
|
Packit Service |
2781ba |
gfloat *output = NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gboolean success = FALSE;
|
|
Packit Service |
2781ba |
int w, h, i, x, y, xdiff, ydiff, neighbour_mask;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GArray *foreground_samples, *background_samples;
|
|
Packit Service |
2781ba |
GArray *unknown_positions;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_return_val_if_fail (babl_format_get_n_components (babl_format (FORMAT_INPUT )) == COMPONENTS_INPUT, FALSE);
|
|
Packit Service |
2781ba |
g_return_val_if_fail (babl_format_get_n_components (babl_format (FORMAT_AUX )) == COMPONENTS_AUX, FALSE);
|
|
Packit Service |
2781ba |
g_return_val_if_fail (babl_format_get_n_components (babl_format (FORMAT_OUTPUT)) == COMPONENTS_OUTPUT, FALSE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_return_val_if_fail (operation, FALSE);
|
|
Packit Service |
2781ba |
g_return_val_if_fail (input_buf, FALSE);
|
|
Packit Service |
2781ba |
g_return_val_if_fail (aux_buf, FALSE);
|
|
Packit Service |
2781ba |
g_return_val_if_fail (output_buf, FALSE);
|
|
Packit Service |
2781ba |
g_return_val_if_fail (result, FALSE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
w = result->width;
|
|
Packit Service |
2781ba |
h = result->height;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
input = g_new (gfloat, w * h * COMPONENTS_INPUT);
|
|
Packit Service |
2781ba |
trimap = g_new (guchar, w * h * COMPONENTS_AUX);
|
|
Packit Service |
2781ba |
output = g_new0 (gfloat, w * h * COMPONENTS_OUTPUT);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_get (input_buf, result, 1.0, babl_format (FORMAT_INPUT), input, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
gegl_buffer_get ( aux_buf, result, 1.0, babl_format (FORMAT_AUX), trimap, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
foreground_samples = g_array_new(FALSE, FALSE, sizeof(ColorSample));
|
|
Packit Service |
2781ba |
background_samples = g_array_new(FALSE, FALSE, sizeof(ColorSample));
|
|
Packit Service |
2781ba |
unknown_positions = g_array_new(FALSE, FALSE, sizeof(Position));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Get mask
|
|
Packit Service |
2781ba |
for (y = 0; y < h; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
for (x = 0; x < w; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int mask = trimap[y * w + x];
|
|
Packit Service |
2781ba |
for (ydiff = -1; ydiff <= 1; ydiff++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Borders
|
|
Packit Service |
2781ba |
if (y+ydiff < 0 || y+ydiff >= h)
|
|
Packit Service |
2781ba |
continue;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (xdiff = -1; xdiff <= 1; xdiff++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Borders
|
|
Packit Service |
2781ba |
if (x+xdiff < 0 || x+xdiff >= w)
|
|
Packit Service |
2781ba |
continue;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
neighbour_mask = trimap[(y + ydiff) * w + x + xdiff];
|
|
Packit Service |
2781ba |
if (neighbour_mask != mask && (mask == 0 || mask == 255))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int index = y*w+x;
|
|
Packit Service |
2781ba |
ColorSample s;
|
|
Packit Service |
2781ba |
s.pos.x = x;
|
|
Packit Service |
2781ba |
s.pos.y = y;
|
|
Packit Service |
2781ba |
COLOR(s.color[c] = input[index*3 + c]);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (mask == 255)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_array_append_val(foreground_samples, s);
|
|
Packit Service |
2781ba |
FG_DISTANCE(output, index) = 0;
|
|
Packit Service |
2781ba |
BG_DISTANCE(output, index) = FLT_MAX;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_array_append_val(background_samples, s);
|
|
Packit Service |
2781ba |
FG_DISTANCE(output, index) = 0;
|
|
Packit Service |
2781ba |
BG_DISTANCE(output, index) = FLT_MAX;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Go to next pixel
|
|
Packit Service |
2781ba |
xdiff = 1;
|
|
Packit Service |
2781ba |
ydiff = 1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Initialize unknowns
|
|
Packit Service |
2781ba |
for (y = 0; y < h; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
for (x = 0; x < w; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int index = y * w + x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (trimap[index] != 0 && trimap[index] != 255)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Position p;
|
|
Packit Service |
2781ba |
p.x = x;
|
|
Packit Service |
2781ba |
p.y = y;
|
|
Packit Service |
2781ba |
g_array_append_val(unknown_positions, p);
|
|
Packit Service |
2781ba |
FG_DISTANCE(output, index) = FLT_MAX;
|
|
Packit Service |
2781ba |
BG_DISTANCE(output, index) = FLT_MAX;
|
|
Packit Service |
2781ba |
FG_INDEX(output, index) = rand() % foreground_samples->len;
|
|
Packit Service |
2781ba |
BG_INDEX(output, index) = rand() % background_samples->len;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_array_sort(foreground_samples, color_compare);
|
|
Packit Service |
2781ba |
g_array_sort(background_samples, color_compare);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Do real iterations
|
|
Packit Service |
2781ba |
for (i = 0; i < o->iterations; i++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
unsigned j;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GEGL_NOTE (GEGL_DEBUG_PROCESS, "Iteration %i", i);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (j=0; j<unknown_positions->len; j++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Position p = g_array_index(unknown_positions, Position, j);
|
|
Packit Service |
2781ba |
do_random_search(foreground_samples, background_samples, input, output, p.x, p.y, w);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (j=0; j<unknown_positions->len; j++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Position p = g_array_index(unknown_positions, Position, j);
|
|
Packit Service |
2781ba |
do_propagate(foreground_samples, background_samples, input, output, trimap, p.x, p.y, w, h);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Fill results in
|
|
Packit Service |
2781ba |
for (y = 0; y < h; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
for (x = 0; x < w; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
int index = y * w + x;
|
|
Packit Service |
2781ba |
if (trimap[index] == 0 || trimap[index] == 255)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Use known values
|
|
Packit Service |
2781ba |
output[index * 4 + 0] = input[index * 3 + 0];
|
|
Packit Service |
2781ba |
output[index * 4 + 1] = input[index * 3 + 1];
|
|
Packit Service |
2781ba |
output[index * 4 + 2] = input[index * 3 + 2];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (trimap[index] == 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
output[index * 4 + 3] = 0;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else if (trimap[index] == 255)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
output[index * 4 + 3] = 1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
ColorSample background, foreground;
|
|
Packit Service |
2781ba |
foreground = g_array_index(foreground_samples, ColorSample, FG_INDEX(output, index));
|
|
Packit Service |
2781ba |
background = g_array_index(background_samples, ColorSample, BG_INDEX(output, index));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
output[index * 4 + 3] = get_alpha(foreground.color, background.color, &input[index * 3]);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
COLOR(output[index * 4 + c] = foreground.color[c]);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Save to buffer
|
|
Packit Service |
2781ba |
gegl_buffer_set (output_buf, result, 0, babl_format (FORMAT_OUTPUT), output,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
success = TRUE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
// Free memory
|
|
Packit Service |
2781ba |
g_free (input);
|
|
Packit Service |
2781ba |
g_free (trimap);
|
|
Packit Service |
2781ba |
g_free (output);
|
|
Packit Service |
2781ba |
g_array_free(foreground_samples, FALSE);
|
|
Packit Service |
2781ba |
g_array_free(background_samples, FALSE);
|
|
Packit Service |
2781ba |
g_array_free(unknown_positions, FALSE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return success;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglOperationClass *operation_class;
|
|
Packit Service |
2781ba |
GeglOperationComposerClass *composer_class;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
composer_class = GEGL_OPERATION_COMPOSER_CLASS (klass);
|
|
Packit Service |
2781ba |
composer_class->process = matting_process;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit Service |
2781ba |
operation_class->prepare = matting_prepare;
|
|
Packit Service |
2781ba |
operation_class->get_required_for_output = matting_get_required_for_output;
|
|
Packit Service |
2781ba |
operation_class->get_cached_region = matting_get_cached_region;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_operation_class_set_keys (operation_class,
|
|
Packit Service |
2781ba |
"name" , "gegl:matting-global",
|
|
Packit Service |
2781ba |
"categories" , "misc",
|
|
Packit Service |
2781ba |
"description",
|
|
Packit Service |
2781ba |
_("Given a sparse user supplied tri-map and an input image, create a "
|
|
Packit Service |
2781ba |
"foreground alpha matte. Set white as foreground, black as background "
|
|
Packit Service |
2781ba |
"for the tri-map. Everything else will be treated as unknown and filled in."),
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
#endif
|