GNOME Bugzilla – Bug 316479
The Perspective Tool creates an empy image instead of transforming it
Last modified: 2016-11-08 18:33:31 UTC
Please describe the problem:
The Perspective Tool doesn't work like expected.
Steps to reproduce:
1. Open the image I'll attach.
2. Click on the Perspective Tool (Shift+P).
3. Set Transform Direction to Backward(corrective).
4. Set the transform grid to the red lines.
Does this happen every time?
Created attachment 52315 [details]
An test image(JPEG) to show this bug.
Indeed, that is very very broken.
Using the perspective tool in corrective mode means having to invert a matrix.
There is nothing to prevent the matrix from being singular or nearly so. If
this happens, it's a bad situation -- like dividing by something nearly zero.
Maybe the best approach is for the tool to calculate the determinant of the
matrix before trying to transform, and bailing out with a warning message if the
value is too close to zero. (I'm not certain this is what is happening, but
judging by the way it is going wrong, I would bet at least a nickel on it.)
I have looked into this a bit more. I had been assuming that the perspective
tool does a linear transformation, but I should have thought more deeply:
linear transformations only give 6 degrees of freedom, and the perspective tool
requires 8 -- two coordinates for each of the four vertices. It manages this by
including a hyperbolic (1/x) component in the transform; see
gimp_matrix3_transform(). Now the problem is that it is easy for hyperbolic
things to blow up, and it is hard to predict when this will happen for the
perspective tool. When it blows up, the result is that the transformed layer
becomes extremely large.
The appropriate fix, I think, is that the function
gimp_drawable_transform_tiles_affine() should do some sanity checking after it
calculates the corners of the transformed layer -- currently it only checks that
they are finite, but it probably should clip them to some multiple of the image
size instead. Also there should be an additional sanity check to verify that
none of the interior points in the region will map to infinity.
In any case, the example given in this bug report is not actually a bug -- what
is happening is that the layer is being shifted such that none of its contents
lie within the image bounds. (In fact, it is being shifted such that one of its
interior points maps to infinity.) This kind of thing is going to happen
sometimes when the perspective tool is used in inverse mode. The real bug is
that some control matrices can give rise to extremely large transformed layers
and cause GIMP either to crash or to thrash.
That's exactly the reason that "Clip result" in on by default in the Perspective transform tool.
Doesn't seem to make sense to have this bug sitting on the 2.2 milestone.
Tobias, please do not change the version field to "Current SVN", at least not without adding a comment. It now looks as if this was a problem in SVN at the time you reported the bug. If you want to point out that a particular problem still exists, please add a comment for it.
Sorry Sven, yes the problem still exists in the "Current SVN".
Please try GIMP 2.7.4 and report back, we won't fix 2.6 bugs any longer.
Could you please try to reproduce bug with GIMP 2.7.4 or later version and update the bug report with your finding, tia.
This bug is still in 2.7.4 (Windows).
Created attachment 216616 [details]
I redid the math to make sure there was no bug there. The problem happens with the inverse transform if one of the perspective's vanishing points is in the transformed region. Well, my calculations suggest that it should fail on the line that connects the vanishing points, but in practice it does not seem to be the case...
Anyway, I think we should just issue a warning if such a case happens, so that the user know why it failed. Or clip the result regardless of what the user says.
Also, comment 5 says that "clip" is on by default, but it seems that now the default option is "adjust". Is there a special reason for this change? If not we should use "clip" by default to prevent this bug from happening.
And bug 598985 describes the same problem.
*** Bug 598985 has been marked as a duplicate of this bug. ***
Adjust is the same as clip used to be, and transforming to huge sizes
is not really avoidable, maybe we need a maximum size here, it should
at least not crash.
Err no, it's not the same :) Are you saying we should default to clip
if we inverse-transform?
Before I investigated this bug, I didn't even know there was a clip or adjust option, and I never noticed that parts of the transformed layer were outside the image, so yes, I wouldn't mind at all.
Well, "crop to result" might be a better default behavior. As I understand it, it crops if the result is larger than the image, and adjusts if it's smaller?
(In reply to comment #12)
> I redid the math to make sure there was no bug there. The problem happens with
> the inverse transform if one of the perspective's vanishing points is in the
> transformed region. Well, my calculations suggest that it should fail on the
> line that connects the vanishing points, but in practice it does not seem to be
> the case...
It fails when the horizon (the line connecting the vanishing points)
intersects the rectangle. In that case one or two corners are
(mathematically) back transformed from behind the viewer and the area
rendered includes parts from outside the source rectangle and does not
include part from inside (which is infinite).
Created attachment 216689 [details]
Attached a script that shows what happens when the horizon
intersects the source rectangle in the case of TRANSFORM-RESIZE-ADJUST
to be run from the command-line
gimp-2.8 -b '(load "perspective.scm")'
and replay the undo history to understand.
Basically the computation of the destination extent assumes that
the 4 transformed corners are directly connected, whereas two segments
connecting them are transformed to infinite lines passing through
the projective point at infinity.
Created attachment 216780 [details] [review]
This patch uses GIMP_TRANSFORM_RESIZE_CLIP when it detects that a transform will fail.
Unfortunately, it only works with 2.8. With current master it does nothing. It looks as if assigning clip_result inside gimp_drawable_transform_buffer_affine was ignored.
Created attachment 217766 [details] [review]
patch against gimp/master
The previous fix stopped working since the switch to GEGL in the transform tool (commit 8a7ea1c25a8e66b16f906595f6b08a6e6842c507).
The problem lies in gegl/operations/transform/transform-core.c. Although transform_generic() properly iterates over the destination buffer (so it only computes useful pixels when the result is clipped), gegl_transform_get_bounding_box() finds an incoherent bounding box, just as gimp_transform_resize_boundary() would if we did not set clip_result.
I added a boolean "result_clipped" property to the "gegl:transform" operation that is true when clip_result is GIMP_TRANSFORM_RESIZE_CLIP. Now gegl_transform_get_bounding_box() knows that we want to clip the result and acts accordingly.
Created attachment 217767 [details] [review]
patch against gegl/master
I was checking old bugs. I tried to follow the reproduction steps in the first comment against master, but could not see anything weird. I don't get an "empty image created", so I don't really see what was supposed to get wrong.
Anyone who participated to this bug by the past, and know what was wrong, has this bug outdated, and now it has been fixed in GIMP master?
I've checked this bug with the latest GIT version of GIMP and GEGL and the bug is still there. Make sure that the transform direction is set to backward(corrective).
Yeah, confirming in current master as well. I'd say this is something we want to fix for 2.10.
This fixes the GEGL part, only with a different patch:
Author: Øyvind Kolås <email@example.com>
Date: Tue Nov 8 16:42:36 2016 +0100
transform: add a clip-to-input property
Add a property for GIMP to set when the used transformation matrix would
make the size of the output explode. ref bug #316479
operations/transform/transform-core.c | 19 +++++++++++++++++--
operations/transform/transform-core.h | 1 +
2 files changed, 18 insertions(+), 2 deletions(-)
Fixed in master:
Author: Alexis Wilhelm <alexiswilhelm%40gmail.com>
Date: Tue Nov 8 17:15:16 2016 +0100
Bug 316479 - The Perspective Tool creates an empy image...
...instead of transforming it
Add gimp_matrix3_will_explode() which determines if a transform
matrix will blow up something in a rectangle to infinity, and use
the function so set both the GIMP and GEGL code paths to clip the
transform to the input size.
app/core/gimpdrawable-transform.c | 4 ++++
app/gegl/gimp-gegl-apply-operation.c | 9 +++++++--
app/gegl/gimp-gegl-apply-operation.h | 1 +
libgimpmath/gimpmath.def | 1 +
libgimpmath/gimpmatrix.c | 36 ++++++++++++++++++++++++++++++++++++
libgimpmath/gimpmatrix.h | 6 ++++++
6 files changed, 55 insertions(+), 2 deletions(-)