56
56
#include "magick/matrix.h"
57
57
#include "magick/memory_.h"
58
58
#include "magick/monitor-private.h"
59
#include "magick/option.h"
60
59
#include "magick/pixel.h"
61
60
#include "magick/pixel-private.h"
62
61
#include "magick/resample.h"
129
128
static inline double MagickRound(double x)
132
Round the fraction to nearest integer.
130
/* round the fraction to nearest integer */
135
return((double) ((ssize_t) (x+0.5)));
136
return((double) ((ssize_t) (x-0.5)));
132
return((double) ((long) (x+0.5)));
133
return((double) ((long) (x-0.5)));
155
152
* which is to allow the use of a bi-linear (order=1.5) polynomial.
156
153
* All the later polynomials are ordered simply from x^N to y^N
158
static size_t poly_number_terms(double order)
155
static unsigned long poly_number_terms(double order)
160
157
/* Return the number of terms for a 2d polynomial */
161
158
if ( order < 1 || order > 5 ||
162
159
( order != floor(order) && (order-1.5) > MagickEpsilon) )
163
160
return 0; /* invalid polynomial order */
164
return((size_t) floor((order+1)*(order+2)/2));
161
return((unsigned long) floor((order+1)*(order+2)/2));
167
static double poly_basis_fn(ssize_t n, double x, double y)
164
static double poly_basis_fn(long n, double x, double y)
169
166
/* Return the result for this polynomial term */
221
218
return( "UNKNOWN" ); /* should never happen */
223
static double poly_basis_dx(ssize_t n, double x, double y)
220
static double poly_basis_dx(long n, double x, double y)
225
222
/* polynomial term for x derivative */
249
246
return( 0.0 ); /* should never happen */
251
static double poly_basis_dy(ssize_t n, double x, double y)
248
static double poly_basis_dy(long n, double x, double y)
253
250
/* polynomial term for y derivative */
284
281
% The format of the GenerateCoefficients() method is:
286
283
% Image *GenerateCoefficients(const Image *image,DistortImageMethod method,
287
% const size_t number_arguments,const double *arguments,
288
% size_t number_values, ExceptionInfo *exception)
284
% const unsigned long number_arguments,const double *arguments,
285
% unsigned long number_values, ExceptionInfo *exception)
290
287
% A description of each parameter follows:
318
315
static double *GenerateCoefficients(const Image *image,
319
DistortImageMethod *method,const size_t number_arguments,
320
const double *arguments,size_t number_values,ExceptionInfo *exception)
316
DistortImageMethod *method,const unsigned long number_arguments,
317
const double *arguments,unsigned long number_values,ExceptionInfo *exception)
322
register unsigned long
329
326
number_coeff, /* number of coefficients to return (array size) */
330
327
cp_size, /* number floating point numbers per control point */
331
328
cp_x,cp_y, /* the x,y indexes for control point */
353
350
/* If not enough control point pairs are found for specific distortions
354
351
fall back to Affine distortion (allowing 0 to 3 point pairs)
356
if ( number_arguments < 4*cp_size &&
353
if ( number_arguments < 4*cp_size &&
357
354
( *method == BilinearForwardDistortion
358
355
|| *method == BilinearReverseDistortion
359
356
|| *method == PerspectiveDistortion
386
383
if ( number_arguments < 1+i*cp_size ) {
387
384
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
388
"InvalidArgument", "%s : 'require at least %.20g CPs'",
389
"Polynomial", (double) i);
385
"InvalidArgument", "%s : 'require at least %ld CPs'",
390
387
return((double *) NULL);
463
460
if ( number_arguments%cp_size != 0 ||
464
461
number_arguments < cp_size ) {
465
462
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
466
"InvalidArgument", "%s : 'require at least %.20g CPs'",
463
"InvalidArgument", "%s : 'require at least %ld CPs'",
468
465
coeff=(double *) RelinquishMagickMemory(coeff);
469
466
return((double *) NULL);
551
548
if ( status == MagickFalse ) {
552
549
coeff = (double *) RelinquishMagickMemory(coeff);
553
550
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
554
"InvalidArgument","%s : 'Unsolvable Matrix'",
555
MagickOptionToMnemonic(MagickDistortOptions, *method) );
551
"InvalidArgument","%s : '%s'","Affine",
552
"Unsolvable Matrix");
556
553
return((double *) NULL);
577
574
if (number_arguments != 6) {
578
575
coeff = (double *) RelinquishMagickMemory(coeff);
579
576
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
580
"InvalidArgument","%s : 'Needs 6 coeff values'",
581
MagickOptionToMnemonic(MagickDistortOptions, *method) );
577
"InvalidArgument","%s : '%s'","AffineProjection",
578
"Needs 6 coeff values");
582
579
return((double *) NULL);
584
581
/* FUTURE: trap test for sx*sy-rx*ry == 0 (determinate = 0, no inverse) */
627
624
coeff = (double *) RelinquishMagickMemory(coeff);
628
625
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
629
"InvalidArgument","%s : 'Needs at least 1 argument'",
630
MagickOptionToMnemonic(MagickDistortOptions, *method) );
626
"InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
627
"Needs at least 1 argument");
631
628
return((double *) NULL);
633
630
a = arguments[0];
669
666
coeff = (double *) RelinquishMagickMemory(coeff);
670
667
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
671
"InvalidArgument","%s : 'Too Many Arguments (7 or less)'",
672
MagickOptionToMnemonic(MagickDistortOptions, *method) );
668
"InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
669
"Too Many Arguments (7 or less)");
673
670
return((double *) NULL);
678
675
if ( fabs(sx) < MagickEpsilon || fabs(sy) < MagickEpsilon ) {
679
676
coeff = (double *) RelinquishMagickMemory(coeff);
680
677
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
681
"InvalidArgument","%s : 'Zero Scale Given'",
682
MagickOptionToMnemonic(MagickDistortOptions, *method) );
678
"InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
683
680
return((double *) NULL);
685
682
/* Save the given arguments as an affine distortion */
740
737
if ( number_arguments%cp_size != 0 ||
741
738
number_arguments < cp_size*4 ) {
742
739
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
743
"InvalidArgument", "%s : 'require at least %.20g CPs'",
744
MagickOptionToMnemonic(MagickDistortOptions, *method), 4.0);
740
"InvalidArgument", "%s : 'require at least %ld CPs'",
745
742
coeff=(double *) RelinquishMagickMemory(coeff);
746
743
return((double *) NULL);
785
782
if ( status == MagickFalse ) {
786
783
coeff = (double *) RelinquishMagickMemory(coeff);
787
784
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
788
"InvalidArgument","%s : 'Unsolvable Matrix'",
789
MagickOptionToMnemonic(MagickDistortOptions, *method) );
785
"InvalidArgument","%s : '%s'","Perspective",
786
"Unsolvable Matrix");
790
787
return((double *) NULL);
809
806
if (number_arguments != 8) {
810
807
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
811
"InvalidArgument", "%s : 'Needs 8 coefficient values'",
812
MagickOptionToMnemonic(MagickDistortOptions, *method));
808
"InvalidArgument","%s : '%s'","PerspectiveProjection",
809
"Needs 8 coefficient values");
813
810
return((double *) NULL);
815
812
/* FUTURE: trap test c0*c4-c3*c1 == 0 (determinate = 0, no inverse) */
856
853
if ( number_arguments%cp_size != 0 ||
857
854
number_arguments < cp_size*4 ) {
858
855
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
859
"InvalidArgument", "%s : 'require at least %.20g CPs'",
860
MagickOptionToMnemonic(MagickDistortOptions, *method), 4.0);
856
"InvalidArgument", "%s : 'require at least %ld CPs'",
857
*method == BilinearForwardDistortion ? "BilinearForward" :
858
"BilinearReverse", 4L);
861
859
coeff=(double *) RelinquishMagickMemory(coeff);
862
860
return((double *) NULL);
893
891
if ( status == MagickFalse ) {
894
892
coeff = (double *) RelinquishMagickMemory(coeff);
895
893
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
896
"InvalidArgument","%s : 'Unsolvable Matrix'",
897
MagickOptionToMnemonic(MagickDistortOptions, *method) );
894
"InvalidArgument","%s : '%s'",
895
*method == BilinearForwardDistortion ?
896
"BilinearForward" : "BilinearReverse",
897
"Unsolvable Matrix");
898
898
return((double *) NULL);
900
900
if ( *method == BilinearForwardDistortion ) {
906
906
i = c0*x + c1*y + c2*x*y + c3;
907
907
j = c4*x + c5*y + c6*x*y + c7;
909
where i,j are in the destination image, NOT the source.
909
where u,v are in the destination image, NOT the source.
911
911
Reverse Pixel mapping however needs to use reverse of these
912
912
functions. It required a full page of algbra to work out the
999
999
/* first two coefficients hold polynomial order information */
1000
1000
coeff[0] = arguments[0];
1001
1001
coeff[1] = (double) poly_number_terms(arguments[0]);
1002
nterms = (size_t) coeff[1];
1002
nterms = (unsigned long) coeff[1];
1004
1004
/* create matrix, a fake vectors matrix, and least sqs terms */
1005
1005
matrix = AcquireMagickMatrix(nterms,nterms);
1023
1023
vectors[i] = &(coeff[2+i*nterms]);
1024
1024
/* Add given control point pairs for least squares solving */
1025
1025
for (i=1; i < number_arguments; i+=cp_size) { /* NB: start = 1 not 0 */
1026
for (j=0; j < (ssize_t) nterms; j++)
1026
for (j=0; j < (long) nterms; j++)
1027
1027
terms[j] = poly_basis_fn(j,arguments[i+cp_x],arguments[i+cp_y]);
1028
1028
LeastSquaresAddTerms(matrix,vectors,terms,
1029
1029
&(arguments[i+cp_values]),nterms,number_values);
1036
1036
if ( status == MagickFalse ) {
1037
1037
coeff = (double *) RelinquishMagickMemory(coeff);
1038
1038
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1039
"InvalidArgument","%s : 'Unsolvable Matrix'",
1040
MagickOptionToMnemonic(MagickDistortOptions, *method) );
1039
"InvalidArgument","%s : '%s'","Polynomial",
1040
"Unsolvable Matrix");
1041
1041
return((double *) NULL);
1081
1081
if ( number_arguments >= 1 && arguments[0] < MagickEpsilon ) {
1082
1082
coeff = (double *) RelinquishMagickMemory(coeff);
1083
1083
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1084
"InvalidArgument","%s : 'Arc Angle Too Small'",
1085
MagickOptionToMnemonic(MagickDistortOptions, *method) );
1084
"InvalidArgument","%s : '%s'", "Arc",
1085
"Arc Angle Too Small");
1086
1086
return((double *) NULL);
1088
1088
if ( number_arguments >= 3 && arguments[2] < MagickEpsilon ) {
1089
1089
coeff = (double *) RelinquishMagickMemory(coeff);
1090
1090
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1091
"InvalidArgument","%s : 'Outer Radius Too Small'",
1092
MagickOptionToMnemonic(MagickDistortOptions, *method) );
1091
"InvalidArgument","%s : '%s'", "Arc",
1092
"Outer Radius Too Small");
1093
1093
return((double *) NULL);
1095
1095
coeff[0] = -MagickPI2; /* -90, place at top! */
1131
1131
if ( number_arguments == 3
1132
1132
|| ( number_arguments > 6 && *method == PolarDistortion )
1133
1133
|| number_arguments > 8 ) {
1134
(void) ThrowMagickException(exception,GetMagickModule(),
1135
OptionError,"InvalidArgument", "%s : number of arguments",
1136
MagickOptionToMnemonic(MagickDistortOptions, *method) );
1134
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1135
"InvalidArgument", "%s : number of arguments",
1136
*method == PolarDistortion ? "Polar" : "DePolar");
1137
1137
coeff=(double *) RelinquishMagickMemory(coeff);
1138
1138
return((double *) NULL);
1192
1192
if ( coeff[0] < MagickEpsilon || coeff[1] < -MagickEpsilon
1193
1193
|| (coeff[0]-coeff[1]) < MagickEpsilon ) {
1194
1194
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1195
"InvalidArgument", "%s : Invalid Radius",
1196
MagickOptionToMnemonic(MagickDistortOptions, *method) );
1195
"InvalidArgument", "%s : Invalid Radius",
1196
*method == PolarDistortion ? "Polar" : "DePolar");
1197
1197
coeff=(double *) RelinquishMagickMemory(coeff);
1198
1198
return((double *) NULL);
1217
1217
Rs=Rd/(A*Rd^3 + B*Rd^2 + C*Rd + D)
1219
1219
Where Rd is the normalized radius from corner to middle of image
1220
Input Arguments are one of the following forms (number of arguments)...
1225
8: Ax,Bx,Cx,Dx Ay,By,Cy,Dy
1226
10: Ax,Bx,Cx,Dx Ay,By,Cy,Dy X,Y
1220
Input Arguments are one of the following forms...
1225
Ax,Bx,Cx,Dx Ay,By,Cy,Dy
1226
Ax,Bx,Cx,Dx Ay,By,Cy,Dy X,Y
1228
1228
Returns 10 coefficent values, which are de-normalized (pixel scale)
1229
1229
Ax, Bx, Cx, Dx, Ay, By, Cy, Dy, Xc, Yc
1233
1233
rscale = 2.0/MagickMin((double) image->columns,(double) image->rows);
1235
/* sanity check number of args must = 3,4,5,6,8,10 or error */
1236
if ( (number_arguments < 3) || (number_arguments == 7) ||
1237
(number_arguments == 9) || (number_arguments > 10) )
1239
coeff=(double *) RelinquishMagickMemory(coeff);
1240
(void) ThrowMagickException(exception,GetMagickModule(),
1241
OptionError,"InvalidArgument", "%s : number of arguments",
1242
MagickOptionToMnemonic(MagickDistortOptions, *method) );
1243
return((double *) NULL);
1235
if ( number_arguments != 4 && number_arguments != 6 &&
1236
number_arguments != 8 && number_arguments != 10 ) {
1237
coeff=(double *) RelinquishMagickMemory(coeff);
1238
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1239
"InvalidArgument", "%s : '%s'", "Barrel(Inv)",
1240
"number of arguments" );
1241
return((double *) NULL);
1245
1243
/* A,B,C,D coefficients */
1246
1244
coeff[0] = arguments[0];
1247
1245
coeff[1] = arguments[1];
1248
1246
coeff[2] = arguments[2];
1249
if ((number_arguments == 3) || (number_arguments == 5) )
1250
coeff[3] = 1.0 - coeff[0] - coeff[1] - coeff[2];
1247
if ( number_arguments == 3 || number_arguments == 5 )
1248
coeff[3] = 1 - arguments[0] - arguments[1] - arguments[2];
1252
coeff[3] = arguments[3];
1253
/* de-normalize the coefficients */
1250
coeff[3] = arguments[3];
1251
/* de-normalize the X coefficients */
1254
1252
coeff[0] *= pow(rscale,3.0);
1255
1253
coeff[1] *= rscale*rscale;
1256
1254
coeff[2] *= rscale;
1257
/* Y coefficients: as given OR same as X coefficients */
1255
/* Y coefficients: as given OR as X coefficients */
1258
1256
if ( number_arguments >= 8 ) {
1259
1257
coeff[4] = arguments[4] * pow(rscale,3.0);
1260
1258
coeff[5] = arguments[5] * rscale*rscale;
1267
1265
coeff[6] = coeff[2];
1268
1266
coeff[7] = coeff[3];
1270
/* X,Y Center of Distortion (image coodinates) */
1268
/* X,Y Center of Distortion */
1269
coeff[8] = ((double)image->columns-1)/2.0 + image->page.x;
1270
coeff[9] = ((double)image->rows-1)/2.0 + image->page.y;
1271
1271
if ( number_arguments == 5 ) {
1272
1272
coeff[8] = arguments[3];
1273
1273
coeff[9] = arguments[4];
1275
else if ( number_arguments == 6 ) {
1275
if ( number_arguments == 6 ) {
1276
1276
coeff[8] = arguments[4];
1277
1277
coeff[9] = arguments[5];
1279
else if ( number_arguments == 10 ) {
1279
if ( number_arguments == 10 ) {
1280
1280
coeff[8] = arguments[8];
1281
1281
coeff[9] = arguments[9];
1284
/* center of the image provided (image coodinates) */
1285
coeff[8] = (double)image->columns/2.0 + image->page.x;
1286
coeff[9] = (double)image->rows/2.0 + image->page.y;
1290
1285
case ShepardsDistortion:
1298
1293
if ( number_arguments%cp_size != 0 ||
1299
1294
number_arguments < cp_size ) {
1300
1295
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1301
"InvalidArgument", "%s : 'require at least %.20g CPs'",
1302
MagickOptionToMnemonic(MagickDistortOptions, *method), 1.0);
1296
"InvalidArgument", "%s : 'require at least %ld CPs'",
1303
1298
coeff=(double *) RelinquishMagickMemory(coeff);
1304
1299
return((double *) NULL);
1341
1336
% The format of the DistortImage() method is:
1343
1338
% Image *DistortImage(const Image *image,const DistortImageMethod method,
1344
% const size_t number_arguments,const double *arguments,
1339
% const unsigned long number_arguments,const double *arguments,
1345
1340
% MagickBooleanType bestfit, ExceptionInfo *exception)
1347
1342
% A description of each parameter follows:
1404
1399
MagickExport Image *DistortImage(const Image *image,DistortImageMethod method,
1405
const size_t number_arguments,const double *arguments,
1400
const unsigned long number_arguments,const double *arguments,
1406
1401
MagickBooleanType bestfit,ExceptionInfo *exception)
1408
1403
#define DistortImageTag "Distort/Image"
1589
1584
/* direct calculation as it needs to tile correctly
1590
1585
* for reversibility in a DePolar-Polar cycle */
1591
1586
geometry.x = geometry.y = 0;
1592
geometry.height = (size_t) ceil(coeff[0]-coeff[1]);
1593
geometry.width = (size_t)
1587
geometry.height = (unsigned long) ceil(coeff[0]-coeff[1]);
1588
geometry.width = (unsigned long)
1594
1589
ceil((coeff[0]-coeff[1])*(coeff[5]-coeff[4])*0.5);
1608
1603
bestfit = MagickFalse;
1612
/* Set the output image geometry to calculated 'bestfit'.
1613
Yes this tends to 'over do' the file image size, ON PURPOSE!
1614
Do not do this for DePolar which needs to be exact for virtual tiling.
1606
/* Set the output image geometry to calculated 'bestfit'
1607
Do not do this for DePolar which needs to be exact for tiling
1616
1609
if ( bestfit && method != DePolarDistortion ) {
1617
geometry.x = (ssize_t) floor(min.x-0.5);
1618
geometry.y = (ssize_t) floor(min.y-0.5);
1619
geometry.width=(size_t) ceil(max.x-geometry.x+0.5);
1620
geometry.height=(size_t) ceil(max.y-geometry.y+0.5);
1610
geometry.x = (long) floor(min.x-0.5);
1611
geometry.y = (long) floor(min.y-0.5);
1612
geometry.width=(unsigned long) ceil(max.x-geometry.x+0.5);
1613
geometry.height=(unsigned long) ceil(max.y-geometry.y+0.5);
1623
/* Now that we have a new size lets some distortions to it exactly
1624
This is for correct handling of Depolar and its virtual tile handling
1615
/* now that we have a new size lets fit distortion to it exactly */
1626
1616
if ( method == DePolarDistortion ) {
1627
1617
coeff[6]=(coeff[5]-coeff[4])/geometry.width; /* changed width */
1628
1618
coeff[7]=(coeff[0]-coeff[1])/geometry.height; /* should be about 1.0 */
1644
1634
/* Verbose output */
1645
1635
if ( GetImageArtifact(image,"verbose") != (const char *) NULL ) {
1648
1638
char image_gen[MaxTextExtent];
1649
1639
const char *lookup;
1651
1641
/* Set destination image size and virtual offset */
1652
1642
if ( bestfit || viewport_given ) {
1653
(void) FormatMagickString(image_gen, MaxTextExtent," -size %.20gx%.20g "
1654
"-page %+.20gx%+.20g xc: +insert \\\n",(double) geometry.width,
1655
(double) geometry.height,(double) geometry.x,(double) geometry.y);
1643
(void) FormatMagickString(image_gen, MaxTextExtent," -size %lux%lu "
1644
"-page %+ld%+ld xc: +insert \\\n",geometry.width,geometry.height,
1645
geometry.x,geometry.y);
1656
1646
lookup="v.p{ xx-v.page.x-.5, yy-v.page.x-.5 }";
1788
1778
case PolynomialDistortion:
1790
size_t nterms = (size_t) coeff[1];
1780
unsigned long nterms = (unsigned long) coeff[1];
1791
1781
fprintf(stderr, "Polynomial (order %lg, terms %lu), FX Equivelent\n",
1792
coeff[0],(unsigned long) nterms);
1793
1783
fprintf(stderr, "%s", image_gen);
1794
1784
fprintf(stderr, " -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
1795
1785
fprintf(stderr, " xx =");
1796
for (i=0; i<(ssize_t) nterms; i++) {
1786
for (i=0; i<(long) nterms; i++) {
1797
1787
if ( i != 0 && i%4 == 0 ) fprintf(stderr, "\n ");
1798
1788
fprintf(stderr, " %+lf%s", coeff[2+i],
1799
1789
poly_basis_str(i));
1801
1791
fprintf(stderr, ";\n yy =");
1802
for (i=0; i<(ssize_t) nterms; i++) {
1792
for (i=0; i<(long) nterms; i++) {
1803
1793
if ( i != 0 && i%4 == 0 ) fprintf(stderr, "\n ");
1804
1794
fprintf(stderr, " %+lf%s", coeff[2+i+nterms],
1805
1795
poly_basis_str(i));
1812
1802
fprintf(stderr, "Arc Distort, Internal Coefficients:\n");
1813
1803
for ( i=0; i<5; i++ )
1814
fprintf(stderr, " c%.20g = %+lf\n", (double) i, coeff[i]);
1804
fprintf(stderr, " c%ld = %+lf\n", i, coeff[i]);
1815
1805
fprintf(stderr, "Arc Distort, FX Equivelent:\n");
1816
1806
fprintf(stderr, "%s", image_gen);
1817
1807
fprintf(stderr, " -fx 'ii=i+page.x; jj=j+page.y;\n");
1830
1820
fprintf(stderr, "Polar Distort, Internal Coefficents\n");
1831
1821
for ( i=0; i<8; i++ )
1832
fprintf(stderr, " c%.20g = %+lf\n", (double) i, coeff[i]);
1822
fprintf(stderr, " c%ld = %+lf\n", i, coeff[i]);
1833
1823
fprintf(stderr, "Polar Distort, FX Equivelent:\n");
1834
1824
fprintf(stderr, "%s", image_gen);
1835
1825
fprintf(stderr, " -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
1849
1839
fprintf(stderr, "DePolar Distort, Internal Coefficents\n");
1850
1840
for ( i=0; i<8; i++ )
1851
fprintf(stderr, " c%.20g = %+lf\n", (double) i, coeff[i]);
1841
fprintf(stderr, " c%ld = %+lf\n", i, coeff[i]);
1852
1842
fprintf(stderr, "DePolar Distort, FX Equivelent:\n");
1853
1843
fprintf(stderr, "%s", image_gen);
1854
1844
fprintf(stderr, " -fx 'aa=(i+.5)*%lf %+lf;\n", coeff[6], -coeff[4] );
1861
1851
case BarrelDistortion:
1862
1852
case BarrelInverseDistortion:
1863
1853
{ double xc,yc;
1864
/* NOTE: This does the barrel roll in pixel coords not image coords
1865
** The internal distortion must do it in image coordinates,
1866
** so that is what the center coeff (8,9) is given in.
1868
1854
xc = ((double)image->columns-1.0)/2.0 + image->page.x;
1869
1855
yc = ((double)image->rows-1.0)/2.0 + image->page.y;
1870
1856
fprintf(stderr, "Barrel%s Distort, FX Equivelent:\n",
1871
1857
method == BarrelDistortion ? "" : "Inv");
1872
1858
fprintf(stderr, "%s", image_gen);
1873
if ( fabs(coeff[8]-xc-0.5) < 0.1 && fabs(coeff[9]-yc-0.5) < 0.1 )
1859
if ( fabs(coeff[8]-xc) < 0.1 && fabs(coeff[9]-yc) < 0.1 )
1874
1860
fprintf(stderr, " -fx 'xc=(w-1)/2; yc=(h-1)/2;\n");
1876
1862
fprintf(stderr, " -fx 'xc=%lf; yc=%lf;\n",
1877
coeff[8]-0.5, coeff[9]-0.5);
1863
coeff[8], coeff[9]);
1878
1864
fprintf(stderr,
1879
1865
" ii=i-xc; jj=j-yc; rr=hypot(ii,jj);\n");
1880
1866
fprintf(stderr, " ii=ii%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n",
1966
1948
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1967
1949
#pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1969
for (j=0; j < (ssize_t) distort_image->rows; j++)
1951
for (j=0; j < (long) distort_image->rows; j++)
1972
1954
validity; /* how mathematically valid is this the mapping */
2030
2012
if (distort_image->colorspace == CMYKColorspace)
2031
2013
ConvertRGBToCMYK(&invalid); /* what about other color spaces? */
2033
for (i=0; i < (ssize_t) distort_image->columns; i++)
2015
for (i=0; i < (long) distort_image->columns; i++)
2035
2017
/* map pixel coordinate to distortion space coordinate */
2036
2018
d.x = (double) (geometry.x+i+0.5)*output_scaling;
2134
2116
case PolynomialDistortion:
2136
2118
/* multi-ordered polynomial */
2140
nterms=(ssize_t)coeff[1];
2122
nterms=(long)coeff[1];
2143
2125
du,dv; /* the du,dv vectors from unit dx,dy -- derivatives */
2231
2213
fx = 1/fx; fy = 1/fy;
2232
2214
gx *= -fx*fx; gy *= -fy*fy;
2234
/* Set the source pixel to lookup and EWA derivative vectors */
2216
/* Set source pixel and EWA derivative vectors */
2235
2217
s.x = d.x*fx + coeff[8];
2236
2218
s.y = d.y*fy + coeff[9];
2237
2219
ScaleFilter( resample_filter[id],
2238
2220
gx*d.x*d.x + fx, gx*d.x*d.y,
2239
2221
gy*d.x*d.y, gy*d.y*d.y + fy );
2242
/* Special handling to avoid divide by zero when r==0
2244
** The source and destination pixels match in this case
2245
** which was set at the top of the loop using s = d;
2246
** otherwise... s.x=coeff[8]; s.y=coeff[9];
2223
else { /* Special handling to avoid divide by zero when r=0 */
2248
2225
if ( method == BarrelDistortion )
2249
2226
ScaleFilter( resample_filter[id],
2250
2227
coeff[3], 0, 0, coeff[7] );
2375
2352
% The format of the SparseColorImage() method is:
2377
2354
% Image *SparseColorImage(const Image *image,const ChannelType channel,
2378
% const SparseColorMethod method,const size_t number_arguments,
2355
% const SparseColorMethod method,const unsigned long number_arguments,
2379
2356
% const double *arguments,ExceptionInfo *exception)
2381
2358
% A description of each parameter follows:
2403
2380
MagickExport Image *SparseColorImage(const Image *image,
2404
2381
const ChannelType channel,const SparseColorMethod method,
2405
const size_t number_arguments,const double *arguments,
2382
const unsigned long number_arguments,const double *arguments,
2406
2383
ExceptionInfo *exception)
2408
2385
#define SparseColorTag "Distort/SparseColor"
2453
2430
switch (method) {
2454
2431
case BarycentricColorInterpolate:
2456
register ssize_t x=0;
2457
2434
fprintf(stderr, "Barycentric Sparse Color:\n");
2458
2435
if ( channel & RedChannel )
2459
2436
fprintf(stderr, " -channel R -fx '%+lf*i %+lf*j %+lf' \\\n",
2475
2452
case BilinearColorInterpolate:
2477
register ssize_t x=0;
2478
2455
fprintf(stderr, "Bilinear Sparse Color\n");
2479
2456
if ( channel & RedChannel )
2480
2457
fprintf(stderr, " -channel R -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
2540
2515
#if defined(MAGICKCORE_OPENMP_SUPPORT)
2541
2516
#pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2543
for (j=0; j < (ssize_t) sparse_image->rows; j++)
2518
for (j=0; j < (long) sparse_image->rows; j++)
2545
2520
MagickBooleanType
2567
2542
/* FUTURE: get pixel from source image - so channel can replace parts */
2568
2543
indexes=GetCacheViewAuthenticIndexQueue(sparse_view);
2570
for (i=0; i < (ssize_t) sparse_image->columns; i++)
2545
for (i=0; i < (long) sparse_image->columns; i++)
2572
2547
switch (method)
2574
2549
case BarycentricColorInterpolate:
2576
register ssize_t x=0;
2577
2552
if ( channel & RedChannel )
2578
2553
pixel.red = coeff[x]*i +coeff[x+1]*j
2579
2554
+coeff[x+2], x+=3;
2594
2569
case BilinearColorInterpolate:
2596
register ssize_t x=0;
2597
2572
if ( channel & RedChannel )
2598
2573
pixel.red = coeff[x]*i + coeff[x+1]*j +
2599
2574
coeff[x+2]*i*j + coeff[x+3], x+=4;
2626
2601
if ( channel & OpacityChannel ) pixel.opacity = 0.0;
2627
2602
denominator = 0.0;
2628
2603
for(k=0; k<number_arguments; k+=2+number_colors) {
2629
register ssize_t x=(ssize_t) k+2;
2604
register long x=(long) k+2;
2630
2605
double weight =
2631
2606
((double)i-arguments[ k ])*((double)i-arguments[ k ])
2632
2607
+ ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
2666
2641
((double)i-arguments[ k ])*((double)i-arguments[ k ])
2667
2642
+ ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
2668
2643
if ( distance < minimum ) {
2669
register ssize_t x=(ssize_t) k+2;
2644
register long x=(long) k+2;
2670
2645
if ( channel & RedChannel ) pixel.red = arguments[x++];
2671
2646
if ( channel & GreenChannel ) pixel.green = arguments[x++];
2672
2647
if ( channel & BlueChannel ) pixel.blue = arguments[x++];