bugGNU Octave - Bugs: bug #44830, image package: imtransform gives...

 
 

bug #44830: image package: imtransform gives different numbers on simple rotation

Submitter:  Hartmut <hardy>
Submitted:  Tue 14 Apr 2015 10:21:45 AM UTC
   
 
Category:  Octave Package Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Matlab Compatibility
Status:  Fixed Assigned to:  None
Originator Name:  Open/Closed:  * Closed
Release:  * 3.8.2 Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Fri 29 May 2015 04:45:00 PM UTC, comment #14: 

I have pushed the supplied changesets. Thank you

Carnë Draug <carandraug>
Group Member
Mon 25 May 2015 02:48:46 PM UTC, comment #13: 

Well changes to xyscale and x/ydata are very intricated and it would be a bit artificial (would leave broken tests between the two commits) and time consuming to try to split them.

I attached 2 csets: in the first one (fix_xyscale2.patch) I tried to make it clearer that now xyscale takes precedence over x/ydata (even when provided by the user). The second is for the shape of the output x/ydata.


(file #34090, file #34091)

Pantxo Diribarne <pantxo>
Group Member
Sun 24 May 2015 01:56:42 AM UTC, comment #12: 

The changeset fixes several things in a single commit. Could you please split it into 3 separate commits? I'm not very familiar with the function and its options to do it. It seems that one changes xyscale, another how to interpret xdata and ydata, and another the shape of the output.

Carnë Draug <carandraug>
Group Member
Thu 14 May 2015 06:17:03 PM UTC, comment #11: 

I have tested this second patch and it looks totally fine to me.

Could we maybe

  • push this patch the repo
  • and just add a litte note to the doc text, that (only) the border pixels are numerically different from the Matlab output?


Thanks a lot for your work. I would suggest to close this bug report (as well as #44857) afterwards.

Hartmut <hardy>
Thu 14 May 2015 01:38:24 PM UTC, comment #10: 

Hi,

I attached a new patch that also fixes x/ydata shape (see comment #8) and add/fix some tests.

The reason why the output pixel data are not symetric is due to the actual x/ydata that are computed [1]: as the output image size has to be integer, the actual (returned) x/ydata have to be recomputed. As specified in Matlab documentation, x/ydata are not recomputed symetrically, only the second element of each is altered. To be clear: the output pixels coordinates are shifted right/down (with regards to the expected center of the image) as needed.

Now about your interpretation of the fact that boundary pixels are wrong in Octave, I think you are right but I don't know how to implement this without a drastic performance drop.

[1] See "xdata" output documentation in http://fr.mathworks.com/help/images/ref/imtransform.html

(file #34009)

Pantxo Diribarne <pantxo>
Group Member
Wed 13 May 2015 06:22:26 PM UTC, comment #9: 

Sorry, I forgot to attach the visualisation sketch. Here it is:


Hartmut <hardy>
Wed 13 May 2015 06:20:47 PM UTC, comment #8: 

I have tested this patch:

  • It does resolve bug #44857 for me.
  • The original topic of (this) bug #44830 is partially solved ford me. The center 2x2 pixels (of the 4x4 result) are identical to the Matlab result. But the outside boundary pixels are not. (I still do not understand why the Matlab result is a-symmetric. But I DO understand why the Matlab result has non-zero outside boundary pixels. This is due to the thinking of pixels as a 1x1 surface, in contrast to just infinitly tiny points. I will attach little sketch to visualize my thoughts here.)
  • The second topic of (this) bug #44830 (post 5) is mostly solved, but not yet perfectly :) The resulting numbers for x and y are now the same as in Matlab. But Matlab returns them as a row vector, whereas Octave (still) returns them as a column vector.


Thanks for looking deeper into this. I would really appreciate if this patch went into the next release of the image package.

Hartmut <hardy>
Wed 13 May 2015 07:52:21 AM UTC, comment #7: 

I have attached a preliminary patch that fixes both bug #44857 and partially this bug. I still have to add a changelog and tests though. Can someone test it and give me feeback?

The computed values for boundary pixels are still not quite the same as in Matlab: it looks like Matlab performs extrapolation for boundary pixels.

(file #33997)

Pantxo Diribarne <pantxo>
Group Member
Tue 28 Apr 2015 12:26:33 PM UTC, comment #6: 

If we don't understand what Matlab is doing, you instead add a warning of the type


@emph{Warning}: this function is not completely @sc{Matlab} compatible.  Octave
does X because of Y, while @Sc{Matlab} does something weird and undocumented
that we can't really explain.  The results should however, be comparable.  The
actual results may change in the future.


Still, I wouldn't close the bug report, ideally we'd have it fixed one day.

Carnë Draug <carandraug>
Group Member
Tue 28 Apr 2015 09:49:54 AM UTC, comment #5: 

I have double checked the behavior of findbounds.m. And this function seems to be quite Matlab compatible. If I run this little script


uv = [1 3; 1 3];
a = 45;
t = maketform('affine',[cosd(a) sind(a) 0; -sind(a) cosd(a) 0; 0 0 1]);
xy = findbounds(t, uv)


Then the Matlab and the Octave result are identical:  xy = [-1.4142 2.8284; -1.4142 2.8284] .

Additionally I have performed another test for Matlab compatibility of imtransform.m. Running this little script


M = [0 1 0; 0 1 0; 0 1 0];
[imtrans, x, y] = imtransform(M, t, 'fillvalues',0);
imtrans
x
y


gives different results in Matlab and Octave. The difference in the rotated image data (imtrans) is already known, this was the original issue of this bug report. But also the returned coordinate limits x and y are different between Matlab and Octave. Octave returns x=[-1.4142; 1.4142] and y=[1.4142; 4.2426], whereas Matlab returns x = [-1.4142, 1.5858] and y=[1.4142, 4.4142].

The height and width of the returned coordinate limits of Octave are sqrt(8), which I can fully understand. The height and width of the returned coordinate limits of Matlab are sqrt(9)=3, there I have no clue why this would be! (Or is it just rounding off the coordinates width to integer values, but why whould they then keep the coordinate limits at fractional values??)

So my personal conclusion is, that the Matlab version of imtransform does some funny things, that I don't understand. And I can fully live with the image results of the Octave version of imtransform.m . (Maybe same image size would be nice, but that's been taken care of with a different bug report already.)

My suggestion: Should we just add a little note to the help string of imtransform.m, and the close this bug report? Maybe something like this "note: The transformed image data is comparable in quality to the Matlab results. But there are differences in the exact values of the returned images."

Hartmut <hardy>
Sun 19 Apr 2015 08:47:24 PM UTC, comment #4: 

One key to this difference between the Matlab and the Octave function "imtransform.m", might be the thinking (and calculating) behind the function "findbounds.m".

Only if I do the following change to line 45 and 46 of findbounds.m (image-2.4.0)

    [xcp, ycp] = meshgrid (linspace (inbnd(1,1)-0.5, inbnd(2,1)+0.5, 3),
                           linspace (inbnd(1,2)-0.5, inbnd(2,2)+0.5, 3));

with the control points in the input space expanded by 0.5 in each direction, then I can reproduce the Matlab results of findbound.m as stated in the Matlab help ( http://de.mathworks.com/help/images/ref/findbounds.html ).

But this seems not the only necessary change. With this adjusted findbounds function, the demo script of the original post only changes to

imtrans =

   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000
   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000
   0.00000   0.00000   0.40000   1.00000   0.00000   0.00000
   0.00000   0.00000   1.00000   0.40000   0.00000   0.00000
   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000
   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000

which is not yet the same as the Matlab result.

I suspect, there must be other resulting changes in imtransform.m to adjust to this different thinking of "input space dimension".

Hartmut <hardy>
Wed 15 Apr 2015 08:53:39 PM UTC, comment #3: 

I found some more information on the Matlab behavior here:

http://www.mathworks.com/matlabcentral/answers/67114-what-is-the-difference-between-imwarp-and-imtransform

Two short quotes from this link:

"...imwarp determines and computes the world limits of the input and output images in terms of the outer extents of the first and last pixel in each dimension where as imtransform computes input and output boundaries in terms of the center of the first and last pixel in each dimension."

"I understand that new functions (IMWARP etc..) and the old functions (IMTRANSFORM) differ in the point of application- for example rotation. In the new ones it is image center while in the old ones it is top left corner."

I haven't come to any useful conclusions, though...

There is also a link to this:

http://blogs.mathworks.com/steve/2006/08/01/spatial-transformations-controlling-the-input-and-output-grids-with-imtransform/

Here I found the suspected value of 0.5 for example:

"imtransform assumes that an M-by-N input image lives in input space inside a rectangle spanning from 0.5 to M+0.5 horizontally, and from 0.5 to N+0.5 vertically."

@Pantxo: Maybe those explanations and the code examples help you understand the Matlab behavior of imtransform a bit more...


Hartmut <hardy>
Wed 15 Apr 2015 09:56:43 AM UTC, comment #2: 

If I skip the last column of the transformation matrix, and thus run the following script in Matlab


clear;
M = [0 1 0; 0 1 0; 0 1 0];
a=45;
t = maketform ('affine',[cosd(a) sind(a); -sind(a) cosd(a); 0 0]);
imtrans = imtransform (M,t,'FillValues',0)


Then Matlab gives the following result:


imtrans =

         0         0    0.2426         0
         0    0.4142    0.8787    0.1005
    0.2426    0.8787    0.1716         0
         0    0.1005         0         0


This is the very same result as with the script in my original post. So there stays a discrepancy between Matlab and Octave here.

Intuitivly I would also expect the result of this 45 degree rotation to be symmetric. But it's not symmetric in Matlab.

I know from making a different function of the image package more Matlab compatible, that Matlab sometimes thinks of an image not as numbers on a dicrete grid, but as 1x1 surfaces tiling the plane. This might give an offsset of 0.5 to the center of rotation (or might not?). But that's only my wild speculation. I do not have any more useful clue why the Matlab result is different in this case.

(As I do NOT have Matlab access at the moment, and for the following months, I wouldn't like to do further Matlab test in this matter, sorry. It always means asking a former colleague for help...)

Hartmut <hardy>
Tue 14 Apr 2015 10:43:56 AM UTC, comment #1: 

The third column in the transform matrix is unused for 'affine' transforms. Does simplifying the call as follows change Matlab result:


clear;
pkg load image;

M = [0 1 0; 0 1 0; 0 1 0];
a=45;
t = maketform ('affine',[cosd(a) sind(a); -sind(a) cosd(a); 0 0]);
imtrans = imtransform (M,t,'fillvalues',0)


Also what should we think about the fact that Matlab output is not symmetric? I expect (may be wrong though) symmetries around both diagonals for such rotation of 45°.

Pantxo Diribarne <pantxo>
Group Member
Tue 14 Apr 2015 10:21:45 AM UTC, original submission:  

Here is a simple script to show the behavior:


clear;
pkg load image;

M = [0 1 0; 0 1 0; 0 1 0];
a=45;
t = maketform('affine',[cosd(a) sind(a) 0; -sind(a) cosd(a) 0; 0 0 1]);
imtrans = imtransform(M,t,'fillvalues',0)


The result of current Octave (3.8.2) and the imtransform script from the image package (2.4.0) gives the following result:


      0         0         0          0
      0   0.33333         1          0
      0         1   0.33333          0
      0         0         0          0


Matlab gives this result with different numbers:


      0         0    0.2426          0
      0    0.4142    0.8787     0.1005
 0.2426    0.8787    0.1716          0
      0    0.1005         0          0


Since the applied geometrical transformation is a simple rotation by 45 degrees, I was expecting the same results from both Matlab and Octave. Both do use the same (default) type of interpolation method (bilinear). And both resulting matrices have the same dimensions.

Nevertheless the resulting numbers differ :( What is working different here?

Hartmut <hardy>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #34090:  fix_xyscale2.patch added by pantxo (5KiB - text/x-diff)
file #34091:  fix_xyscale3.patch added by pantxo (1KiB - text/x-diff)
file #34009:  fix_xyscale.patch added by pantxo (6KiB - text/x-diff)
file #33997:  fix_xydata.patch added by pantxo (1KiB - text/x-diff)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by pantxo (Posted a comment)
  • -email is unavailable- added by hardy (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 8 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2015-05-29 carandraug StatusIn Progress Fixed
        Open/ClosedOpen Closed
    2015-05-25 pantxo Attached File- Added fix_xyscale2.patch, #34090
        Attached File- Added fix_xyscale3.patch, #34091
    2015-05-14 pantxo Attached File- Added fix_xyscale.patch, #34009
        StatusNone In Progress
    2015-05-13 hardy Attached File- Added Rotated3PixelSurfaces.png, #34001
    2015-05-13 pantxo Attached File- Added fix_xydata.patch, #33997

    Back to the top

    Powered by Savane 3.13-f8d8.
    Corresponding source code