root / ImageMagick / trunk / magick / distort.c

Revision 12610, 94.9 kB (checked in by cristy, 5 days ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%               DDDD   IIIII  SSSSS  TTTTT   OOO   RRRR   TTTTT               %
7%               D   D    I    SS       T    O   O  R   R    T                 %
8%               D   D    I     SSS     T    O   O  RRRR     T                 %
9%               D   D    I       SS    T    O   O  R R      T                 %
10%               DDDD   IIIII  SSSSS    T     OOO   R  R     T                 %
11%                                                                             %
12%                                                                             %
13%                     ImageMagick Image Distortion Methods.                   %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                              Anthony Thyssen                                %
18%                                 June 2007                                   %
19%                                                                             %
20%                                                                             %
21%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
22%  dedicated to making software imaging solutions freely available.           %
23%                                                                             %
24%  You may not use this file except in compliance with the License.  You may  %
25%  obtain a copy of the License at                                            %
26%                                                                             %
27%    http://www.imagemagick.org/script/license.php                            %
28%                                                                             %
29%  Unless required by applicable law or agreed to in writing, software        %
30%  distributed under the License is distributed on an "AS IS" BASIS,          %
31%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32%  See the License for the specific language governing permissions and        %
33%  limitations under the License.                                             %
34%                                                                             %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/artifact.h"
45#include "magick/cache-view.h"
46#include "magick/colorspace-private.h"
47#include "magick/composite-private.h"
48#include "magick/distort.h"
49#include "magick/exception.h"
50#include "magick/exception-private.h"
51#include "magick/gem.h"
52#include "magick/hashmap.h"
53#include "magick/image.h"
54#include "magick/list.h"
55#include "magick/matrix.h"
56#include "magick/memory_.h"
57#include "magick/monitor-private.h"
58#include "magick/pixel.h"
59#include "magick/pixel-private.h"
60#include "magick/resample.h"
61#include "magick/registry.h"
62#include "magick/semaphore.h"
63#include "magick/string_.h"
64#include "magick/token.h"
65
66/*
67  Numerous internal routines for image distortions.
68*/
69static inline double MagickMin(const double x,const double y)
70{
71  return( x < y ? x : y);
72}
73static inline double MagickMax(const double x,const double y)
74{
75  return( x > y ? x : y);
76}
77
78static inline void AffineArgsToCoefficients(double *affine)
79{
80  /* map  external sx,ry,rx,sy,tx,ty  to  internal c0,c2,c4,c1,c3,c5 */
81  double tmp[4];  /* note indexes  0 and 5 remain unchanged */
82  tmp[0]=affine[1]; tmp[1]=affine[2]; tmp[2]=affine[3]; tmp[3]=affine[4];
83  affine[3]=tmp[0]; affine[1]=tmp[1]; affine[4]=tmp[2]; affine[2]=tmp[3];
84}
85static inline void CoefficientsToAffineArgs(double *coeff)
86{
87  /* map  internal c0,c1,c2,c3,c4,c5  to  external sx,ry,rx,sy,tx,ty */
88  double tmp[4];  /* note indexes 0 and 5 remain unchanged */
89  tmp[0]=coeff[3]; tmp[1]=coeff[1]; tmp[2]=coeff[4]; tmp[3]=coeff[2];
90  coeff[1]=tmp[0]; coeff[2]=tmp[1]; coeff[3]=tmp[2]; coeff[4]=tmp[3];
91}
92static void InvertAffineCoefficients(const double *coeff,double *inverse)
93{
94  /* From "Digital Image Warping" by George Wolberg, page 50 */
95  double determinant;
96
97  determinant=1.0/(coeff[0]*coeff[4]-coeff[1]*coeff[3]);
98  inverse[0]=determinant*coeff[4];
99  inverse[1]=determinant*(-coeff[1]);
100  inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[2]*coeff[4]);
101  inverse[3]=determinant*(-coeff[3]);
102  inverse[4]=determinant*coeff[0];
103  inverse[5]=determinant*(coeff[2]*coeff[3]-coeff[0]*coeff[5]);
104}
105
106static void InvertPerspectiveCoefficients(const double *coeff,
107  double *inverse)
108{
109  /* From "Digital Image Warping" by George Wolberg, page 53 */
110  double determinant;
111
112  determinant=1.0/(coeff[0]*coeff[4]-coeff[3]*coeff[1]);
113  inverse[0]=determinant*(coeff[4]-coeff[7]*coeff[5]);
114  inverse[1]=determinant*(coeff[7]*coeff[2]-coeff[1]);
115  inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[4]*coeff[2]);
116  inverse[3]=determinant*(coeff[6]*coeff[5]-coeff[3]);
117  inverse[4]=determinant*(coeff[0]-coeff[6]*coeff[2]);
118  inverse[5]=determinant*(coeff[3]*coeff[2]-coeff[0]*coeff[5]);
119  inverse[6]=determinant*(coeff[3]*coeff[7]-coeff[6]*coeff[4]);
120  inverse[7]=determinant*(coeff[6]*coeff[1]-coeff[0]*coeff[7]);
121}
122
123static inline double MagickRound(double x)
124{
125  /* round the fraction to nearest integer */
126  if (x >= 0.0)
127    return((double) ((long) (x+0.5)));
128  return((double) ((long) (x-0.5)));
129}
130
131static unsigned long poly_number_terms(double order)
132{
133  /* Return the number of terms for a 2d polynomial
134     Order must either be an integer, or 1.5 to produce
135     the 2 number_valuesal polyminal function...
136        affine     1 (3)      u = c0 + c1*x + c2*y
137        bilinear  1.5 (4)     u = '' + c3*x*y
138        quadratic  2 (6)      u = '' + c4*x*x + c5*y*y
139        cubic      3 (10)     u = '' + c6*x^3 + c7*x*x*y + c8*x*y*y + c9*y^3
140        quartic    4 (15)     u = '' + c10*x^4 + ... + c14*y^4
141        quintic    5 (21)     u = '' + c15*x^5 + ... + c20*y^5
142     number in parenthesis minimum number of points needed.
143     Anything beyond quintic, has not been implemented until
144     a more automated way of determined terms is found.
145   */
146  if ( order < 1 || order > 5 ||
147       ( order != floor(order) && (order-1.5) > MagickEpsilon) )
148    return 0; /* invalid polynomial order */
149  return ((unsigned long) floor((order+1)*(order+2)/2));
150}
151
152static double poly_basis_fn(long n, double x, double y)
153{
154  /* return the result for this polynomial term */
155  switch(n) {
156    case  0return( 1.0 ); /* constant */
157    case  1return(  x  );
158    case  2return(  y  ); /* affine      order = 1   terms = 3 */
159    case  3return( x*y ); /* bilinear    order = 1.5 terms = 4 */
160    case  4return( x*x );
161    case  5return( y*y ); /* quadratic   order = 2   terms = 6 */
162    case  6return( x*x*x );
163    case  7return( x*x*y );
164    case  8return( x*y*y );
165    case  9return( y*y*y ); /* cubic       order = 3   terms = 10 */
166    case 10return( x*x*x*x );
167    case 11return( x*x*x*y );
168    case 12return( x*x*y*y );
169    case 13return( x*y*y*y );
170    case 14return( y*y*y*y ); /* quartic     order = 4   terms = 15 */
171    case 15return( x*x*x*x*x );
172    case 16return( x*x*x*x*y );
173    case 17return( x*x*x*y*y );
174    case 18return( x*x*y*y*y );
175    case 19return( x*y*y*y*y );
176    case 20return( y*y*y*y*y ); /* quintic     order = 5   terms = 21 */
177  }
178  return( 0 ); /* should never happen */
179}
180static const char *poly_basis_str(long n)
181{
182  /* return the result for this polynomial term */
183  switch(n) {
184    case  0return(""); /* constant */
185    case  1return("*ii");
186    case  2return("*jj"); /* affiine      order = 1   terms = 3 */
187    case  3return("*ii*jj"); /* biiliinear    order = 1.5 terms = 4 */
188    case  4return("*ii*ii");
189    case  5return("*jj*jj"); /* quadratiic   order = 2   terms = 6 */
190    case  6return("*ii*ii*ii");
191    case  7return("*ii*ii*jj");
192    case  8return("*ii*jj*jj");
193    case  9return("*jj*jj*jj"); /* cubiic       order = 3   terms = 10 */
194    case 10return("*ii*ii*ii*ii");
195    case 11return("*ii*ii*ii*jj");
196    case 12return("*ii*ii*jj*jj");
197    case 13return("*ii*jj*jj*jj");
198    case 14return("*jj*jj*jj*jj"); /* quartiic     order = 4   terms = 15 */
199    case 15return("*ii*ii*ii*ii*ii");
200    case 16return("*ii*ii*ii*ii*jj");
201    case 17return("*ii*ii*ii*jj*jj");
202    case 18return("*ii*ii*jj*jj*jj");
203    case 19return("*ii*jj*jj*jj*jj");
204    case 20return("*jj*jj*jj*jj*jj"); /* quiintiic     order = 5   terms = 21 */
205  }
206  return( "UNKNOWN" ); /* should never happen */
207}
208static double poly_basis_dx(long n, double x, double y)
209{
210  /* polynomial term for x derivative */
211  switch(n) {
212    case  0return( 0.0 ); /* constant */
213    case  1return( 1.0 );
214    case  2return( 0.0 ); /* affine      order = 1   terms = 3 */
215    case  3return(  y  ); /* bilinear    order = 1.5 terms = 4 */
216    case  4return(  x  );
217    case  5return( 0.0 ); /* quadratic   order = 2   terms = 6 */
218    case  6return( x*x );
219    case  7return( x*y );
220    case  8return( y*y );
221    case  9return( 0.0 ); /* cubic       order = 3   terms = 10 */
222    case 10return( x*x*x );
223    case 11return( x*x*y );
224    case 12return( x*y*y );
225    case 13return( y*y*y );
226    case 14return( 0.0 ); /* quartic     order = 4   terms = 15 */
227    case 15return( x*x*x*x );
228    case 16return( x*x*x*y );
229    case 17return( x*x*y*y );
230    case 18return( x*y*y*y );
231    case 19return( y*y*y*y );
232    case 20return( 0.0 ); /* quintic     order = 5   terms = 21 */
233  }
234  return( 0.0 ); /* should never happen */
235}
236static double poly_basis_dy(long n, double x, double y)
237{
238  /* polynomial term for y derivative */
239  switch(n) {
240    case  0return( 0.0 ); /* constant */
241    case  1return( 0.0 );
242    case  2return( 1.0 ); /* affine      order = 1   terms = 3 */
243    case  3return(  x  ); /* bilinear    order = 1.5 terms = 4 */
244    case  4return( 0.0 );
245    case  5return(  y  ); /* quadratic   order = 2   terms = 6 */
246    defaultreturn( poly_basis_dx(n-1,x,y) ); /* weird but true */
247  }
248  /* NOTE: the only reason that last is not true for 'quadtratic'
249     is due to the re-arrangement of terms to allow for 'bilinear'
250  */
251}
252
253/*
254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255%                                                                             %
256%                                                                             %
257%                                                                             %
258+   G e n e r a t e C o e f f i c i e n t s                                   %
259%                                                                             %
260%                                                                             %
261%                                                                             %
262%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263%
264%  GenerateCoefficients() takes user provided input arguments and generates
265%  the coefficients, needed to apply the specific distortion for either
266%  distorting images (generally using control points) or generating a color
267%  gradient from sparsely separated color points.
268%
269%  The format of the GenerateCoefficients() method is:
270%
271%    Image *GenerateCoefficients(const Image *image, DistortImageMethod method,
272%        const unsigned long number_arguments,const double *arguments,
273%        unsigned long number_values, ExceptionInfo *exception)
274%
275%  A description of each parameter follows:
276%
277%    o image: the image to be distorted.
278%
279%    o method: the method of image distortion/ sparse gradient
280%
281%    o number_arguments: the number of arguments given.
282%
283%    o arguments: the arguments for this distortion method.
284%
285%    o number_values: the style and format of given control points, (caller type)
286%         0: 2 dimensional mapping of control points (Distort)
287%            Format:  u,v,x,y  where u,v is the 'source' of the
288%            the color to be plotted, for DistortImage()
289%         N: Interpolation of control points with N values (usally r,g,b)
290%            Format: x,y,r,g,b    mapping x,y to color values r,g,b
291%            IN future, varible number of values may be given (1 to N)
292%
293%    o exception: Return any errors or warnings in this structure
294%
295%  Note that the returned array of double values must be freed by the
296%  calling method using RelinquishMagickMemory().  This however may change in
297%  the future to require a more 'method' specific method.
298%
299%  Because of this this method should not be classed as stable or used
300%  outside other MagickCore library methods.
301*/
302
303static double *GenerateCoefficients(const Image *image,
304  DistortImageMethod *method,const unsigned long number_arguments,
305  const double *arguments,unsigned long number_values,ExceptionInfo *exception)
306{
307  double
308    *coeff;
309
310  register unsigned long
311    i;
312
313  unsigned long
314    number_coeff, /* number of coefficients to return (array size) */
315    cp_size,      /* number floating point numbers per control point */
316    cp_x,cp_y,    /* the x,y indexes for control point */
317    cp_values;    /* index of values for this control point */
318    /* number_values   Number of values given per control point */
319
320  if ( number_values == 0 ) {
321    /* Image distortion using control points (or other distortion)
322       That is generate a mapping so that   x,y->u,v   given  u,v,x,y
323    */
324    number_values = 2;   /* special case: two values of u,v */
325    cp_values = 0;       /* with the values are BEFORE the CP x,y */
326    cp_x = 2;            /* location of x,y in input control values */
327    cp_y = 3;
328    /* NOTE: cp_values, also used for later 'reverse map distort' tests */
329  }
330  else {
331    cp_x = 0;            /* location of x,y in input control values */
332    cp_y = 1;
333    cp_values = 2;       /* and the other values are after x,y */
334    /* Typically in this case the values are R,G,B color values */
335  }
336  cp_size = number_values+2; /* each CP defintion involves this many numbers */
337
338
339  /* If not enough control point pairs are found for specific distortions
340    fall back to Affine distortion (allowing 0 to 3 point pairs)
341  */
342  if ( number_arguments < 4*cp_size &&
343       (  *method == BilinearDistortion
344       || *method == PerspectiveDistortion
345       ) )
346    *method = AffineDistortion;
347
348  switch (*method) {
349    case AffineDistortion:
350    /* also BarycentricColorInterpolate: */
351      number_coeff=3*number_values;
352      break;
353    case BilinearDistortion:
354      number_coeff=4*number_values;
355      break;
356    case PolynomialDistortion:
357      /* number of coefficents depend on the given polynomal 'order' */
358      if ( number_arguments <= 1 && (number_arguments-1)%cp_size != 0)
359      {
360        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
361                   "InvalidArgument","%s : '%s'","Polynomial",
362                   "Invalid number of args: order [CPs]...");
363        return((double *) NULL);
364      }
365      i = poly_number_terms(arguments[0]);
366      number_coeff = 2 + i*number_values;
367      if ( i == 0 ) {
368        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
369                   "InvalidArgument","%s : '%s'","Polynomial",
370                   "Invalid order, should be 1 to 5, or 1.5");
371        return((double *) NULL);
372      }
373      if ( number_arguments < 1+i*cp_size ) {
374        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
375               "InvalidArgument", "%s : 'require at least %ld CPs'",
376               "Polynomial", i);
377        return((double *) NULL);
378      }
379      break;
380    /* The rest are constants as they are only used for image distorts */
381    case ShepardsDistortion:
382    case VoronoiColorInterpolate:
383      number_coeff=1;  /* may not be used, but provide some type of return */
384      break;
385    case ArcDistortion:
386      number_coeff=5;
387      break;
388    case ScaleRotateTranslateDistortion:
389    case AffineProjectionDistortion:
390      number_coeff=6;
391      break;
392    case PolarDistortion:
393    case DePolarDistortion:
394      number_coeff=8;
395      number_coeff=8;
396      break;
397    case PerspectiveDistortion:
398    case PerspectiveProjectionDistortion:
399      number_coeff=9;
400      break;
401    case BarrelDistortion:
402    case BarrelInverseDistortion:
403      number_coeff=10;
404      break;
405    case UndefinedDistortion:
406    default:
407      assert(! "Unknown Method Given"); /* just fail assertion */
408  }
409
410  /* allocate the array of coefficients needed */
411  coeff = (double *) AcquireQuantumMemory(number_coeff,sizeof(*coeff));
412  if (coeff == (double *) NULL) {
413    (void) ThrowMagickException(exception,GetMagickModule(),
414                  ResourceLimitError,"MemoryAllocationFailed",
415                  "%s", "GenerateCoefficients");
416    return((double *) NULL);
417  }
418
419  /* zero out coeffiecents array */
420  for (i=0; i < number_coeff; i++)
421    coeff[i] = 0.0;
422
423  switch (*method)
424  {
425    case AffineDistortion:
426    {
427      /* Affine Distortion
428           v =  c0*x + c1*y + c2
429         for each 'value' given
430
431         Input Arguments are sets of control points...
432         For Distort Images    u,v, x,y  ...
433         For Sparse Gradients  x,y, r,g,b  ...
434      */
435      if ( number_arguments%cp_size != 0 ||
436           number_arguments < cp_size ) {
437        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
438               "InvalidArgument", "%s : 'require at least %ld CPs'",
439               "Affine", 1L);
440        coeff=(double *) RelinquishMagickMemory(coeff);
441        return((double *) NULL);
442      }
443      /* handle special cases of not enough arguments */
444      if ( number_arguments == cp_size ) {
445        /* Only 1 CP Set Given */
446        if ( cp_values == 0 ) {
447          /* image distortion - translate the image */
448          coeff[0] = 1.0;
449          coeff[2] = arguments[0] - arguments[2];
450          coeff[4] = 1.0;
451          coeff[5] = arguments[1] - arguments[3];
452        }
453        else {
454          /* sparse gradient - use the values directly */
455          for (i=0; i<number_values; i++)
456            coeff[i*3+2] = arguments[cp_values+i];
457        }
458      }
459      else {
460        /* 2 or more points (usally 3) given.
461           Solve a least squares simultanious equation for coefficients.
462        */
463        double
464          **matrix,
465          **vectors,
466          terms[3];
467
468        MagickBooleanType
469          status;
470
471        /* create matrix, and a fake vectors matrix */
472        matrix = AcquireMagickMatrix(3UL,3UL);
473        vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
474        if (matrix == (double **) NULL || vectors == (double **) NULL)
475        {
476          matrix  = RelinquishMagickMatrix(matrix, 3UL);
477          vectors = (double **) RelinquishMagickMemory(vectors);
478          coeff   = (double *) RelinquishMagickMemory(coeff);
479          (void) ThrowMagickException(exception,GetMagickModule(),
480                  ResourceLimitError,"MemoryAllocationFailed",
481                  "%s", "DistortCoefficients");
482          return((double *) NULL);
483        }
484        /* fake a number_values x3 vectors matrix from coefficients array */
485        for (i=0; i < number_values; i++)
486          vectors[i] = &(coeff[i*3]);
487        /* Add given control point pairs for least squares solving */
488        for (i=0; i < number_arguments; i+=cp_size) {
489          terms[0] = arguments[i+cp_x];  /* x */
490          terms[1] = arguments[i+cp_y];  /* y */
491          terms[2] = 1;                  /* 1 */
492          LeastSquaresAddTerms(matrix,vectors,terms,
493                   &(arguments[i+cp_values]),3UL,number_values);
494        }
495        if ( number_arguments == 2*cp_size ) {
496          /* Only two pairs were given, but we need 3 to solve the affine.
497             Fake extra coordinates by rotating p1 around p0 by 90 degrees.
498               x2 = x0 - (y1-y0)   y2 = y0 + (x1-x0)
499           */
500          terms[0] = arguments[cp_x]
501                   - ( arguments[cp_size+cp_y] - arguments[cp_y] ); /* x2 */
502          terms[1] = arguments[cp_y] +
503                   + ( arguments[cp_size+cp_x] - arguments[cp_x] ); /* y2 */
504          terms[2] = 1;                                             /* 1 */
505          if ( cp_values == 0 ) {
506            /* Image Distortion - rotate the u,v coordients too */
507            double
508              uv2[2];
509            uv2[0] = arguments[0] - arguments[5] + arguments[1];   /* u2 */
510            uv2[1] = arguments[1] + arguments[4] - arguments[0];   /* v2 */
511            LeastSquaresAddTerms(matrix,vectors,terms,uv2,3UL,2UL);
512          }
513          else {
514            /* Sparse Gradient - use values of p0 for linear gradient */
515            LeastSquaresAddTerms(matrix,vectors,terms,
516                  &(arguments[cp_values]),3UL,number_values);
517          }
518        }
519        /* Solve for LeastSquares Coefficients */
520        status=GaussJordanElimination(matrix,vectors,3UL,number_values);
521        matrix = RelinquishMagickMatrix(matrix, 3UL);
522        vectors = (double **) RelinquishMagickMemory(vectors);
523        if ( status == MagickFalse ) {
524          coeff = (double *) RelinquishMagickMemory(coeff);
525          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
526                      "InvalidArgument","%s : '%s'","Affine",
527                      "Unsolvable Matrix");
528          return((double *) NULL);
529        }
530      }
531      return(coeff);
532    }
533    case AffineProjectionDistortion:
534    {
535      /*
536        Arguments: Affine Matrix (forward mapping)
537        Arguments  sx, rx, ry, sy, tx, ty
538        Where      u = sx*x + ry*y + tx
539                   v = rx*x + sy*y + ty
540
541        Returns coefficients (in there inverse form) ordered as...
542             sx ry tx  rx sy ty
543
544        AffineProjection Distortion Notes...
545           + Will only work with a 2 number_values for Image Distortion
546           + Can not be used for generating a sparse gradient (interpolation)
547      */
548      double inverse[8];
549      if (number_arguments != 6) {
550        coeff = (double *) RelinquishMagickMemory(coeff);
551        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
552                     "InvalidArgument","%s : '%s'","AffineProjection",
553                     "Needs 6 coeff values");
554        return((double *) NULL);
555      }
556      /* FUTURE: trap test for sx*sy-rx*ry == 0 (determinate = 0, no inverse) */
557      for(i=0; i<6UL; i++ )
558        inverse[i] = arguments[i];
559      AffineArgsToCoefficients(inverse); /* map into coefficents */
560      InvertAffineCoefficients(inverse, coeff); /* invert */
561      *method = AffineDistortion;
562
563      return(coeff);
564    }
565    case ScaleRotateTranslateDistortion:
566    {
567      /* Scale, Rotate and Translate Distortion
568         An alturnative Affine Distortion
569         Argument options, by number of arguments given:
570           7: x,y, sx,sy, a, nx,ny
571           6: x,y,   s,   a, nx,ny
572           5: x,y, sx,sy, a
573           4: x,y,   s,   a
574           3: x,y,        a
575           2:        s,   a
576           1:             a
577         Where actions are (in order of application)
578            x,y     'center' of transforms     (default = image center)
579            sx,sy   scale image by this amount (default = 1)
580            a       angle of rotation          (argument required)
581            nx,ny   move 'center' here         (default = no movement)
582         And convert to affine mapping coefficients
583
584         ScaleRotateTranslate Distortion Notes...
585           + Does not use a set of CPs in any normal way
586           + Will only work with a 2 number_valuesal Image Distortion
587           + Can not be used for generating a sparse gradient (interpolation)
588      */
589      double
590        cosine, sine,
591        x,y,sx,sy,a,nx,ny;
592
593      /* set default center, and default scale */
594      x = nx = (double)(image->columns-1.0)/2.0 + image->page.x;
595      y = ny = (double)(image->rows-1.0)/2.0    + image->page.y;
596      sx = sy = 1.0;
597      switch ( number_arguments ) {
598      case 0:
599        coeff = (double *) RelinquishMagickMemory(coeff);
600        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
601                     "InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
602                     "Needs at least 1 argument");
603        return((double *) NULL);
604      case 1:
605        a = arguments[0];
606        break;
607      case 2:
608        sx = sy = arguments[0];
609        a = arguments[1];
610        break;
611      default:
612        x = nx = arguments[0];
613        y = ny = arguments[1];
614        switch ( number_arguments ) {
615        case 3:
616          a = arguments[2];
617          break;
618        case 4:
619          sx = sy = arguments[2];
620          a = arguments[3];
621          break;
622        case 5:
623          sx = arguments[2];
624          sy = arguments[3];
625          a = arguments[4];
626          break;
627        case 6:
628          sx = sy = arguments[2];
629          a = arguments[3];
630          nx = arguments[4];
631          ny = arguments[5];
632          break;
633        case 7:
634          sx = arguments[2];
635          sy = arguments[3];
636          a = arguments[4];
637          nx = arguments[5];
638          ny = arguments[6];
639          break;
640        default:
641          coeff = (double *) RelinquishMagickMemory(coeff);
642          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
643                     "InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
644                     "Too Many Arguments (7 or less)");
645          return((double *) NULL);
646        }
647        break;
648      }
649      /* Trap if sx or sy == 0 -- image is scaled out of existance! */
650      if ( fabs(sx) < MagickEpsilon || fabs(sy) < MagickEpsilon ) {
651        coeff = (double *) RelinquishMagickMemory(coeff);
652        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
653                     "InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
654                     "Zero Scale Given");
655        return((double *) NULL);
656      }
657      /* Save the given arguments as an affine distortion */
658      a=DegreesToRadians(a); cosine=cos(a); sine=sin(a);
659
660      *method = AffineDistortion;
661      coeff[0]=cosine/sx;
662      coeff[1]=sine/sx;
663      coeff[2]=x-nx*coeff[0]-ny*coeff[1];
664      coeff[3]=(-sine)/sy;
665      coeff[4]=cosine/sy;
666      coeff[5]=y-nx*coeff[3]-ny*coeff[4];
667      return(coeff);
668    }
669    case PerspectiveDistortion:
670    { /*
671         Perspective Distortion (a ratio of affine distortions)
672
673                p(x,y)    c0*x + c1*y + c2
674            u = ------ = ------------------
675                r(x,y)    c6*x + c7*y + 1
676
677                q(x,y)    c3*x + c4*y + c5
678            v = ------ = ------------------
679                r(x,y)    c6*x + c7*y + 1
680
681           c8 = Sign of 'r', or the denominator affine, for the actual image.
682                This determines what part of the distorted image is 'ground'
683                side of the horizon, the other part is 'sky' or invalid.
684                Valid values are  +1.0  or  -1.0  only.
685
686         Input Arguments are sets of control points...
687         For Distort Images    u,v, x,y  ...
688         For Sparse Gradients  x,y, r,g,b  ...
689
690         Perspective Distortion Notes...
691           + Can be thought of as ratio of  3 affine transformations
692           + Not separatable: r() or c6 and c7 are used by both equations
693           + All 8 coefficients must be determined simultaniously
694           + Will only work with a 2 number_valuesal Image Distortion
695           + Can not be used for generating a sparse gradient (interpolation)
696           + It is not linear, but is simple to generate an inverse
697           + All lines within an image remain lines.
698           + but distances between points may vary.
699      */
700      double
701        **matrix,
702        *vectors[1],
703        terms[8];
704
705      unsigned long
706        cp_u = cp_values,
707        cp_v = cp_values+1;
708
709      MagickBooleanType
710        status;
711
712      /* fake 1x8 vectors matrix directly using the coefficients array */
713      vectors[0] = &(coeff[0]);
714      /* 8x8 least-squares matrix (zeroed) */
715      matrix = AcquireMagickMatrix(8UL,8UL);
716      if (matrix == (double **) NULL) {
717        (void) ThrowMagickException(exception,GetMagickModule(),
718                  ResourceLimitError,"MemoryAllocationFailed",
719                  "%s", "DistortCoefficients");
720        return((double *) NULL);
721      }
722      /* Add control points for least squares solving */
723      for (i=0; i < number_arguments; i+=4) {
724        terms[0]=arguments[i+cp_x];            /*   c0*x   */
725        terms[1]=arguments[i+cp_y];            /*   c1*y   */
726        terms[2]=1.0;                          /*   c2*1   */
727        terms[3]=0.0;
728        terms[4]=0.0;
729        terms[5]=0.0;
730        terms[6]=-terms[0]*arguments[i+cp_u];  /* 1/(c6*x) */
731        terms[7]=-terms[1]*arguments[i+cp_u];  /* 1/(c7*y) */
732        LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_u]),
733            8UL,1UL);
734
735        terms[0]=0.0;
736        terms[1]=0.0;
737        terms[2]=0.0;
738        terms[3]=arguments[i+cp_x];           /*   c3*x   */
739        terms[4]=arguments[i+cp_y];           /*   c4*y   */
740        terms[5]=1.0;                         /*   c5*1   */
741        terms[6]=-terms[3]*arguments[i+cp_v]; /* 1/(c6*x) */
742        terms[7]=-terms[4]*arguments[i+cp_v]; /* 1/(c7*y) */
743        LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_v]),
744            8UL,1UL);
745      }
746      /* Solve for LeastSquares Coefficients */
747      status=GaussJordanElimination(matrix,vectors,8UL,1UL);
748      matrix = RelinquishMagickMatrix(matrix, 8UL);
749      if ( status == MagickFalse ) {
750        coeff = (double *) RelinquishMagickMemory(coeff);
751        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
752                    "InvalidArgument","%s : '%s'","Perspective",
753                    "Unsolvable Matrix");
754        return((double *) NULL);
755      }
756      /*
757        Calculate 9'th coefficient! The ground-sky determination.
758        What is sign of the 'ground' in r() denominator affine function?
759        Just use any valid image coordinate (first control point) in
760        destination for determination of what part of view is 'ground'.
761      */
762      coeff[8] = coeff[6]*arguments[cp_x]
763                      + coeff[7]*arguments[cp_y] + 1.0;
764      coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0;
765
766      return(coeff);
767    }
768    case PerspectiveProjectionDistortion:
769    {
770      /*
771        Arguments: Perspective Coefficents (forward mapping)
772      */
773      if (number_arguments != 8) {
774        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
775                     "InvalidArgument","%s : '%s'","PerspectiveProjection",
776                     "Needs 8 coefficient values");
777        return((double *) NULL);
778      }
779      /* FUTURE: trap test  c0*c4-c3*c1 == 0  (determinate = 0, no inverse) */
780      InvertPerspectiveCoefficients(arguments, coeff);
781      /*
782        Calculate 9'th coefficient! The ground-sky determination.
783        What is sign of the 'ground' in r() denominator affine function?
784        Just use any valid image cocodinate in destination for determination.
785        For a forward mapped perspective the images 0,0 coord will map to
786        c2,c5 in the distorted image, so set the sign of denominator of that.
787      */
788      coeff[8] = coeff[6]*arguments[2]
789                           + coeff[7]*arguments[5] + 1.0;
790      coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0;
791      *method = PerspectiveDistortion;
792
793      return(coeff);
794    }
795    case BilinearDistortion:
796    {
797      /* Bilinear Distortion
798            v = c0*x + c1*y + c2*x*y + c3;
799         for each 'value' given
800
801         Input Arguments are sets of control points...
802         For Distort Images    u,v, x,y  ...
803         For Sparse Gradients  x,y, r,g,b  ...
804
805         Bilinear Distortion Notes...
806           + This a reversed mapped distortion
807           + Can map source orthogonal rectangles to non-planar quadraterials
808           + may be used for generating forward mapped 'grid' interpolation
809      */
810      double
811        **matrix,
812        **vectors,
813        terms[4];
814
815      MagickBooleanType
816        status;
817
818      /* create matrix, and a fake vectors matrix */
819      matrix = AcquireMagickMatrix(4UL,4UL);
820      vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
821      if (matrix == (double **) NULL || vectors == (double **) NULL)
822      {
823        matrix  = RelinquishMagickMatrix(matrix, 4UL);
824        vectors = (double **) RelinquishMagickMemory(vectors);
825        coeff   = (double *) RelinquishMagickMemory(coeff);
826        (void) ThrowMagickException(exception,GetMagickModule(),
827                ResourceLimitError,"MemoryAllocationFailed",
828                "%s", "DistortCoefficients");
829        return((double *) NULL);
830      }
831      /* fake a number_values x3 vectors matrix from coefficients array */
832      for (i=0; i < number_values; i++)
833        vectors[i] = &(coeff[i*4]);
834      /* Add given control point pairs for least squares solving */
835      for (i=0; i < number_arguments; i+=cp_size) {
836        terms[0] = arguments[i+cp_x];   /*  x  */
837        terms[1] = arguments[i+cp_y];   /*  y  */
838        terms[2] = terms[0]*terms[1];   /* x*y */
839        terms[3] = 1;                   /*