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. 5. Transform. Actual results: Expected results: Does this happen every time? Yes. Other information:
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] math 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] testcase Attached a script that shows what happens when the horizon intersects the source rectangle in the case of TRANSFORM-RESIZE-ADJUST vs TRANSFORM-RESIZE-CLIP. 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] patch 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
Hi, 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? Thanks.
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: commit 363b1c983be018c5fb344f1e482f1dbd0e6fe6a6 Author: Øyvind Kolås <pippin@gimp.org> 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: commit 768d06614f203bf555bbda1f6186d4730ae2f8b5 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(-)