Commit Graph

45 Commits

Author SHA1 Message Date
6391b2bcff Issue #3263: fix critical error on bucket fill tool.
Fixes the error:
> Critical error: gimp_line_art_thaw: assertion 'line_art->priv->frozen'

This may happen in cases when we didn't actually freeze the line art at
pointer click, because we were in an invalid case (for instance,
clicking out of selection), hence we must not thaw the line art either
at button release.
2019-08-27 12:41:49 +02:00
7e99aa59f5 Add other misc. typo fixes 2019-08-13 11:50:51 -04:00
746a72b956 Make sure to use % for constants
Documentation-wise in C, this doesn't matter a lot, but it allows
GObject-Introspection based bindings to use their built-in versions when
they want to render any kind of documentation (for example, docs for
Python plugins can render `%NULL` as `None`).
2019-08-03 07:53:47 +00:00
63695b4b21 libgimbase: merge gimpparam.h into gimpparamspecs.h
which means that it's now included normally via gimpbase.h
and not any longer via gimpbasetypes.h which we only did out
of lazyness. A *lot* of files in libgimp* and app/ now need to
2019-07-31 10:16:21 +02:00
Ell
2d80d4d138 app: use gimp_gegl_buffer_dup() everywhere
... instead of gegl_buffer_dup().
2019-07-30 20:32:41 +03:00
Ell
caad9ca649 app: various fixes to last commit 2019-03-06 15:56:09 -05:00
Ell
d8e69d66bc app: allow canceling line-art computation
Line-art computation can take a long time, and it's therefore
desirable for it to be interruptable.  While we do cancel the line-
art async when its result is no longer needed, most parts of the
computation don't respond to the cancelation request, leaving the
async operation running in the background, blocking subsequent
async operations.

Implement cancelation support of line-art computation, by passing
down the async object to the various functions, and periodically
checking for its cancelation at various points.  When the async is
canceled, we quickly abort the operation.

Even though cancelation now happens relatively quickly, some parts
of the computation are still uninterruptable and may incur some
latency, so we avoid waiting for the async opration to be aborted
after cancelation, as we did before.
2019-03-06 15:24:14 -05:00
Ell
bb7f61c919 app: use gimp_gegl_buffer_copy() in various places
... instead of gegl_buffer_copy().  The former parallelizes the
format conversion.
2019-03-06 05:59:57 -05:00
f310db6c21 app: improve line art filling when clicking on a line art closure.
When clicking on a line art pixel, only this pixel gets colored, which
is fine for actual (original) line art pixels. But on generated ones
(closure pixels, which are internal only), you end up with a single
pixel colored while the whole surrounding area is empty. This feels like
a bug (even though it was not one technically) as you have no way to
guess you are clicking on a closure pixel.
Instead, when this happens, simulate clicks on all neighbour pixels,
hence potentially coloring all surrounding regions, which is most likely
what you wanted.
2019-03-04 18:31:13 +01:00
3a317e72aa app: fixing the line art GimpBusyBox visibility.
Commit bc187cc5cc was a bit wrong as it was possible to get some race
conditions when changing settings quickly in a short time frame.
2019-03-04 16:55:51 +01:00
c0996241f6 app: avoid useless line art closure recomputation.
On various property changes, only recompute the line art when the
property actually changed. Also add a gimp_line_art_bind_gap_length() to
avoid computing twice the line art when changing both type of closure
(splines and segments) together, as is currently the case.
2019-03-04 16:43:19 +01:00
bc187cc5cc app: add a GimpBusyBox near the "Line Art Detection" label in…
… Bucket Fill tool options.
This will provide feedback when the line art closure is being computed,
which may be useful on big images where it may take some time. Otherwise
painter may be left hanging without knowing what takes time.
2019-03-04 16:06:59 +01:00
248477a125 app: some small improvements in line art code.
Mostly I am adding a counter to the insignifiant zone fill, to be double
sure we are not going to fill huge areas (this should not happen already
anyway) and also it is no use to sample the line art buffer in such
case.
2019-02-16 12:35:10 +01:00
0636c302a3 app: gimp_edgel_region_area() may return < 0 for non-closed zones.
The algorithm to compute a zone area by following its border only works
well for fully closed zones. It may return negative values otherwise.
Let's just assume the created zone is big in this case (which may or may
not be the case, but this is the safe case as it does not prevent
closure creation).
2019-02-14 13:53:33 +01:00
c4beca8c90 app: clarify function to validate line art closure.
Add some comments and string docs as it is not that obvious to
understand the whole logics, invert the return value (returning TRUE
when the closure line is accepted, instead of the opposite) and rename
it to more appropriate gimp_line_art_allow_closure().
2019-02-11 15:16:02 +01:00
14e7424403 app: proper signedness for return value of gimp_edgel_region_area().
It is just weird to return a negative area and multiply it by -1.
Just apply the proper signs from the start.
2019-02-11 15:16:02 +01:00
72092fbdbc app: improve line art bucket fill by filling unsignificant areas.
The line art imaginary segments/splines are not added when they create
too small zones, unless when these are just too small ("unsignificant").
Why the original algorithm keeps such micro-zones is because there may
be such zones created when several splines or segments are leaving from
a same key point (and we don't necessarily won't to forbid this). Also
we had cases when using very spiky brushes (for the line art) would
create many zones, and such micro-zones would appear just too often
(whereas with very smooth lines, they are much rarer, if not totally
absent most of the time).
Also it is to be noted that the original paper would call these
"unsignificant" indeed, but these are definitely significant for the
artists. Therefore having to "fix" the filling afterwards (with a brush
for instance) kind of defeat the whole purpose of this tool.

I already had code which would special-case (fill) 1-pixel zones in the
end, but bigger micro zones could appear (up to 4 pixels in the current
code, but this could change). Also I don't want to use the "Remove
Holes" (gimp:flood) operation as I want to make sure I remove only
micro-holes created by the line art closure code (not micro-holes from
original line arts in particular).

This code takes care of this issue by filling the micro-holes with
imaginary line art pixels, which may later be potentially bucket filled
when water-filling the line art.
2019-02-07 18:09:30 +01:00
aa04258620 app: improved fix to commit 036ccc70cf.
After discussion with Sébastien Fourey and David Tschumperlé, it was
decided that a better fix for the edge case raised in #2785 was to add a
keypoint anyway, even if the point and none of its neigbours have a
positive smoothed curvature, yet they have a positive raw curvature. In
such case, we use the local maximum raw curvature instead of the local
maximum smoothed curvature.
2019-01-17 13:21:18 +01:00
c71b4916af app: add the concept of line art source to Bucket Fill tool.
Additionally to sample merge and active layer, now we can only use the
layer above or below the active layer as line art source.

The line art fill is meant to work on drawing lines. Though sample merge
still is ok in many cases, the more you fill with colors, the more the
line art computation becomes unecessarily complex. Also when you use a
lot of layers with some of them already filled with colors, it makes it
impossible to colorize some line art zones with the tool. Moreover you
just don't want to have to hide every layers out there to colorize one
layer (especially background layers and such as you may want to see the
result with your background).
Thus we want to be able to set the source as a unique layer, while it
not being necessarily the active one (because you want lines and colors
on different layers). In this case, I am assuming that the color and the
line layers are next to each other (most common organization).
2019-01-15 16:06:50 +01:00
036ccc70cf Issue #2785: Fill by line art detection produces Segmentation fault...
... with some images.
2019-01-13 17:40:25 +01:00
005bc1406b app: add link to Smart Colorization scientific paper.
This is sometimes asked, and myself also need to find it from time to
time. I may as well put the link inside the code comments, where it is
just easy to find!
2019-01-12 00:26:19 +01:00
Ell
823d4a0d24 app: in bucket-fill tool, avoid calculating line art when not in line-art mode
In the bucket-fill tool, don't pre-calculate the line art when not
using a line-art fill area.  Also, misc. cleanup.
2019-01-06 16:30:41 -05:00
Ell
ef9b1f6694 app: in GimpLineArt, use "invalidate-preview" signal of input viewable
In GimpLineArt, use the "invalidate-preview" signal of the input
viewable, instead of its "painted" or "rendered" signals, for
asynchronously computing the line art.  Subsequently, remove the
aforementioned signals from GimpDrawable and GimpProjection,
respectively.  This simplifies the code, and reduces the number of
signals.
2018-12-27 17:14:28 -05:00
503775a5a0 app: rename and merge the spline and segment length properties...
... in GimpBucketFillOptions for the line art algorithm.

Inside GimpLineArt, there are still 2 properties, but we don't show them
anymore in the Bucket Fill tool options. One of the main reason is
probably that it's hard to differentiate their usage. One is to close
with curved lines, the other with straight segments. Yet we don't
actually have any control on one or the other. All one knows is that you
can have "holes" in your drawing of a given size and you want them
close-like for filling. Only reason I can see to have 2 types of closure
is whether you'd want to totally disable one type of closure (then you
set it to 0). But this is a very limited reason for making the options
less understandable overall, IMO.
So for the time being, let's show up only a single option which sets
both properties in GimpLineArt. As patdavid says "it makes sense as a
first pass".

Also rename the option to shorter/simpler "Maximum gap length". Thanks
to patdavid and pippin for helping on figuring out this better label!

Finally I am bumping the default for the gaps to 100px. The original
values were ok for the basic small images used in demos, but not for
real life image where it was always too short (even 100px may still be
too short actually, but much better than the 20 and 60px from before!).
2018-12-24 13:33:58 +01:00
0a2d066168 app: allow setting line art spline and segment length to 0.
Practically it means that the algorithm won't close line art anymore
with both settings at 0. This can nevertheless still be a very useful
tool when you have a drawing style with well-closed lines. In such a
case, you will still profit from the color flooding under the line art
part of the algorithm.
Moreover with such well-closed zones from start, you don't get the
over-segmentation anymore and the threaded processing will be faster
obviously.
2018-12-17 15:46:47 +01:00
db18c679f3 app: reorganize the line art code inside a GimpLineArt object.
The code was too much spread out, in core and tool code, and also it was
made too specific to fill. I'll want to reuse this code at least in the
fuzzy select tool. This will avoid code duplication, and also make this
new process more self-contained and simpler to review later (the
algorithm also has a lot of settings and it is much cleaner to have them
as properties rather than passing these as parameters through many
functions).

The refactoring may not be finished; that's at least a first step.
2018-12-07 22:18:06 +01:00
Ell
053e5edc93 libgimpcolor, app, modules, plug-ins: remove GEGL_ITERATOR2 define
... it's no longer needed, since GEGL commit
gegl@9dcd2cde63f95a080bf16a58c10e9ffbdd99aace.

Partially reverts commits:

6fca9959c7
cc10af72cc
49c53568d7
8edbc0d491
29f63616d2
3a2014984d
ee48ec6877
4165a315d5
764085278f
b7633c722e
6ab12061b7
754a3c5b18
22b4b647bd
55b3438328
c6d23add65
f03a84d607
822f9f0d2b
95358ca1fa
cdda37f4ee
41e8035635
6761da42b2
fb5d7832a8
97ed7817d8
46e9036578
ea9c5e6a49
24fbdfb591
beb4ecb238
4b77831e03
fcf113a39c
567ffe94ff
2018-12-02 11:15:37 -05:00
f7a4ce1051 app: some code cleaning in gimplineart.
In particular, make simpler code in a few places, taking abyss value
into account (rather than checking the position).
2018-11-29 14:13:50 +01:00
6bec0bc82d app: radius map actually not useful during smart colorization grow step.
The distance map has all the information we need already. Also we will
actually grow up to the max radius pixel (middle pixel of a stroke).
After discussing with Aryeom, we realized it was better to fill a stroke
fully (for cases of overflowing, I already added the "Maximum growing
size" property anyway).
2018-11-27 14:59:35 +01:00
c32b0ecc92 app: simpler code with gegl_node_blit().
No need to go through an intermediate GeglBuffer when unneeded.
2018-11-26 12:26:54 +01:00
5a4754f32b 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.
2018-11-22 14:39:43 +01:00
3467acf096 app: replace gegl:watershed-transform with custom algorithm.
We don't really need to flow every line art pixel and this new
implementation is simpler (because we don't actually need over-featured
watershedding), and a lot lot faster, making the line art bucket fill
now very reactive.
For this, I am keeping the computed distance map, as well as local
thickness map around to be used when flooding the line art pixels
(basically I try to flood half the stroke thickness).

Note that there are still some issues with this new implementation as it
doesn't properly flood yet created (i.e. invisible) splines and
segments, and in particular the ones between 2 colored sections. I am
going to fix this next.
2018-11-22 14:24:52 +01:00
79571231c5 app: end point detection uses both the end point rate and clamped value. 2018-11-19 14:44:26 +01:00
3f58a38574 app: remove now useless erosion size option.
Since commit b00037b850, erosion size is not used anymore, as this step
has been removed, and the end point detection now uses local thickness
of strokes instead.
2018-11-19 14:18:18 +01:00
b00037b850 app: improve end point detection for smart colorization.
Previous algorithm was relying on strokes of small radius to detect
points of interest. In order to work with various sizes of strokes, we
were computing an approximate median stroke thickness, then using this
median value to erode the binary line art.

Unfortunately this was not working that well for very fat strokes, and
also it was potentially opening holes in the line art. These holes were
usually filled back later during the spline and segment creations. Yet
it could not be totally assured, and we had some experience where color
filling would leak out of line art zones without any holes from the
start (which is the opposite of where this new feature is supposed to
go)!

This updated code computes instead some radius estimate for every border
point of strokes, and the detection of end points uses this information
of local thickness. Using local approximation is obviously much more
accurate than a single thickness approximation for the whole drawing,
while not making the processing slower (in particular since we got rid
of the quite expensive erosion step).
This fixes the aforementionned issues (i.e. work better with fat strokes
and do not create invisible holes in closed lines), and also is not
subject to the problem of mistakenly increasing median radius when you
color fill in sample merge mode (i.e. using also the color data in the
input)!
Also it is algorithmically less intensive, which is obviously very good.

This new version of the algorithm is a reimplementation in GIMP of new
code by Sébastien Fourey and David Tschumperlé, as a result of our many
discussions and tests with the previous algorithm.

Note that we had various tests, experiments and propositions to try and
improve these issues. Skeletonization was evoked, but would have been
most likely much slower. Simpler erosion based solely on local radius
was also a possibility but it may have created too much noise (skeleton
barbs), with high curvature, hence may have created too many new
artificial endpoints.
This new version also creates more endpoints though (and does not seem
to lose any previously detected endpoints), which may be a bit annoying
yet acceptable with the new bucket fill stroking interaction. In any
case, on simple examples, it seems to do the job quite well.
2018-11-16 20:39:04 +01:00
824af12438 app: edit the bucket fill tool options with new line art options.
I have not added all the options for this new tool yet, but this sets
the base. I also added a bit of TODO for several places where we need to
make it settable, in particular the fuzzy select tool, but also simply
PDB calls (this will need to be a PDB context settings.

Maybe also I will want to make some LineArtOptions struct in order not
to have infinite list of parameters to functions. And at some point, it
may also be worth splitting a bit process with other type of
selection/fill (since they barely share any settings anyway).

Finally I take the opportunity to document a little more the parameters
to gimp_lineart_close(), which can still be improved later (I should
have documented these straight away when I re-implemented this all from
G'Mic code, as I am a bit fuzzy on some details now and will need to
re-understand code).
2018-11-14 13:37:42 +01:00
93a49951a0 app: fix line art labellization.
The older labelling based off CImg code was broken (probably because of
me, from my port). Anyway I realized what it was trying to do was too
generic, which is why we had to fix the result later (labeling all
non-stroke pixels as 0, etc.). Instead I just implemented a simpler
labelling and only look for stroke regions. It still over-label a bit
the painting but a lot less, and is much faster.
2018-11-14 13:37:42 +01:00
c4ff81540d app: better use GeglBufferIterator!
I don't actually need to loop through borders first. This is what the
abyss policy is for, and I can simply check the iterator position to
verify I am within buffer boundaries or not.
This simplifies the code a lot.
2018-11-14 13:37:42 +01:00
0c80f8a718 app: use char array for temporary data (rather than a GEGL buffer).
Also use more GeglBufferIterator on input GEGL buffer.
Using a char array is much less expensive and accelerated the line
erosion a lot!
Moving to GeglBufferIterator is not finished, but I do in steps.
2018-11-14 13:37:42 +01:00
f975f15ec0 app: use simpler allocated variables.
Allocating double-level arrays is just very inefficient.
2018-11-14 13:37:42 +01:00
f19181dcf8 app: make visited into single-level allocated array. 2018-11-14 13:37:42 +01:00
910d7934f5 app: fix stroke labels in gimp_lineart_estimate_stroke_width().
I must make sure that stroke pixels are labelled 0 and non-stroke other
than 0.
2018-11-14 13:37:42 +01:00
1822ea399a app: use more GeglBufferIterator.
In this case, it makes the code a bit more messy, but hopefully more
efficient.
2018-11-14 13:37:42 +01:00
041a8f1eec app: use GeglBufferIterator rather than gegl_buffer_sample|set(). 2018-11-14 13:37:42 +01:00
8ed12b1b98 app, libgimpbase: add GIMP_SELECT_CRITERION_LINE_ART selection type.
This commit implements part of the research paper "A Fast and Efficient
Semi-guided Algorithm for Flat Coloring Line-arts" from the GREYC (the
people from G'Mic). It is meant to select regions from drawn sketchs in
a "smart" way, in particular it tries to close non-perfectly closed
regions, which is a common headache for digital painters and colorists.

The implementation is not finished as it needs some watersheding as well
so that the selected area does not leave "holes" near stroke borders.
The research paper proposes a new watersheding algorithm, but I may not
have to implement it, as it is more focused on automatic colorization
with prepared spots (instead of bucket fill-type interaction).

This will be used in particular with the fuzzy select and bucket fill
tools.

Note that this first version is a bit slow once we get to big images,
but I hope to be able to optimize this.
Also no options from the algorithm are made available in the GUI yet.
2018-11-14 13:37:42 +01:00