| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 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 | |
|---|
| 68 | |
|---|
| 69 | static inline double MagickMin(const double x,const double y) |
|---|
| 70 | { |
|---|
| 71 | return( x < y ? x : y); |
|---|
| 72 | } |
|---|
| 73 | static inline double MagickMax(const double x,const double y) |
|---|
| 74 | { |
|---|
| 75 | return( x > y ? x : y); |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | static inline void AffineArgsToCoefficients(double *affine) |
|---|
| 79 | { |
|---|
| 80 | |
|---|
| 81 | double tmp[4]; |
|---|
| 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 | } |
|---|
| 85 | static inline void CoefficientsToAffineArgs(double *coeff) |
|---|
| 86 | { |
|---|
| 87 | |
|---|
| 88 | double tmp[4]; |
|---|
| 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 | } |
|---|
| 92 | static void InvertAffineCoefficients(const double *coeff,double *inverse) |
|---|
| 93 | { |
|---|
| 94 | |
|---|
| 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 | |
|---|
| 106 | static void InvertPerspectiveCoefficients(const double *coeff, |
|---|
| 107 | double *inverse) |
|---|
| 108 | { |
|---|
| 109 | |
|---|
| 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 | |
|---|
| 123 | static inline double MagickRound(double x) |
|---|
| 124 | { |
|---|
| 125 | |
|---|
| 126 | if (x >= 0.0) |
|---|
| 127 | return((double) ((long) (x+0.5))); |
|---|
| 128 | return((double) ((long) (x-0.5))); |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | static unsigned long poly_number_terms(double order) |
|---|
| 132 | { |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | |
|---|
| 138 | |
|---|
| 139 | |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | |
|---|
| 146 | if ( order < 1 || order > 5 || |
|---|
| 147 | ( order != floor(order) && (order-1.5) > MagickEpsilon) ) |
|---|
| 148 | return 0; |
|---|
| 149 | return ((unsigned long) floor((order+1)*(order+2)/2)); |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | static double poly_basis_fn(long n, double x, double y) |
|---|
| 153 | { |
|---|
| 154 | |
|---|
| 155 | switch(n) { |
|---|
| 156 | case 0: return( 1.0 ); |
|---|
| 157 | case 1: return( x ); |
|---|
| 158 | case 2: return( y ); |
|---|
| 159 | case 3: return( x*y ); |
|---|
| 160 | case 4: return( x*x ); |
|---|
| 161 | case 5: return( y*y ); |
|---|
| 162 | case 6: return( x*x*x ); |
|---|
| 163 | case 7: return( x*x*y ); |
|---|
| 164 | case 8: return( x*y*y ); |
|---|
| 165 | case 9: return( y*y*y ); |
|---|
| 166 | case 10: return( x*x*x*x ); |
|---|
| 167 | case 11: return( x*x*x*y ); |
|---|
| 168 | case 12: return( x*x*y*y ); |
|---|
| 169 | case 13: return( x*y*y*y ); |
|---|
| 170 | case 14: return( y*y*y*y ); |
|---|
| 171 | case 15: return( x*x*x*x*x ); |
|---|
| 172 | case 16: return( x*x*x*x*y ); |
|---|
| 173 | case 17: return( x*x*x*y*y ); |
|---|
| 174 | case 18: return( x*x*y*y*y ); |
|---|
| 175 | case 19: return( x*y*y*y*y ); |
|---|
| 176 | case 20: return( y*y*y*y*y ); |
|---|
| 177 | } |
|---|
| 178 | return( 0 ); |
|---|
| 179 | } |
|---|
| 180 | static const char *poly_basis_str(long n) |
|---|
| 181 | { |
|---|
| 182 | |
|---|
| 183 | switch(n) { |
|---|
| 184 | case 0: return(""); |
|---|
| 185 | case 1: return("*ii"); |
|---|
| 186 | case 2: return("*jj"); |
|---|
| 187 | case 3: return("*ii*jj"); |
|---|
| 188 | case 4: return("*ii*ii"); |
|---|
| 189 | case 5: return("*jj*jj"); |
|---|
| 190 | case 6: return("*ii*ii*ii"); |
|---|
| 191 | case 7: return("*ii*ii*jj"); |
|---|
| 192 | case 8: return("*ii*jj*jj"); |
|---|
| 193 | case 9: return("*jj*jj*jj"); |
|---|
| 194 | case 10: return("*ii*ii*ii*ii"); |
|---|
| 195 | case 11: return("*ii*ii*ii*jj"); |
|---|
| 196 | case 12: return("*ii*ii*jj*jj"); |
|---|
| 197 | case 13: return("*ii*jj*jj*jj"); |
|---|
| 198 | case 14: return("*jj*jj*jj*jj"); |
|---|
| 199 | case 15: return("*ii*ii*ii*ii*ii"); |
|---|
| 200 | case 16: return("*ii*ii*ii*ii*jj"); |
|---|
| 201 | case 17: return("*ii*ii*ii*jj*jj"); |
|---|
| 202 | case 18: return("*ii*ii*jj*jj*jj"); |
|---|
| 203 | case 19: return("*ii*jj*jj*jj*jj"); |
|---|
| 204 | case 20: return("*jj*jj*jj*jj*jj"); |
|---|
| 205 | } |
|---|
| 206 | return( "UNKNOWN" ); |
|---|
| 207 | } |
|---|
| 208 | static double poly_basis_dx(long n, double x, double y) |
|---|
| 209 | { |
|---|
| 210 | |
|---|
| 211 | switch(n) { |
|---|
| 212 | case 0: return( 0.0 ); |
|---|
| 213 | case 1: return( 1.0 ); |
|---|
| 214 | case 2: return( 0.0 ); |
|---|
| 215 | case 3: return( y ); |
|---|
| 216 | case 4: return( x ); |
|---|
| 217 | case 5: return( 0.0 ); |
|---|
| 218 | case 6: return( x*x ); |
|---|
| 219 | case 7: return( x*y ); |
|---|
| 220 | case 8: return( y*y ); |
|---|
| 221 | case 9: return( 0.0 ); |
|---|
| 222 | case 10: return( x*x*x ); |
|---|
| 223 | case 11: return( x*x*y ); |
|---|
| 224 | case 12: return( x*y*y ); |
|---|
| 225 | case 13: return( y*y*y ); |
|---|
| 226 | case 14: return( 0.0 ); |
|---|
| 227 | case 15: return( x*x*x*x ); |
|---|
| 228 | case 16: return( x*x*x*y ); |
|---|
| 229 | case 17: return( x*x*y*y ); |
|---|
| 230 | case 18: return( x*y*y*y ); |
|---|
| 231 | case 19: return( y*y*y*y ); |
|---|
| 232 | case 20: return( 0.0 ); |
|---|
| 233 | } |
|---|
| 234 | return( 0.0 ); |
|---|
| 235 | } |
|---|
| 236 | static double poly_basis_dy(long n, double x, double y) |
|---|
| 237 | { |
|---|
| 238 | |
|---|
| 239 | switch(n) { |
|---|
| 240 | case 0: return( 0.0 ); |
|---|
| 241 | case 1: return( 0.0 ); |
|---|
| 242 | case 2: return( 1.0 ); |
|---|
| 243 | case 3: return( x ); |
|---|
| 244 | case 4: return( 0.0 ); |
|---|
| 245 | case 5: return( y ); |
|---|
| 246 | default: return( poly_basis_dx(n-1,x,y) ); |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | |
|---|
| 250 | |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | |
|---|
| 254 | |
|---|
| 255 | |
|---|
| 256 | |
|---|
| 257 | |
|---|
| 258 | |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | |
|---|
| 262 | |
|---|
| 263 | |
|---|
| 264 | |
|---|
| 265 | |
|---|
| 266 | |
|---|
| 267 | |
|---|
| 268 | |
|---|
| 269 | |
|---|
| 270 | |
|---|
| 271 | |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | |
|---|
| 275 | |
|---|
| 276 | |
|---|
| 277 | |
|---|
| 278 | |
|---|
| 279 | |
|---|
| 280 | |
|---|
| 281 | |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | |
|---|
| 285 | |
|---|
| 286 | |
|---|
| 287 | |
|---|
| 288 | |
|---|
| 289 | |
|---|
| 290 | |
|---|
| 291 | |
|---|
| 292 | |
|---|
| 293 | |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | |
|---|
| 297 | |
|---|
| 298 | |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | |
|---|
| 302 | |
|---|
| 303 | static 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, |
|---|
| 315 | cp_size, |
|---|
| 316 | cp_x,cp_y, |
|---|
| 317 | cp_values; |
|---|
| 318 | |
|---|
| 319 | |
|---|
| 320 | if ( number_values == 0 ) { |
|---|
| 321 | |
|---|
| 322 | |
|---|
| 323 | |
|---|
| 324 | number_values = 2; |
|---|
| 325 | cp_values = 0; |
|---|
| 326 | cp_x = 2; |
|---|
| 327 | cp_y = 3; |
|---|
| 328 | |
|---|
| 329 | } |
|---|
| 330 | else { |
|---|
| 331 | cp_x = 0; |
|---|
| 332 | cp_y = 1; |
|---|
| 333 | cp_values = 2; |
|---|
| 334 | |
|---|
| 335 | } |
|---|
| 336 | cp_size = number_values+2; |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | |
|---|
| 340 | |
|---|
| 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 | |
|---|
| 351 | number_coeff=3*number_values; |
|---|
| 352 | break; |
|---|
| 353 | case BilinearDistortion: |
|---|
| 354 | number_coeff=4*number_values; |
|---|
| 355 | break; |
|---|
| 356 | case PolynomialDistortion: |
|---|
| 357 | |
|---|
| 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 | |
|---|
| 381 | case ShepardsDistortion: |
|---|
| 382 | case VoronoiColorInterpolate: |
|---|
| 383 | number_coeff=1; |
|---|
| 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"); |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | |
|---|
| 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 | |
|---|
| 420 | for (i=0; i < number_coeff; i++) |
|---|
| 421 | coeff[i] = 0.0; |
|---|
| 422 | |
|---|
| 423 | switch (*method) |
|---|
| 424 | { |
|---|
| 425 | case AffineDistortion: |
|---|
| 426 | { |
|---|
| 427 | |
|---|
| 428 | |
|---|
| 429 | |
|---|
| 430 | |
|---|
| 431 | |
|---|
| 432 | |
|---|
| 433 | |
|---|
| 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 | |
|---|
| 444 | if ( number_arguments == cp_size ) { |
|---|
| 445 | |
|---|
| 446 | if ( cp_values == 0 ) { |
|---|
| 447 | |
|---|
| 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 | |
|---|
| 455 | for (i=0; i<number_values; i++) |
|---|
| 456 | coeff[i*3+2] = arguments[cp_values+i]; |
|---|
| 457 | } |
|---|
| 458 | } |
|---|
| 459 | else { |
|---|
| 460 | |
|---|
| 461 | |
|---|
| 462 | |
|---|
| 463 | double |
|---|
| 464 | **matrix, |
|---|
| 465 | **vectors, |
|---|
| 466 | terms[3]; |
|---|
| 467 | |
|---|
| 468 | MagickBooleanType |
|---|
| 469 | status; |
|---|
| 470 | |
|---|
| 471 | |
|---|
| 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 | |
|---|
| 485 | for (i=0; i < number_values; i++) |
|---|
| 486 | vectors[i] = &(coeff[i*3]); |
|---|
| 487 | |
|---|
| 488 | for (i=0; i < number_arguments; i+=cp_size) { |
|---|
| 489 | terms[0] = arguments[i+cp_x]; |
|---|
| 490 | terms[1] = arguments[i+cp_y]; |
|---|
| 491 | terms[2] = 1; |
|---|
| 492 | LeastSquaresAddTerms(matrix,vectors,terms, |
|---|
| 493 | &(arguments[i+cp_values]),3UL,number_values); |
|---|
| 494 | } |
|---|
| 495 | if ( number_arguments == 2*cp_size ) { |
|---|
| 496 | |
|---|
| 497 | |
|---|
| 498 | |
|---|
| 499 | |
|---|
| 500 | terms[0] = arguments[cp_x] |
|---|
| 501 | - ( arguments[cp_size+cp_y] - arguments[cp_y] ); |
|---|
| 502 | terms[1] = arguments[cp_y] + |
|---|
| 503 | + ( arguments[cp_size+cp_x] - arguments[cp_x] ); |
|---|
| 504 | terms[2] = 1; |
|---|
| 505 | if ( cp_values == 0 ) { |
|---|
| 506 | |
|---|
| 507 | double |
|---|
| 508 | uv2[2]; |
|---|
| 509 | uv2[0] = arguments[0] - arguments[5] + arguments[1]; |
|---|
| 510 | uv2[1] = arguments[1] + arguments[4] - arguments[0]; |
|---|
| 511 | LeastSquaresAddTerms(matrix,vectors,terms,uv2,3UL,2UL); |
|---|
| 512 | } |
|---|
| 513 | else { |
|---|
| 514 | |
|---|
| 515 | LeastSquaresAddTerms(matrix,vectors,terms, |
|---|
| 516 | &(arguments[cp_values]),3UL,number_values); |
|---|
| 517 | } |
|---|
| 518 | } |
|---|
| 519 | |
|---|
| 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 | |
|---|
| 537 | |
|---|
| 538 | |
|---|
| 539 | |
|---|
| 540 | |
|---|
| 541 | |
|---|
| 542 | |
|---|
| 543 | |
|---|
| 544 | |
|---|
| 545 | |
|---|
| 546 | |
|---|
| 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 | |
|---|
| 557 | for(i=0; i<6UL; i++ ) |
|---|
| 558 | inverse[i] = arguments[i]; |
|---|
| 559 | AffineArgsToCoefficients(inverse); |
|---|
| 560 | InvertAffineCoefficients(inverse, coeff); |
|---|
| 561 | *method = AffineDistortion; |
|---|
| 562 | |
|---|
| 563 | return(coeff); |
|---|
| 564 | } |
|---|
| 565 | case ScaleRotateTranslateDistortion: |
|---|
| 566 | { |
|---|
| 567 | |
|---|
| 568 | |
|---|
| 569 | |
|---|
| 570 | |
|---|
| 571 | |
|---|
| 572 | |
|---|
| 573 | |
|---|
| 574 | |
|---|
| 575 | |
|---|
| 576 | |
|---|
| 577 | |
|---|
| 578 | |
|---|
| 579 | |
|---|
| 580 | |
|---|
| 581 | |
|---|
| 582 | |
|---|
| 583 | |
|---|
| 584 | |
|---|
| 585 | |
|---|
| 586 | |
|---|
| 587 | |
|---|
| 588 | |
|---|
| 589 | double |
|---|
| 590 | cosine, sine, |
|---|
| 591 | x,y,sx,sy,a,nx,ny; |
|---|
| 592 | |
|---|
| 593 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 672 | |
|---|
| 673 | |
|---|
| 674 | |
|---|
| 675 | |
|---|
| 676 | |
|---|
| 677 | |
|---|
| 678 | |
|---|
| 679 | |
|---|
| 680 | |
|---|
| 681 | |
|---|
| 682 | |
|---|
| 683 | |
|---|
| 684 | |
|---|
| 685 | |
|---|
| 686 | |
|---|
| 687 | |
|---|
| 688 | |
|---|
| 689 | |
|---|
| 690 | |
|---|
| 691 | |
|---|
| 692 | |
|---|
| 693 | |
|---|
| 694 | |
|---|
| 695 | |
|---|
| 696 | |
|---|
| 697 | |
|---|
| 698 | |
|---|
| 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 | |
|---|
| 713 | vectors[0] = &(coeff[0]); |
|---|
| 714 | |
|---|
| 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 | |
|---|
| 723 | for (i=0; i < number_arguments; i+=4) { |
|---|
| 724 | terms[0]=arguments[i+cp_x]; |
|---|
| 725 | terms[1]=arguments[i+cp_y]; |
|---|
| 726 | terms[2]=1.0; |
|---|
| 727 | terms[3]=0.0; |
|---|
| 728 | terms[4]=0.0; |
|---|
| 729 | terms[5]=0.0; |
|---|
| 730 | terms[6]=-terms[0]*arguments[i+cp_u]; |
|---|
| 731 | terms[7]=-terms[1]*arguments[i+cp_u]; |
|---|
| 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]; |
|---|
| 739 | terms[4]=arguments[i+cp_y]; |
|---|
| 740 | terms[5]=1.0; |
|---|
| 741 | terms[6]=-terms[3]*arguments[i+cp_v]; |
|---|
| 742 | terms[7]=-terms[4]*arguments[i+cp_v]; |
|---|
| 743 | LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_v]), |
|---|
| 744 | 8UL,1UL); |
|---|
| 745 | } |
|---|
| 746 | |
|---|
| 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 | |
|---|
| 758 | |
|---|
| 759 | |
|---|
| 760 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 780 | InvertPerspectiveCoefficients(arguments, coeff); |
|---|
| 781 | |
|---|
| 782 | |
|---|
| 783 | |
|---|
| 784 | |
|---|
| 785 | |
|---|
| 786 | |
|---|
| 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 | |
|---|
| 798 | |
|---|
| 799 | |
|---|
| 800 | |
|---|
| 801 | |
|---|
| 802 | |
|---|
| 803 | |
|---|
| 804 | |
|---|
| 805 | |
|---|
| 806 | |
|---|
| 807 | |
|---|
| 808 | |
|---|
| 809 | |
|---|
| 810 | double |
|---|
| 811 | **matrix, |
|---|
| 812 | **vectors, |
|---|
| 813 | terms[4]; |
|---|
| 814 | |
|---|
| 815 | MagickBooleanType |
|---|
| 816 | status; |
|---|
| 817 | |
|---|
| 818 | |
|---|
| 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 | |
|---|
| 832 | for (i=0; i < number_values; i++) |
|---|
| 833 | vectors[i] = &(coeff[i*4]); |
|---|
| 834 | |
|---|
| 835 | for (i=0; i < number_arguments; i+=cp_size) { |
|---|
| 836 | terms[0] = arguments[i+cp_x]; |
|---|
| 837 | terms[1] = arguments[i+cp_y]; |
|---|
| 838 | terms[2] = terms[0]*terms[1]; |
|---|
| 839 | terms[3] = 1; |
|---|