app: properly (bucket) fill created splines and segments in line art.

For this, I needed distmap of the closed version of the line art (after
splines and segments are created). This will result in invisible stroke
borders added when flooding in the end. These invisible borders will
have a thickness of 0.0, which means that flooding will stop at once
after these single pixels are filled, which makes it quick, and is
perfect since created splines and segments are 1-pixel thick anyway.
Only downside is having to run "gegl:distance-transform" a second time,
but this still stays fast.
This commit is contained in:
Jehan 2018-11-22 14:32:59 +01:00
parent 3467acf096
commit 5a4754f32b
2 changed files with 36 additions and 14 deletions

View File

@ -105,8 +105,7 @@ static GArray * gimp_lineart_line_segment_until_hit (const GeglBuffer
Pixel start,
GimpVector2 direction,
int size);
static gfloat * gimp_lineart_estimate_strokes_radii (GeglBuffer *mask,
gfloat **lineart_distmap);
static gfloat * gimp_lineart_estimate_strokes_radii (GeglBuffer *mask);
/* Some callback-type functions. */
@ -188,7 +187,7 @@ static void gimp_edgelset_next8 (const GeglBuffer *buffer,
* @segments_max_length: the maximum length for creating segments
* between end points. Unlike splines, segments
* are straight lines.
* @lineart_distmap: a distance map of the line art pixels.
* @closed_distmap: a distance map of the closed line art pixels.
* @lineart_radii: a map of estimated radii of line art border pixels.
*
* Creates a binarized version of the strokes of @buffer, detected either
@ -224,7 +223,7 @@ gimp_lineart_close (GeglBuffer *buffer,
gint created_regions_minimum_area,
gboolean small_segments_from_spline_sources,
gint segments_max_length,
gfloat **lineart_distmap,
gfloat **closed_distmap,
gfloat **lineart_radii)
{
const Babl *gray_format;
@ -313,7 +312,7 @@ gimp_lineart_close (GeglBuffer *buffer,
smoothed_curvatures,
normal_estimate_mask_size);
radii = gimp_lineart_estimate_strokes_radii (strokes, lineart_distmap);
radii = gimp_lineart_estimate_strokes_radii (strokes);
threshold = 1.0f - end_point_rate;
clamped_threshold = MAX (0.25f, threshold);
for (i = 0; i < width; i++)
@ -457,6 +456,33 @@ gimp_lineart_close (GeglBuffer *buffer,
point++;
}
if (closed_distmap)
{
GeglNode *graph;
GeglNode *input;
GeglNode *op;
/* Flooding needs a distance map for closed line art. */
*closed_distmap = g_new (gfloat, width * height);
graph = gegl_node_new ();
input = gegl_node_new_child (graph,
"operation", "gegl:buffer-source",
"buffer", closed,
NULL);
op = gegl_node_new_child (graph,
"operation", "gegl:distance-transform",
"metric", GEGL_DISTANCE_METRIC_EUCLIDEAN,
"normalize", FALSE,
NULL);
gegl_node_connect_to (input, "output",
op, "input");
gegl_node_blit (op, 1.0, gegl_buffer_get_extent (closed),
NULL, *closed_distmap,
GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_DEFAULT);
g_object_unref (graph);
}
g_hash_table_destroy (visited);
g_array_free (keypoints, TRUE);
g_object_unref (strokes);
@ -1276,8 +1302,7 @@ gimp_lineart_line_segment_until_hit (const GeglBuffer *mask,
}
static gfloat *
gimp_lineart_estimate_strokes_radii (GeglBuffer *mask,
gfloat **lineart_distmap)
gimp_lineart_estimate_strokes_radii (GeglBuffer *mask)
{
GeglBufferIterator *gi;
gfloat *dist;
@ -1422,10 +1447,7 @@ gimp_lineart_estimate_strokes_radii (GeglBuffer *mask,
}
}
if (lineart_distmap)
*lineart_distmap = dist;
else
g_free (dist);
g_free (dist);
g_object_unref (distmap);
return thickness;

View File

@ -437,10 +437,10 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable,
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
gfloat thickness = thickmap[x + y * width];
if (thickness > 0.0)
if (distmap[x + y * width] == 1.0)
{
gfloat thickness = thickmap[x + y * width];
if (x > 0)
{
nx = x - 1;