Page 1 of 1

Possible bug in MagickDistortImage

Posted: 2008-11-24T19:11:06-07:00
by el_supremo
I've been playing with affine transformations (which will eventually end up in my MagickWand examples) and the program below rotates the logo: image clockwise by 90 degrees and requests that the distorted result be retained (otherwise the result is a white image). The logo: image is 640x480 but the final image is 481x641. Is this just a result of round-off or some other unavoidable feature of the affine transformation, or is it a bug in the way the bestfit is made?
The program first puts a black pixel in each corner of logo: so that you can see that in the final image the top row and right edge have each been extended by one pixel to produce the extension from the expected 480x630 to 481x641.

Pete

Code: Select all

#include <windows.h>
#include <wand/magick_wand.h>
#define _USE_MATH_DEFINES
#include <math.h>
#define DegreesToRadians(a) (a*M_PI/180.)

// Set the affine array to rotate image by 'degrees' clockwise
double *set_rotate_affine(double r[],double degrees)
{
	r[0] = cos(DegreesToRadians(fmod(degrees,360.0)));
	r[1] = sin(DegreesToRadians(fmod(degrees,360.0)));
	r[2] = -sin(DegreesToRadians(fmod(degrees,360.0)));
	r[3] = cos(DegreesToRadians(fmod(degrees,360.0)));
	r[4] = 0;
	r[5] = 0;
	return(r);
}
void test_wand(void) {
{
	double r[6];
	DrawingWand *dw = NULL;
	PixelWand *pw = NULL;
	MagickWand *mw = NULL;

	MagickWandGenesis();
	mw=NewMagickWand();
	MagickReadImage(mw,"logo:");

	// Put a black pixel in each of the corners
	pw = NewPixelWand();
	dw = NewDrawingWand();
	PixelSetColor(pw,"black");
	DrawSetFillColor(dw,pw);
	DrawPoint(dw,0,0);
	DrawPoint(dw,0,479);
	DrawPoint(dw,639,479);
	DrawPoint(dw,639,0);
	MagickDrawImage(mw,dw);

	// Do the affine rotation
	MagickDistortImage(mw,AffineProjectionDistortion,
							6,set_rotate_affine(r,90),MagickTrue);
							
	// Output as GIF - avoid JPG artifacts
	MagickWriteImage(mw,"logo_affine_4.gif");
	if(mw)mw = DestroyMagickWand(mw);
	if(dw)dw = DestroyDrawingWand(dw);
	if(pw)pw = DestroyPixelWand(pw);
	MagickWandTerminus();
}

Re: Possible bug in MagickDistortImage

Posted: 2008-11-25T21:58:14-07:00
by anthony
With MagickTrue flag the distort is equivelent to +distort.

this can result in the image being enlarged slightly to ensure that semi-tranparent edge pixels are captured by the distort process.

Essentually the distort function tries to forward map the corners (or other parts) of the image into distorted space to try to figure out how big the destination image should and with what offset on the virtual canvas. These calculated locations are floating point, and yet the virtual canvas is only specified in intergers (image size and offset (may be a negative offset!). The virtual canvas size itself is best fited to this, though really it is non-sensical without further input from the user (say due to multiple layers and a -layers merge)

The float to interger rounding is not perfect, and can result in a 1 or 2 pixel size difference, and a posible -1 offset difference.

Basicaly it depends on just how well the forward map is handled.

Note the distortion itself is a reverse mapping, and sometimes a forward mapping is not available! For example in Shepards Distortions or Barrel Distortions.

Note setting MagickTrue (using MagickFalse) so as to use the original image size and offset as the viewport, OR supplying a distort:viewport setting will override this calculation.

Basically I have tries to make distort as 'virtual canvas friendly' as I can. You are welcome to check the code, or make suggestions. In fact I welcome any programmer input. Work commitments are keeping me too busy for much coding time.

Just look at 'magick/distort.c'
A view from other programmers would be very helpful at this point.