Changeset 1250
- Timestamp:
- Jul 21, 2004, 1:39:10 PM (22 years ago)
- Location:
- trunk/psLib/src/image
- Files:
-
- 2 edited
-
psImageManip.c (modified) (3 diffs)
-
psImageManip.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/image/psImageManip.c
r1226 r1250 10 10 * @author Ross Harman, MHPCC 11 11 * 12 * @version $Revision: 1. 3$ $Name: not supported by cvs2svn $13 * @date $Date: 2004-07- 15 19:58:37$12 * @version $Revision: 1.4 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2004-07-21 23:39:10 $ 14 14 * 15 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 24 24 #include "psStats.h" 25 25 #include "psMemory.h" 26 #include "psImageStats.h" 26 27 27 28 bool getSpecifiedStatValue(const psStats* stats, double* value); … … 527 528 return out; 528 529 } 530 531 psImage* psImageRotate(psImage* out, const psImage* in, float angle, float unexposedValue, psImageInterpolateMode mode) 532 { 533 if (in == NULL) { 534 psError(__func__,"The input image was NULL."); 535 psFree(out); 536 return NULL; 537 } 538 539 // put the angle in the range of 0...360. 540 angle = angle - 360.0f*floor(angle/360.0f); 541 542 if (fabsf(angle-90.0f) < FLT_EPSILON) { 543 // perform 1/4 rotate counter-clockwise 544 int numRows = in->numCols; 545 int numCols = in->numRows; 546 int lastCol = numCols - 1; 547 psElemType type = in->type.type; 548 out = psImageRecycle(out,numCols,numRows,type); 549 550 #define PSIMAGE_ROTATE_LEFT_90(TYPE) \ 551 case PS_TYPE_##TYPE: { \ 552 ps##TYPE** inData = in->data.TYPE; \ 553 for (int row=0;row<numRows;row++) { \ 554 ps##TYPE* outRow = out->data.TYPE[row]; \ 555 for (int col=0;col<numCols;col++) { \ 556 outRow[col] = inData[lastCol-col][row]; \ 557 } \ 558 } \ 559 } \ 560 break; 561 562 switch (type) { 563 PSIMAGE_ROTATE_LEFT_90(U8); 564 PSIMAGE_ROTATE_LEFT_90(U16); 565 PSIMAGE_ROTATE_LEFT_90(U32); 566 PSIMAGE_ROTATE_LEFT_90(U64); 567 PSIMAGE_ROTATE_LEFT_90(S8); 568 PSIMAGE_ROTATE_LEFT_90(S16); 569 PSIMAGE_ROTATE_LEFT_90(S32); 570 PSIMAGE_ROTATE_LEFT_90(S64); 571 PSIMAGE_ROTATE_LEFT_90(F32); 572 PSIMAGE_ROTATE_LEFT_90(F64); 573 PSIMAGE_ROTATE_LEFT_90(C32); 574 PSIMAGE_ROTATE_LEFT_90(C64); 575 default: 576 psError(__func__,"Unsupported type (%d)",type); 577 psFree(out); 578 return NULL; 579 } 580 } else if (fabsf(angle-180.0f) < FLT_EPSILON) { 581 // perform 1/2 rotate 582 int numRows = in->numRows; 583 int lastRow = numRows - 1; 584 int numCols = in->numCols; 585 int lastCol = numCols - 1; 586 psElemType type = in->type.type; 587 out = psImageRecycle(out,numCols,numRows,type); 588 589 #define PSIMAGE_ROTATE_180_CASE(TYPE) \ 590 case PS_TYPE_##TYPE: { \ 591 for (int row=0;row<numRows;row++) { \ 592 ps##TYPE* outRow = out->data.TYPE[row]; \ 593 ps##TYPE* inRow = in->data.TYPE[lastRow-row]; \ 594 for (int col=0;col<numCols;col++) { \ 595 outRow[col] = inRow[lastCol - col]; \ 596 } \ 597 } \ 598 } \ 599 break; 600 601 switch (type) { 602 PSIMAGE_ROTATE_180_CASE(U8); 603 PSIMAGE_ROTATE_180_CASE(U16); 604 PSIMAGE_ROTATE_180_CASE(U32); 605 PSIMAGE_ROTATE_180_CASE(U64); 606 PSIMAGE_ROTATE_180_CASE(S8); 607 PSIMAGE_ROTATE_180_CASE(S16); 608 PSIMAGE_ROTATE_180_CASE(S32); 609 PSIMAGE_ROTATE_180_CASE(S64); 610 PSIMAGE_ROTATE_180_CASE(F32); 611 PSIMAGE_ROTATE_180_CASE(F64); 612 PSIMAGE_ROTATE_180_CASE(C32); 613 PSIMAGE_ROTATE_180_CASE(C64); 614 default: 615 psError(__func__,"Unsupported type (%d)",type); 616 psFree(out); 617 return NULL; 618 } 619 } else if (fabsf(angle-270.0f) < FLT_EPSILON) { 620 // perform 1/4 rotate clockwise 621 int numRows = in->numCols; 622 int lastRow = numRows - 1; 623 int numCols = in->numRows; 624 psElemType type = in->type.type; 625 out = psImageRecycle(out,numCols,numRows,type); 626 627 #define PSIMAGE_ROTATE_RIGHT_90(TYPE) \ 628 case PS_TYPE_##TYPE: { \ 629 ps##TYPE** inData = in->data.TYPE; \ 630 for (int row=0;row<numRows;row++) { \ 631 ps##TYPE* outRow = out->data.TYPE[row]; \ 632 for (int col=0;col<numCols;col++) { \ 633 outRow[col] = inData[col][lastRow-row]; \ 634 } \ 635 } \ 636 } \ 637 break; 638 639 switch (type) { 640 PSIMAGE_ROTATE_RIGHT_90(U8); 641 PSIMAGE_ROTATE_RIGHT_90(U16); 642 PSIMAGE_ROTATE_RIGHT_90(U32); 643 PSIMAGE_ROTATE_RIGHT_90(U64); 644 PSIMAGE_ROTATE_RIGHT_90(S8); 645 PSIMAGE_ROTATE_RIGHT_90(S16); 646 PSIMAGE_ROTATE_RIGHT_90(S32); 647 PSIMAGE_ROTATE_RIGHT_90(S64); 648 PSIMAGE_ROTATE_RIGHT_90(F32); 649 PSIMAGE_ROTATE_RIGHT_90(F64); 650 PSIMAGE_ROTATE_RIGHT_90(C32); 651 PSIMAGE_ROTATE_RIGHT_90(C64); 652 default: 653 psError(__func__,"Unsupported type (%d)",type); 654 psFree(out); 655 return NULL; 656 } 657 } else if (fabsf(angle) < FLT_EPSILON) { 658 out = psImageCopy(out,in,in->type.type); 659 } else { 660 psElemType type = in->type.type; 661 int numRows = in->numRows; 662 int numCols = in->numCols; 663 double centerX = (float)(numCols) / 2.0f; 664 float centerY = (float)(numRows) / 2.0f; 665 float t = angle*(3.14159265358f/180.0f); 666 float cosT = cosf(t); 667 float sinT = sinf(t); 668 float cosNegT = cosf(-t); 669 float sinNegT = sinf(-t); 670 671 // calculate the corners of the rotated image so we know the proper output image size. 672 // x' = x cos(t) + y sin(t); i.e, x' = (x-centerX)*cosT + (y-centerY)*sinT; 673 // y' = y cos(t) - x sin(t); i.e. y' = (y-centerY)*cosT - (x-centerX)*sinT; 674 675 #define rotateProjectX(x,y) (x-centerX)*cosNegT + (y-centerY)*sinNegT 676 #define rotateProjectY(x,y) (y-centerY)*cosNegT - (x-centerX)*sinNegT 677 678 // bottom-left, i.e., (0,0) 679 float xbl = rotateProjectX(0,0); 680 float ybl = rotateProjectY(0,0); 681 // bottom-right, i.e., (numCols,0) 682 float xbr = rotateProjectX(numCols,0); 683 float ybr = rotateProjectY(numCols,0); 684 // top-left, i.e., (0,numRows) 685 float xtl = rotateProjectX(0,numRows); 686 float ytl = rotateProjectY(0,numRows); 687 // top-right, i.e., (numCols,numRows) 688 float xtr = rotateProjectX(numCols,numRows); 689 float ytr = rotateProjectY(numCols,numRows); 690 691 float minX = xbl; 692 minX = (minX > xbr) ? xbr : minX; 693 minX = (minX > xtl) ? xtl : minX; 694 minX = (minX > xtr) ? xtr : minX; 695 696 float minY = ybl; 697 minY = (minY > ybr) ? ybr : minY; 698 minY = (minY > ytl) ? ytl : minY; 699 minY = (minY > ytr) ? ytr : minY; 700 701 float maxX = xbl; 702 maxX = (maxX < xbr) ? xbr : maxX; 703 maxX = (maxX < xtl) ? xtl : maxX; 704 maxX = (maxX < xtr) ? xtr : maxX; 705 706 float maxY = ybl; 707 maxY = (maxY < ybr) ? ybr : maxY; 708 maxY = (maxY < ytl) ? ytl : maxY; 709 maxY = (maxY < ytr) ? ytr : maxY; 710 711 int intMinY = minY; 712 int outRows = ceil(maxY-minY)+1; 713 int outCols = ceil(maxX-minX)+1; 714 715 out = psImageRecycle(out,outCols,outRows,type); 716 717 /* optimized public domain rotation routine by Karl Lager 718 float cosT,sinT; 719 cosT = cos(t); 720 sinT = sin(t); 721 for (y = min_y; y <= max_y; y++) 722 { x' = min_x * cosT + y * sinT + x1'; 723 y' = y * cosT - min_x * sinT + y1'; 724 for (x = min_x; x <= max_x; x++) 725 { if (x', y') is in the bounds of the bitmap, 726 get pixel(x', y') and plot the pixel to 727 (x, y) on screen. 728 x' += cosT; 729 y' -= sinT; 730 } 731 } 732 */ 733 734 // precalculate some figures that are used within loop 735 float minXTimesCosTPlusCenterX = minX*cosT+centerX; 736 float CenterYMinusminXTimesSinT = centerY-minX*sinT; 737 738 #define PSIMAGE_ROTATE_ARBITRARY_LOOP(TYPE,MODE) { \ 739 if (unexposedValue < PS_MIN_##TYPE || unexposedValue > PS_MAX_##TYPE) { \ 740 psError(__func__,"The given unexposedValue (%g) is outside of the " \ 741 "image type's range (%g->%g).", \ 742 unexposedValue, (double)PS_MIN_##TYPE,(double)PS_MAX_##TYPE); \ 743 psFree(out); \ 744 out = NULL; \ 745 break; \ 746 } \ 747 float inX; \ 748 float inY; \ 749 ps##TYPE* outRow; \ 750 for (int y = 0; y < outRows; y++) { \ 751 inX = minXTimesCosTPlusCenterX + (y+intMinY) * sinT; \ 752 inY = CenterYMinusminXTimesSinT + (y+intMinY) * cosT; \ 753 outRow = out->data.TYPE[y]; \ 754 for (int x = 0; x < outCols; x++) { \ 755 outRow[x] = p_psImagePixelInterpolate##MODE##_##TYPE(in,inX,inY,unexposedValue); \ 756 inX += cosT; \ 757 inY -= sinT; \ 758 } \ 759 } \ 760 } 761 762 #define PSIMAGE_ROTATE_ARBITRARY_CASE(MODE) \ 763 case PS_INTERPOLATE_##MODE: \ 764 switch (type) { \ 765 case PS_TYPE_U8: \ 766 PSIMAGE_ROTATE_ARBITRARY_LOOP(U8,MODE); \ 767 break; \ 768 case PS_TYPE_U16: \ 769 PSIMAGE_ROTATE_ARBITRARY_LOOP(U16,MODE); \ 770 break; \ 771 case PS_TYPE_U32: \ 772 PSIMAGE_ROTATE_ARBITRARY_LOOP(U32,MODE); \ 773 break; \ 774 case PS_TYPE_U64: \ 775 PSIMAGE_ROTATE_ARBITRARY_LOOP(U64,MODE); \ 776 break; \ 777 case PS_TYPE_S8: \ 778 PSIMAGE_ROTATE_ARBITRARY_LOOP(S8,MODE); \ 779 break; \ 780 case PS_TYPE_S16: \ 781 PSIMAGE_ROTATE_ARBITRARY_LOOP(S16,MODE); \ 782 break; \ 783 case PS_TYPE_S32: \ 784 PSIMAGE_ROTATE_ARBITRARY_LOOP(S32,MODE); \ 785 break; \ 786 case PS_TYPE_S64: \ 787 PSIMAGE_ROTATE_ARBITRARY_LOOP(S64,MODE); \ 788 break; \ 789 case PS_TYPE_F32: \ 790 PSIMAGE_ROTATE_ARBITRARY_LOOP(F32,MODE); \ 791 break; \ 792 case PS_TYPE_F64: \ 793 PSIMAGE_ROTATE_ARBITRARY_LOOP(F64,MODE); \ 794 break; \ 795 default: \ 796 psError(__func__,"Image type (%d) not supported",type); \ 797 psFree(out); \ 798 out = NULL; \ 799 } \ 800 break; 801 802 switch (mode) { 803 PSIMAGE_ROTATE_ARBITRARY_CASE(FLAT); 804 PSIMAGE_ROTATE_ARBITRARY_CASE(BILINEAR); 805 default: 806 psError(__func__,"Unsupported interpolation mode (%d)",mode); 807 psFree(out); 808 out = NULL; 809 } 810 } 811 812 return out; 813 } 814 815 psImage* psImageShift(psImage* out, const psImage* in, float dx, float dy, psF64 unexposedValue, psImageInterpolateMode mode) 816 { 817 int outRows; 818 int outCols; 819 int elementSize; 820 psElemType type; 821 822 if (in == NULL) { 823 psError(__func__,"Input image can not be NULL."); 824 return NULL; 825 } 826 827 // create an output image of the same size and type 828 outRows = in->numRows; 829 outCols = in->numCols; 830 type = in->type.type; 831 elementSize = PSELEMTYPE_SIZEOF(type); 832 out = psImageRecycle(out,outCols, outRows, type); 833 834 #define PSIMAGE_SHIFT_CASE(TYPE) \ 835 case PS_TYPE_##TYPE: \ 836 if (unexposedValue < PS_MIN_##TYPE || unexposedValue > PS_MAX_##TYPE) { \ 837 psError(__func__,"The given unexposedValue (%g) is outside of the " \ 838 "image type's range (%g->%g).", \ 839 unexposedValue, (double)PS_MIN_##TYPE,(double)PS_MAX_##TYPE); \ 840 psFree(out); \ 841 out = NULL; \ 842 break; \ 843 } \ 844 for (int row=0;row<outRows;row++) { \ 845 ps##TYPE* outRow = out->data.TYPE[row]; \ 846 float y = dy+(float)row; \ 847 for (int col=0;col<outCols;col++) { \ 848 outRow[col] = psImagePixelInterpolate(in,dx+(float)col,y,unexposedValue,mode); \ 849 } \ 850 } \ 851 break; 852 853 switch (in->type.type) { 854 PSIMAGE_SHIFT_CASE(U8); 855 PSIMAGE_SHIFT_CASE(U16); 856 PSIMAGE_SHIFT_CASE(U32); 857 PSIMAGE_SHIFT_CASE(U64); 858 PSIMAGE_SHIFT_CASE(S8); 859 PSIMAGE_SHIFT_CASE(S16); 860 PSIMAGE_SHIFT_CASE(S32); 861 PSIMAGE_SHIFT_CASE(S64); 862 PSIMAGE_SHIFT_CASE(F32); 863 PSIMAGE_SHIFT_CASE(F64); 864 PSIMAGE_SHIFT_CASE(C32); 865 PSIMAGE_SHIFT_CASE(C64); 866 default: 867 psError(__func__,"Image type (%d) not supported.",type); 868 psFree(out); 869 out = NULL; 870 } 871 return out; 872 } -
trunk/psLib/src/image/psImageManip.h
r1226 r1250 10 10 * @author Ross Harman, MHPCC 11 11 * 12 * @version $Revision: 1. 3$ $Name: not supported by cvs2svn $13 * @date $Date: 2004-07- 15 19:58:37$12 * @version $Revision: 1.4 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2004-07-21 23:39:10 $ 14 14 * 15 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 19 19 20 20 #include "psImage.h" 21 #include "psImageStats.h" 21 22 22 23 /// @addtogroup Image … … 104 105 ); 105 106 107 psImage* psImageRotate( 108 psImage* out, ///< an psImage to recycle. If NULL, a new image is created 109 const psImage* in, ///< input image 110 float angle, 111 float unexposedValue, 112 psImageInterpolateMode mode 113 ); 114 115 psImage* psImageShift( 116 psImage* out, ///< an psImage to recycle. If NULL, a new image is created 117 const psImage* in, ///< input image 118 float dx, 119 float dy, 120 float unexposedValue, 121 psImageInterpolateMode mode 122 ); 123 106 124 /** Roll image by an integer number of pixels in either direction. 107 125 *
Note:
See TracChangeset
for help on using the changeset viewer.
