Changeset 1407 for trunk/psLib/src/image/psImageManip.c
- Timestamp:
- Aug 6, 2004, 2:06:06 PM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/image/psImageManip.c (modified) (34 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/image/psImageManip.c
r1406 r1407 1 1 2 /** @file psImageManip.c 2 3 * … … 10 11 * @author Ross Harman, MHPCC 11 12 * 12 * @version $Revision: 1.1 0$ $Name: not supported by cvs2svn $13 * @date $Date: 2004-08-0 6 22:34:05$13 * @version $Revision: 1.11 $ $Name: not supported by cvs2svn $ 14 * @date $Date: 2004-08-07 00:06:06 $ 14 15 * 15 16 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii 16 17 */ 17 #include <math.h> // for isfinite(), etc. 18 #include <math.h> // for 19 // isfinite(), 20 // etc. 18 21 #include <stdlib.h> 19 22 #include <stdbool.h> 20 #include <string.h> // for memcpy, etc. 23 #include <string.h> // for 24 // memcpy, 25 // etc. 21 26 22 27 #include "psError.h" … … 26 31 #include "psImageExtraction.h" 27 32 28 int psImageClip(psImage * input, psF64 min, psF64 vmin, psF64 max, psF64 vmax)33 int psImageClip(psImage * input, psF64 min, psF64 vmin, psF64 max, psF64 vmax) 29 34 { 30 35 int numClipped = 0; … … 37 42 38 43 if (max < min) { 39 psError(__func__, "psImageClip can not be invoked with max < min.");44 psError(__func__, "psImageClip can not be invoked with max < min."); 40 45 return 0; 41 46 } … … 100 105 break; 101 106 102 psImageClipCase(S8, "psS8")103 psImageClipCase(S16, "psS16")104 psImageClipCase(S32, "psS32")105 psImageClipCase(S64, "psS64")106 psImageClipCase(U8, "psU8")107 psImageClipCase(U16, "psU16")108 psImageClipCase(U32, "psU32")109 psImageClipCase(U64, "psU64")110 psImageClipCase(F32, "psF32")111 psImageClipCase(F64, "psF64")112 psImageClipCaseComplex(C32, "psC32",cabsf)113 psImageClipCaseComplex(C64, "psC64",cabs)107 psImageClipCase(S8, "psS8") 108 psImageClipCase(S16, "psS16") 109 psImageClipCase(S32, "psS32") 110 psImageClipCase(S64, "psS64") 111 psImageClipCase(U8, "psU8") 112 psImageClipCase(U16, "psU16") 113 psImageClipCase(U32, "psU32") 114 psImageClipCase(U64, "psU64") 115 psImageClipCase(F32, "psF32") 116 psImageClipCase(F64, "psF64") 117 psImageClipCaseComplex(C32, "psC32", cabsf) 118 psImageClipCaseComplex(C64, "psC64", cabs) 114 119 115 120 default: 116 psError(__func__,"psImageClip does not support the given datatype (%d)", 117 input->type.type); 121 psError(__func__, "psImageClip does not support the given datatype (%d)", input->type.type); 118 122 } 119 123 … … 121 125 } 122 126 123 int psImageClipNaN(psImage * input,psF64 value)127 int psImageClipNaN(psImage * input, psF64 value) 124 128 { 125 129 int numClipped = 0; … … 154 158 155 159 default: 156 psError(__func__,"psImageClip does not support the given datatype (%d)", 157 input->type.type); 160 psError(__func__, "psImageClip does not support the given datatype (%d)", input->type.type); 158 161 } 159 162 … … 161 164 } 162 165 163 int psImageOverlaySection(psImage* image, const psImage* overlay, int col0, 164 int row0, const char* op) 166 int psImageOverlaySection(psImage * image, const psImage * overlay, int col0, int row0, const char *op) 165 167 { 166 168 unsigned int imageNumRows; … … 170 172 unsigned int imageRowLimit; 171 173 unsigned int imageColLimit; 172 psElemType type;174 psElemType type; 173 175 174 176 if (image == NULL || overlay == NULL) { 175 psError(__func__, "one of the input images was NULL.");177 psError(__func__, "one of the input images was NULL."); 176 178 return 1; 177 179 } 178 180 179 181 if (op == NULL) { 180 psError(__func__, "Operation can not be NULL.");182 psError(__func__, "Operation can not be NULL."); 181 183 return 1; 182 184 } … … 185 187 186 188 if (type != overlay->type.type) { 187 psError(__func__,"Image and overlay datatypes must match. (%d vs %d)", 188 type,overlay->type.type); 189 psError(__func__, "Image and overlay datatypes must match. (%d vs %d)", type, overlay->type.type); 189 190 return 2; 190 191 } … … 197 198 /* check row0/col0 to see if it is within the image size */ 198 199 if (row0 < 0 || col0 < 0 || row0 >= imageNumRows || col0 >= imageNumCols) { 199 psError(__func__, "Overlay origin of (%d,%d) is outside of the image dimensions (%d x %d).", 200 psError(__func__, 201 "Overlay origin of (%d,%d) is outside of the image dimensions (%d x %d).", 200 202 col0, row0, imageNumCols, imageNumRows); 201 203 return 3; … … 203 205 204 206 /* check if overlay is totally withing input image */ 205 imageRowLimit = row0 +overlayNumRows;206 imageColLimit = col0 +overlayNumCols;207 imageRowLimit = row0 + overlayNumRows; 208 imageColLimit = col0 + overlayNumCols; 207 209 if (imageRowLimit > imageNumRows || imageColLimit > imageNumCols) { 208 psError(__func__, "Overlay image (%d,%d -> %d,%d) is partially outside" 210 psError(__func__, 211 "Overlay image (%d,%d -> %d,%d) is partially outside" 209 212 " of the input image (%d x %d).", 210 col0, row0, col0+overlayNumCols-1, row0+overlayNumRows-1, 211 imageNumCols,imageNumRows); 213 col0, row0, col0 + overlayNumCols - 1, row0 + overlayNumRows - 1, imageNumCols, imageNumRows); 212 214 return 4; 213 215 } … … 259 261 260 262 default: 261 psError(__func__, "Can not operate on type %d.",type);263 psError(__func__, "Can not operate on type %d.", type); 262 264 } 263 265 … … 265 267 } 266 268 267 int psImageClipComplexRegion(psImage * input, psC64 min, psC64 vmin, psC64 max, psC64 vmax)269 int psImageClipComplexRegion(psImage * input, psC64 min, psC64 vmin, psC64 max, psC64 vmax) 268 270 { 269 271 int numClipped = 0; … … 276 278 277 279 if (input == NULL) { 278 psError(__func__, "Can not perform clip on NULL image");280 psError(__func__, "Can not perform clip on NULL image"); 279 281 return 0; 280 282 } 281 283 282 if ( realMax < realMin) {283 psError(__func__, "psImageClipComplexRegion can not be invoked with "284 " max < min in the real image space.");284 if (realMax < realMin) { 285 psError(__func__, 286 "psImageClipComplexRegion can not be invoked with " "max < min in the real image space."); 285 287 return 0; 286 288 } 287 if ( imagMax < imagMin ) { 288 psError(__func__,"psImageClipComplexRegion can not be invoked with " 289 if (imagMax < imagMin) { 290 psError(__func__, 291 "psImageClipComplexRegion can not be invoked with " 289 292 "max < min in the imaginary image space."); 290 293 return 0; … … 294 297 numCols = input->numCols; 295 298 299 #define psImageClipComplexRegionCase(type,typename,realfcn,imagfcn) \ 300 case PS_TYPE_##type: { \ 301 if (realfcn(vmin) < PS_MIN_##type || imagfcn(vmin) < PS_MIN_##type || \ 302 realfcn(vmin) > PS_MAX_##type || imagfcn(vmin) > PS_MAX_##type ) { \ 303 psError(__func__, "Specified vmin (%g%+gi) is outside of image's " \ 304 typename " pixel range", \ 305 creal(vmin),cimag(vmin)); \ 306 break; \ 307 } \ 308 if (realfcn(vmax) > PS_MAX_##type || imagfcn(vmax) > PS_MAX_##type || \ 309 realfcn(vmax) < PS_MIN_##type || imagfcn(vmax) < PS_MIN_##type ) { \ 310 psError(__func__, "Specified vmax (%g%+gi) is outside of image's " \ 311 typename " pixel range", \ 312 creal(vmax),cimag(vmax)); \ 313 break; \ 314 } \ 315 for (unsigned int row = 0;row<numRows;row++) { \ 316 ps##type* inputRow = input->data.type[row]; \ 317 for (unsigned int col = 0; col < numCols; col++) { \ 318 if ( (realfcn(inputRow[col]) > realMax) || (imagfcn(inputRow[col]) > imagMax) ) { \ 319 inputRow[col] = (ps##type)vmax; \ 320 numClipped++; \ 321 } else if ( (realfcn(inputRow[col]) < realMin) || (imagfcn(inputRow[col]) < imagMin) ){ \ 322 inputRow[col] = (ps##type)vmin; \ 323 numClipped++; \ 324 } \ 325 } \ 326 } \ 327 } \ 328 break; 329 296 330 switch (input->type.type) { 297 331 298 #define psImageClipComplexRegionCase(type,typename,realfcn,imagfcn) \ 299 case PS_TYPE_##type: { \ 300 if (realfcn(vmin) < PS_MIN_##type || imagfcn(vmin) < PS_MIN_##type || \ 301 realfcn(vmin) > PS_MAX_##type || imagfcn(vmin) > PS_MAX_##type ) { \ 302 psError(__func__, "Specified vmin (%g%+gi) is outside of image's " \ 303 typename " pixel range", \ 304 creal(vmin),cimag(vmin)); \ 305 break; \ 306 } \ 307 if (realfcn(vmax) > PS_MAX_##type || imagfcn(vmax) > PS_MAX_##type || \ 308 realfcn(vmax) < PS_MIN_##type || imagfcn(vmax) < PS_MIN_##type ) { \ 309 psError(__func__, "Specified vmax (%g%+gi) is outside of image's " \ 310 typename " pixel range", \ 311 creal(vmax),cimag(vmax)); \ 312 break; \ 313 } \ 314 for (unsigned int row = 0;row<numRows;row++) { \ 315 ps##type* inputRow = input->data.type[row]; \ 316 for (unsigned int col = 0; col < numCols; col++) { \ 317 if ( (realfcn(inputRow[col]) > realMax) || (imagfcn(inputRow[col]) > imagMax) ) { \ 318 inputRow[col] = (ps##type)vmax; \ 319 numClipped++; \ 320 } else if ( (realfcn(inputRow[col]) < realMin) || (imagfcn(inputRow[col]) < imagMin) ){ \ 321 inputRow[col] = (ps##type)vmin; \ 322 numClipped++; \ 323 } \ 324 } \ 325 } \ 326 } \ 327 break; 328 329 psImageClipComplexRegionCase(C32,"psC32",crealf,cimagf) 330 psImageClipComplexRegionCase(C64,"psC64",creal,cimag) 332 psImageClipComplexRegionCase(C32, "psC32", crealf, cimagf) 333 psImageClipComplexRegionCase(C64, "psC64", creal, cimag) 331 334 332 335 default: 333 psError(__func__,"psImageClip does not support the given datatype (%d)", 334 input->type.type); 336 psError(__func__, "psImageClip does not support the given datatype (%d)", input->type.type); 335 337 } 336 338 … … 338 340 } 339 341 340 341 psImage* psImageRebin(psImage* out,const psImage* in,unsigned int scale,const psStats* stats) 342 psImage *psImageRebin(psImage * out, const psImage * in, unsigned int scale, const psStats * stats) 342 343 { 343 344 int inRows; … … 345 346 int outRows; 346 347 int outCols; 347 psVector* vec; // vector to hold the values of a single bin. 348 psStats* myStats; 348 psVector *vec; // vector to hold 349 350 // the values of 351 // a single bin. 352 psStats *myStats; 349 353 double statVal; 350 354 351 355 if (in == NULL) { 352 psError(__func__, "Input image is NULL.");356 psError(__func__, "Input image is NULL."); 353 357 psFree(out); 354 358 return NULL; … … 356 360 357 361 if (scale < 1) { 358 psError(__func__, "The scale must be positive.");362 psError(__func__, "The scale must be positive."); 359 363 psFree(out); 360 364 return NULL; … … 362 366 363 367 if (stats == NULL) { 364 psError(__func__, "The stats input can not be NULL.");368 psError(__func__, "The stats input can not be NULL."); 365 369 psFree(out); 366 370 return NULL; 367 371 } 368 372 369 if (p_psGetStatValue(stats, &statVal) == false) {370 psError(__func__, "The stat options didn't specify a single supported statistic type.");373 if (p_psGetStatValue(stats, &statVal) == false) { 374 psError(__func__, "The stat options didn't specify a single supported statistic type."); 371 375 psFree(out); 372 376 return NULL; … … 376 380 *myStats = *stats; 377 381 378 vec = psVectorAlloc(scale *scale,in->type.type);382 vec = psVectorAlloc(scale * scale, in->type.type); 379 383 380 384 // create output image. 381 385 inRows = in->numRows; 382 386 inCols = in->numCols; 383 outRows = (inRows+scale-1) / scale; // round-up for remainders 384 outCols = (inCols+scale-1) / scale; // round-up for remainders 385 out = psImageRecycle(out,outCols,outRows,in->type.type); 387 outRows = (inRows + scale - 1) / scale; // round-up 388 // for 389 // remainders 390 outCols = (inCols + scale - 1) / scale; // round-up 391 // for 392 // remainders 393 out = psImageRecycle(out, outCols, outRows, in->type.type); 386 394 387 395 #define PS_IMAGE_REBIN_CASE(type) \ … … 425 433 PS_IMAGE_REBIN_CASE(C64); 426 434 default: 427 psError(__func__, "Input image type not supported.");435 psError(__func__, "Input image type not supported."); 428 436 psFree(out); 429 437 out = NULL; … … 435 443 return out; 436 444 } 437 psImage* psImageResample(psImage* out, const psImage* in, int scale, psImageInterpolateMode mode) 445 446 psImage *psImageResample(psImage * out, const psImage * in, int scale, psImageInterpolateMode mode) 438 447 { 439 448 int outRows; … … 442 451 443 452 if (in == NULL) { 444 psError(__func__, "Input image can not be NULL.");453 psError(__func__, "Input image can not be NULL."); 445 454 psFree(out); 446 455 return NULL; 447 456 } 448 449 // create an output image of the same sizeand type450 outRows = in->numRows *scale;451 outCols = in->numCols *scale;457 // create an output image of the same size 458 // and type 459 outRows = in->numRows * scale; 460 outCols = in->numCols * scale; 452 461 invScale = 1.0f / (float)scale; 453 454 462 455 463 #define PSIMAGE_RESAMPLE_CASE(TYPE) \ … … 466 474 } 467 475 468 switch (in->type.type) {476 switch (in->type.type) { 469 477 PSIMAGE_RESAMPLE_CASE(U8) 470 478 PSIMAGE_RESAMPLE_CASE(U16) … … 480 488 PSIMAGE_RESAMPLE_CASE(C64) 481 489 default: 482 psError(__func__, "Unsupported type (%d)",in->type.type);490 psError(__func__, "Unsupported type (%d)", in->type.type); 483 491 psFree(out); 484 492 return NULL; … … 488 496 } 489 497 490 psImage * psImageRoll(psImage* out, const psImage* in, int dx, int dy)498 psImage *psImageRoll(psImage * out, const psImage * in, int dx, int dy) 491 499 { 492 500 int outRows; … … 495 503 496 504 if (in == NULL) { 497 psError(__func__, "Input image can not be NULL.");505 psError(__func__, "Input image can not be NULL."); 498 506 psFree(out); 499 507 return NULL; 500 508 } 501 502 // create an output image of the same sizeand type509 // create an output image of the same size 510 // and type 503 511 outRows = in->numRows; 504 512 outCols = in->numCols; 505 513 elementSize = PSELEMTYPE_SIZEOF(in->type.type); 506 out = psImageRecycle(out,outCols, outRows, in->type.type); 507 508 // make dx and dy between 0 and outCols or outRows, respectively 514 out = psImageRecycle(out, outCols, outRows, in->type.type); 515 516 // make dx and dy between 0 and outCols or 517 // outRows, respectively 509 518 dx = dx % outCols; 510 519 dy = dy % outRows; … … 516 525 } 517 526 518 int segment1Size = elementSize*(outCols-dx); 519 int segment2Size = elementSize*dx; 520 521 for (int row=0;row<outRows;row++) { 522 int inRowNumber = row+dy; 527 int segment1Size = elementSize * (outCols - dx); 528 int segment2Size = elementSize * dx; 529 530 for (int row = 0; row < outRows; row++) { 531 int inRowNumber = row + dy; 532 523 533 if (inRowNumber >= outRows) { 524 534 inRowNumber -= outRows; 525 535 } 526 psU8* inRow = in->data.U8[inRowNumber]; // to allow byte arithmetic, but for all types 527 psU8* outRow = out->data.U8[row]; 528 memcpy(outRow,inRow+segment2Size,segment1Size); 529 memcpy(outRow+segment1Size,inRow,segment2Size); 536 psU8 *inRow = in->data.U8[inRowNumber]; // to 537 538 // allow 539 540 // byte 541 // arithmetic, 542 543 // but for all types 544 psU8 *outRow = out->data.U8[row]; 545 546 memcpy(outRow, inRow + segment2Size, segment1Size); 547 memcpy(outRow + segment1Size, inRow, segment2Size); 530 548 } 531 549 … … 533 551 } 534 552 535 psImage* psImageRotate(psImage* out, const psImage* in, float angle, float unexposedValue, psImageInterpolateMode mode) 553 psImage *psImageRotate(psImage * out, 554 const psImage * in, float angle, float unexposedValue, psImageInterpolateMode mode) 536 555 { 537 556 if (in == NULL) { 538 psError(__func__, "The input image was NULL.");557 psError(__func__, "The input image was NULL."); 539 558 psFree(out); 540 559 return NULL; 541 560 } 542 543 561 // put the angle in the range of 0...360. 544 angle = angle - 360.0f *floor(angle/360.0f);545 546 if (fabsf(angle -90.0f) < FLT_EPSILON) {562 angle = angle - 360.0f * floor(angle / 360.0f); 563 564 if (fabsf(angle - 90.0f) < FLT_EPSILON) { 547 565 // perform 1/4 rotate counter-clockwise 548 566 int numRows = in->numCols; … … 550 568 int lastCol = numCols - 1; 551 569 psElemType type = in->type.type; 552 out = psImageRecycle(out,numCols,numRows,type); 570 571 out = psImageRecycle(out, numCols, numRows, type); 553 572 554 573 #define PSIMAGE_ROTATE_LEFT_90(TYPE) \ … … 578 597 PSIMAGE_ROTATE_LEFT_90(C64); 579 598 default: 580 psError(__func__, "Unsupported type (%d)",type);599 psError(__func__, "Unsupported type (%d)", type); 581 600 psFree(out); 582 601 return NULL; 583 602 } 584 } else 585 if (fabsf(angle-180.0f) < FLT_EPSILON) { 586 // perform 1/2 rotate 587 int numRows = in->numRows; 588 int lastRow = numRows - 1; 589 int numCols = in->numCols; 590 int lastCol = numCols - 1; 591 psElemType type = in->type.type; 592 out = psImageRecycle(out,numCols,numRows,type); 593 594 #define PSIMAGE_ROTATE_180_CASE(TYPE) \ 595 case PS_TYPE_##TYPE: { \ 596 for (int row=0;row<numRows;row++) { \ 597 ps##TYPE* outRow = out->data.TYPE[row]; \ 598 ps##TYPE* inRow = in->data.TYPE[lastRow-row]; \ 599 for (int col=0;col<numCols;col++) { \ 600 outRow[col] = inRow[lastCol - col]; \ 601 } \ 602 } \ 603 } \ 604 break; 605 606 switch (type) { 607 PSIMAGE_ROTATE_180_CASE(U8); 608 PSIMAGE_ROTATE_180_CASE(U16); 609 PSIMAGE_ROTATE_180_CASE(U32); 610 PSIMAGE_ROTATE_180_CASE(U64); 611 PSIMAGE_ROTATE_180_CASE(S8); 612 PSIMAGE_ROTATE_180_CASE(S16); 613 PSIMAGE_ROTATE_180_CASE(S32); 614 PSIMAGE_ROTATE_180_CASE(S64); 615 PSIMAGE_ROTATE_180_CASE(F32); 616 PSIMAGE_ROTATE_180_CASE(F64); 617 PSIMAGE_ROTATE_180_CASE(C32); 618 PSIMAGE_ROTATE_180_CASE(C64); 619 default: 620 psError(__func__,"Unsupported type (%d)",type); 621 psFree(out); 622 return NULL; 623 } 624 } else 625 if (fabsf(angle-270.0f) < FLT_EPSILON) { 626 // perform 1/4 rotate clockwise 627 int numRows = in->numCols; 628 int lastRow = numRows - 1; 629 int numCols = in->numRows; 630 psElemType type = in->type.type; 631 out = psImageRecycle(out,numCols,numRows,type); 632 633 #define PSIMAGE_ROTATE_RIGHT_90(TYPE) \ 634 case PS_TYPE_##TYPE: { \ 635 ps##TYPE** inData = in->data.TYPE; \ 636 for (int row=0;row<numRows;row++) { \ 637 ps##TYPE* outRow = out->data.TYPE[row]; \ 638 for (int col=0;col<numCols;col++) { \ 639 outRow[col] = inData[col][lastRow-row]; \ 640 } \ 641 } \ 642 } \ 643 break; 644 645 switch (type) { 646 PSIMAGE_ROTATE_RIGHT_90(U8); 647 PSIMAGE_ROTATE_RIGHT_90(U16); 648 PSIMAGE_ROTATE_RIGHT_90(U32); 649 PSIMAGE_ROTATE_RIGHT_90(U64); 650 PSIMAGE_ROTATE_RIGHT_90(S8); 651 PSIMAGE_ROTATE_RIGHT_90(S16); 652 PSIMAGE_ROTATE_RIGHT_90(S32); 653 PSIMAGE_ROTATE_RIGHT_90(S64); 654 PSIMAGE_ROTATE_RIGHT_90(F32); 655 PSIMAGE_ROTATE_RIGHT_90(F64); 656 PSIMAGE_ROTATE_RIGHT_90(C32); 657 PSIMAGE_ROTATE_RIGHT_90(C64); 658 default: 659 psError(__func__,"Unsupported type (%d)",type); 660 psFree(out); 661 return NULL; 662 } 663 } else 664 if (fabsf(angle) < FLT_EPSILON) { 665 out = psImageCopy(out,in,in->type.type); 666 } else { 667 psElemType type = in->type.type; 668 int numRows = in->numRows; 669 int numCols = in->numCols; 670 double centerX = (float)(numCols) / 2.0f; 671 float centerY = (float)(numRows) / 2.0f; 672 float t = angle*(3.14159265358f/180.0f); 673 float cosT = cosf(t); 674 float sinT = sinf(t); 675 676 // calculate the corners of the rotated image so we know the proper output image size. 677 // x' = x cos(t) + y sin(t); i.e, x' = (x-centerX)*cosT + (y-centerY)*sinT; 678 // y' = y cos(t) - x sin(t); i.e. y' = (y-centerY)*cosT - (x-centerX)*sinT; 679 680 681 int outCols = ceil(abs(numCols*cosT)+abs(numRows*sinT))+1; 682 int outRows = ceil(abs(numCols*sinT)+abs(numRows*cosT))+1; 683 float minX = (float)outCols/-2.0f; 684 int intMinY = outRows/-2; 685 686 out = psImageRecycle(out,outCols,outRows,type); 687 688 /* optimized public domain rotation routine by Karl Lager 689 float cosT,sinT; 690 cosT = cos(t); 691 sinT = sin(t); 692 for (y = min_y; y <= max_y; y++) 693 { x' = min_x * cosT + y * sinT + x1'; 694 y' = y * cosT - min_x * sinT + y1'; 695 for (x = min_x; x <= max_x; x++) 696 { if (x', y') is in the bounds of the bitmap, 697 get pixel(x', y') and plot the pixel to 698 (x, y) on screen. 699 x' += cosT; 700 y' -= sinT; 701 } 702 } 703 */ 704 705 // precalculate some figures that are used within loop 706 float minXTimesCosTPlusCenterX = minX*cosT+centerX; 707 float CenterYMinusminXTimesSinT = centerY-minX*sinT; 708 709 #define PSIMAGE_ROTATE_ARBITRARY_LOOP(TYPE,MODE) { \ 710 if (unexposedValue < PS_MIN_##TYPE || unexposedValue > PS_MAX_##TYPE) { \ 711 psError(__func__,"The given unexposedValue (%g) is outside of the " \ 712 "image type's range (%g->%g).", \ 713 unexposedValue, (double)PS_MIN_##TYPE,(double)PS_MAX_##TYPE); \ 714 psFree(out); \ 715 out = NULL; \ 716 break; \ 717 } \ 718 float inX; \ 719 float inY; \ 720 ps##TYPE* outRow; \ 721 for (int y = 0; y < outRows; y++) { \ 722 inX = minXTimesCosTPlusCenterX + (y+intMinY) * sinT; \ 723 inY = CenterYMinusminXTimesSinT + (y+intMinY) * cosT; \ 724 outRow = out->data.TYPE[y]; \ 725 for (int x = 0; x < outCols; x++) { \ 726 outRow[x] = p_psImagePixelInterpolate##MODE##_##TYPE(in,inX,inY,unexposedValue); \ 727 inX += cosT; \ 728 inY -= sinT; \ 729 } \ 730 } \ 731 } 732 733 #define PSIMAGE_ROTATE_ARBITRARY_CASE(MODE) \ 734 case PS_INTERPOLATE_##MODE: \ 735 switch (type) { \ 736 case PS_TYPE_U8: \ 737 PSIMAGE_ROTATE_ARBITRARY_LOOP(U8,MODE); \ 738 break; \ 739 case PS_TYPE_U16: \ 740 PSIMAGE_ROTATE_ARBITRARY_LOOP(U16,MODE); \ 741 break; \ 742 case PS_TYPE_U32: \ 743 PSIMAGE_ROTATE_ARBITRARY_LOOP(U32,MODE); \ 744 break; \ 745 case PS_TYPE_U64: \ 746 PSIMAGE_ROTATE_ARBITRARY_LOOP(U64,MODE); \ 747 break; \ 748 case PS_TYPE_S8: \ 749 PSIMAGE_ROTATE_ARBITRARY_LOOP(S8,MODE); \ 750 break; \ 751 case PS_TYPE_S16: \ 752 PSIMAGE_ROTATE_ARBITRARY_LOOP(S16,MODE); \ 753 break; \ 754 case PS_TYPE_S32: \ 755 PSIMAGE_ROTATE_ARBITRARY_LOOP(S32,MODE); \ 756 break; \ 757 case PS_TYPE_S64: \ 758 PSIMAGE_ROTATE_ARBITRARY_LOOP(S64,MODE); \ 759 break; \ 760 case PS_TYPE_F32: \ 761 PSIMAGE_ROTATE_ARBITRARY_LOOP(F32,MODE); \ 762 break; \ 763 case PS_TYPE_F64: \ 764 PSIMAGE_ROTATE_ARBITRARY_LOOP(F64,MODE); \ 765 break; \ 766 case PS_TYPE_C32: \ 767 PSIMAGE_ROTATE_ARBITRARY_LOOP(C32,MODE); \ 768 break; \ 769 case PS_TYPE_C64: \ 770 PSIMAGE_ROTATE_ARBITRARY_LOOP(C64,MODE); \ 771 break; \ 772 default: \ 773 psError(__func__,"Image type (%d) not supported",type); \ 774 psFree(out); \ 775 out = NULL; \ 776 } \ 777 break; 778 779 switch (mode) { 780 PSIMAGE_ROTATE_ARBITRARY_CASE(FLAT); 781 PSIMAGE_ROTATE_ARBITRARY_CASE(BILINEAR); 782 default: 783 psError(__func__,"Unsupported interpolation mode (%d)",mode); 784 psFree(out); 785 out = NULL; 786 } 787 } 603 } else if (fabsf(angle - 180.0f) < FLT_EPSILON) { 604 // perform 1/2 rotate 605 int numRows = in->numRows; 606 int lastRow = numRows - 1; 607 int numCols = in->numCols; 608 int lastCol = numCols - 1; 609 psElemType type = in->type.type; 610 611 out = psImageRecycle(out, numCols, numRows, type); 612 613 #define PSIMAGE_ROTATE_180_CASE(TYPE) \ 614 case PS_TYPE_##TYPE: { \ 615 for (int row=0;row<numRows;row++) { \ 616 ps##TYPE* outRow = out->data.TYPE[row]; \ 617 ps##TYPE* inRow = in->data.TYPE[lastRow-row]; \ 618 for (int col=0;col<numCols;col++) { \ 619 outRow[col] = inRow[lastCol - col]; \ 620 } \ 621 } \ 622 } \ 623 break; 624 625 switch (type) { 626 PSIMAGE_ROTATE_180_CASE(U8); 627 PSIMAGE_ROTATE_180_CASE(U16); 628 PSIMAGE_ROTATE_180_CASE(U32); 629 PSIMAGE_ROTATE_180_CASE(U64); 630 PSIMAGE_ROTATE_180_CASE(S8); 631 PSIMAGE_ROTATE_180_CASE(S16); 632 PSIMAGE_ROTATE_180_CASE(S32); 633 PSIMAGE_ROTATE_180_CASE(S64); 634 PSIMAGE_ROTATE_180_CASE(F32); 635 PSIMAGE_ROTATE_180_CASE(F64); 636 PSIMAGE_ROTATE_180_CASE(C32); 637 PSIMAGE_ROTATE_180_CASE(C64); 638 default: 639 psError(__func__, "Unsupported type (%d)", type); 640 psFree(out); 641 return NULL; 642 } 643 } else if (fabsf(angle - 270.0f) < FLT_EPSILON) { 644 // perform 1/4 rotate clockwise 645 int numRows = in->numCols; 646 int lastRow = numRows - 1; 647 int numCols = in->numRows; 648 psElemType type = in->type.type; 649 650 out = psImageRecycle(out, numCols, numRows, type); 651 652 #define PSIMAGE_ROTATE_RIGHT_90(TYPE) \ 653 case PS_TYPE_##TYPE: { \ 654 ps##TYPE** inData = in->data.TYPE; \ 655 for (int row=0;row<numRows;row++) { \ 656 ps##TYPE* outRow = out->data.TYPE[row]; \ 657 for (int col=0;col<numCols;col++) { \ 658 outRow[col] = inData[col][lastRow-row]; \ 659 } \ 660 } \ 661 } \ 662 break; 663 664 switch (type) { 665 PSIMAGE_ROTATE_RIGHT_90(U8); 666 PSIMAGE_ROTATE_RIGHT_90(U16); 667 PSIMAGE_ROTATE_RIGHT_90(U32); 668 PSIMAGE_ROTATE_RIGHT_90(U64); 669 PSIMAGE_ROTATE_RIGHT_90(S8); 670 PSIMAGE_ROTATE_RIGHT_90(S16); 671 PSIMAGE_ROTATE_RIGHT_90(S32); 672 PSIMAGE_ROTATE_RIGHT_90(S64); 673 PSIMAGE_ROTATE_RIGHT_90(F32); 674 PSIMAGE_ROTATE_RIGHT_90(F64); 675 PSIMAGE_ROTATE_RIGHT_90(C32); 676 PSIMAGE_ROTATE_RIGHT_90(C64); 677 default: 678 psError(__func__, "Unsupported type (%d)", type); 679 psFree(out); 680 return NULL; 681 } 682 } else if (fabsf(angle) < FLT_EPSILON) { 683 out = psImageCopy(out, in, in->type.type); 684 } else { 685 psElemType type = in->type.type; 686 int numRows = in->numRows; 687 int numCols = in->numCols; 688 double centerX = (float)(numCols) / 2.0f; 689 float centerY = (float)(numRows) / 2.0f; 690 float t = angle * (3.14159265358f / 180.0f); 691 float cosT = cosf(t); 692 float sinT = sinf(t); 693 694 // calculate the corners of the rotated 695 // image so we know the proper 696 // output image size. 697 // x' = x cos(t) + y sin(t); i.e, x' = 698 // (x-centerX)*cosT + 699 // (y-centerY)*sinT; 700 // y' = y cos(t) - x sin(t); i.e. y' = 701 // (y-centerY)*cosT - 702 // (x-centerX)*sinT; 703 704 int outCols = ceil(abs(numCols * cosT) + abs(numRows * sinT)) + 1; 705 int outRows = ceil(abs(numCols * sinT) + abs(numRows * cosT)) + 1; 706 float minX = (float)outCols / -2.0f; 707 int intMinY = outRows / -2; 708 709 out = psImageRecycle(out, outCols, outRows, type); 710 711 /* optimized public domain rotation routine by Karl Lager float cosT,sinT; cosT = cos(t); sinT = 712 * sin(t); for (y = min_y; y <= max_y; y++) { x' = min_x * cosT + y * sinT + x1'; y' = y * cosT - 713 * min_x * sinT + y1'; for (x = min_x; x <= max_x; x++) { if (x', y') * * * * * * * * is in the 714 * bounds of the bitmap, get pixel(x', y') and plot the pixel to (x, y) on screen. x' += cosT; y' -= 715 * sinT; } } */ 716 717 // precalculate some figures that are 718 // used within loop 719 float minXTimesCosTPlusCenterX = minX * cosT + centerX; 720 float CenterYMinusminXTimesSinT = centerY - minX * sinT; 721 722 #define PSIMAGE_ROTATE_ARBITRARY_LOOP(TYPE,MODE) { \ 723 if (unexposedValue < PS_MIN_##TYPE || unexposedValue > PS_MAX_##TYPE) { \ 724 psError(__func__,"The given unexposedValue (%g) is outside of the " \ 725 "image type's range (%g->%g).", \ 726 unexposedValue, (double)PS_MIN_##TYPE,(double)PS_MAX_##TYPE); \ 727 psFree(out); \ 728 out = NULL; \ 729 break; \ 730 } \ 731 float inX; \ 732 float inY; \ 733 ps##TYPE* outRow; \ 734 for (int y = 0; y < outRows; y++) { \ 735 inX = minXTimesCosTPlusCenterX + (y+intMinY) * sinT; \ 736 inY = CenterYMinusminXTimesSinT + (y+intMinY) * cosT; \ 737 outRow = out->data.TYPE[y]; \ 738 for (int x = 0; x < outCols; x++) { \ 739 outRow[x] = p_psImagePixelInterpolate##MODE##_##TYPE(in,inX,inY,unexposedValue); \ 740 inX += cosT; \ 741 inY -= sinT; \ 742 } \ 743 } \ 744 } 745 746 #define PSIMAGE_ROTATE_ARBITRARY_CASE(MODE) \ 747 case PS_INTERPOLATE_##MODE: \ 748 switch (type) { \ 749 case PS_TYPE_U8: \ 750 PSIMAGE_ROTATE_ARBITRARY_LOOP(U8,MODE); \ 751 break; \ 752 case PS_TYPE_U16: \ 753 PSIMAGE_ROTATE_ARBITRARY_LOOP(U16,MODE); \ 754 break; \ 755 case PS_TYPE_U32: \ 756 PSIMAGE_ROTATE_ARBITRARY_LOOP(U32,MODE); \ 757 break; \ 758 case PS_TYPE_U64: \ 759 PSIMAGE_ROTATE_ARBITRARY_LOOP(U64,MODE); \ 760 break; \ 761 case PS_TYPE_S8: \ 762 PSIMAGE_ROTATE_ARBITRARY_LOOP(S8,MODE); \ 763 break; \ 764 case PS_TYPE_S16: \ 765 PSIMAGE_ROTATE_ARBITRARY_LOOP(S16,MODE); \ 766 break; \ 767 case PS_TYPE_S32: \ 768 PSIMAGE_ROTATE_ARBITRARY_LOOP(S32,MODE); \ 769 break; \ 770 case PS_TYPE_S64: \ 771 PSIMAGE_ROTATE_ARBITRARY_LOOP(S64,MODE); \ 772 break; \ 773 case PS_TYPE_F32: \ 774 PSIMAGE_ROTATE_ARBITRARY_LOOP(F32,MODE); \ 775 break; \ 776 case PS_TYPE_F64: \ 777 PSIMAGE_ROTATE_ARBITRARY_LOOP(F64,MODE); \ 778 break; \ 779 case PS_TYPE_C32: \ 780 PSIMAGE_ROTATE_ARBITRARY_LOOP(C32,MODE); \ 781 break; \ 782 case PS_TYPE_C64: \ 783 PSIMAGE_ROTATE_ARBITRARY_LOOP(C64,MODE); \ 784 break; \ 785 default: \ 786 psError(__func__,"Image type (%d) not supported",type); \ 787 psFree(out); \ 788 out = NULL; \ 789 } \ 790 break; 791 792 switch (mode) { 793 PSIMAGE_ROTATE_ARBITRARY_CASE(FLAT); 794 PSIMAGE_ROTATE_ARBITRARY_CASE(BILINEAR); 795 default: 796 psError(__func__, "Unsupported interpolation mode (%d)", mode); 797 psFree(out); 798 out = NULL; 799 } 800 } 788 801 789 802 return out; 790 803 } 791 804 792 psImage* psImageShift(psImage* out, const psImage* in, float dx, float dy, psF64 unexposedValue, psImageInterpolateMode mode) 805 psImage *psImageShift(psImage * out, 806 const psImage * in, 807 float dx, float dy, psF64 unexposedValue, psImageInterpolateMode mode) 793 808 { 794 809 int outRows; … … 798 813 799 814 if (in == NULL) { 800 psError(__func__, "Input image can not be NULL.");815 psError(__func__, "Input image can not be NULL."); 801 816 return NULL; 802 817 } 803 804 // create an output image of the same sizeand type818 // create an output image of the same size 819 // and type 805 820 outRows = in->numRows; 806 821 outCols = in->numCols; 807 822 type = in->type.type; 808 823 elementSize = PSELEMTYPE_SIZEOF(type); 809 out = psImageRecycle(out, outCols, outRows, type);824 out = psImageRecycle(out, outCols, outRows, type); 810 825 811 826 #define PSIMAGE_SHIFT_CASE(TYPE) \ … … 842 857 PSIMAGE_SHIFT_CASE(C64); 843 858 default: 844 psError(__func__, "Image type (%d) not supported.",type);859 psError(__func__, "Image type (%d) not supported.", type); 845 860 psFree(out); 846 861 out = NULL;
Note:
See TracChangeset
for help on using the changeset viewer.
