/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ #include "mrilib.h" /*** NOT 7D SAFE ***/ /*** functions to "warp" images -- not very efficient, but quite general ***/ #ifdef HP # undef INLINE # pragma INLINE xxMRI_scaler # pragma INLINE xxMRI_rotfunc #endif #define FINS(i,j) ( ( (i)<0 || (j)<0 || (i)>=nx || (j)>=ny ) \ ? 0.0 : far[(i)+(j)*nx] ) /**************************************************************************/ static float sx_scale , sy_scale ; /* global scaler data */ /* inline func with static vars should be static 24 Sep 2015 [rickr] */ static INLINE void xxMRI_scaler( float xpr, float ypr, float *xx , float *yy ) { *xx = sx_scale * xpr ; *yy = sy_scale * ypr ; return ; } /**************************************************************************/ MRI_IMAGE *mri_warp( MRI_IMAGE *im , int nxnew , int nynew , int wtype , void wfunc(float,float,float *,float *) ) { switch( wtype ){ case MRI_BILINEAR: return mri_warp_bilinear( im , nxnew , nynew , wfunc ) ; case MRI_BICUBIC: return mri_warp_bicubic( im , nxnew , nynew , wfunc ) ; default: fprintf( stderr , "mri_warp: illegal wtype %d\n" , wtype ) ; MRI_FATAL_ERROR ; } return NULL ; } /****************************************************************************/ MRI_IMAGE *mri_resize_NN( MRI_IMAGE *im , int nxnew , int nynew ) /* 08 Jun 2004 */ { int nx,ny , nnx,nny , ii,jj , pp,qq , bb ; float fx,fy ; MRI_IMAGE *nim ; char *nar , *ar ; if( im == NULL ) return NULL ; nx = im->nx ; ny = im->ny ; nnx = nxnew ; nny = nynew ; fx = ((float)nx) / (float)nnx ; fy = ((float)ny) / (float)nny ; nim = mri_new( nnx , nny , im->kind ) ; nar = mri_data_pointer( nim ) ; ar = mri_data_pointer( im ) ; bb = im->pixel_size ; for( jj=0 ; jj < nny ; jj++ ){ qq = (int)( fy*jj ) ; for( ii=0 ; ii < nnx ; ii++ ){ pp = (int)( fx*ii ) ; memcpy( nar + (ii+jj*nnx)*bb , ar + (pp+qq*nx)*bb , bb ) ; } } MRI_COPY_AUX(nim,im) ; nim->dx *= fx ; nim->dy *= fy ; return nim ; } /****************************************************************************/ MRI_IMAGE *mri_squareaspect( MRI_IMAGE *im ) /* 08 Jun 2004 */ { int nx,ny , nxnew,nynew ; float dx,dy , rr ; if( im == NULL ) return NULL ; dx = fabs(im->dx) ; dy = fabs(im->dy) ; if( dx == 0.0 || dy == 0.0 ) return NULL ; rr = dy / dx ; if( rr == 1.0 ) return NULL ; nx = im->nx ; ny = im->ny ; if( rr < 1.0 ){ nxnew = rint( nx/rr ) ; if( nxnew <= nx ) return NULL ; nynew = ny ; } else { nynew = rint( ny*rr ) ; if( nynew <= ny ) return NULL ; nxnew = nx ; } return mri_resize_NN( im , nxnew , nynew ) ; } /****************************************************************************/ MRI_IMAGE *mri_resize( MRI_IMAGE *im , int nxnew , int nynew ) { int nx,ny , nnx,nny , wtype ; nx = im->nx ; ny = im->ny ; nnx = nxnew ; nny = nynew ; if( nnx <= 0 && nny <= 0 ){ fprintf( stderr , "mri_resize: nxnew,nynew = %d %d\n",nxnew,nynew ) ; MRI_FATAL_ERROR ; } sx_scale = (nnx > 0) ? ((float)nx)/nnx : 0.0 ; sy_scale = (nny > 0) ? ((float)ny)/nny : 0.0 ; if( nnx <= 0 ){ sx_scale = sy_scale ; nnx = sx_scale * nx ; } else if( nny <= 0 ){ sy_scale = sx_scale ; nny = sy_scale * ny ; } #if 0 wtype = MRI_BICUBIC ; if( ( ((nnx>=nx) && (nnx%nx==0)) || ((nnx=ny) && (nny%ny==0)) || ((nnynx ; /* input image dimensions, for convenience */ ny = im->ny ; nxnew = (nxnew > 0) ? nxnew : nx ; /* default output image sizes */ nynew = (nynew > 0) ? nynew : ny ; switch( im->kind ){ /* 29 Mar 2003: allow for different input types */ /* by doing components 1 at a time */ case MRI_float: imfl = im ; break ; default: imfl = mri_to_float(im) ; break ; case MRI_short:{ imfl = mri_to_float(im) ; newImg = mri_warp_bicubic( imfl , nxnew,nynew , wf ) ; mri_free(imfl) ; imfl = mri_to_mri(MRI_short,newImg) ; mri_free(newImg) ; return imfl ; } case MRI_byte:{ imfl = mri_to_float(im) ; newImg = mri_warp_bicubic( imfl , nxnew,nynew , wf ) ; mri_free(imfl) ; imfl = mri_to_mri(MRI_byte,newImg) ; mri_free(newImg) ; return imfl ; } case MRI_rgb:{ MRI_IMARR *imar = mri_rgb_to_3float(im) ; MRI_IMAGE *rim,*gim,*bim ; rim = mri_warp_bicubic( IMARR_SUBIM(imar,0), nxnew,nynew, wf ) ; gim = mri_warp_bicubic( IMARR_SUBIM(imar,1), nxnew,nynew, wf ) ; bim = mri_warp_bicubic( IMARR_SUBIM(imar,2), nxnew,nynew, wf ) ; DESTROY_IMARR(imar) ; newImg = mri_3to_rgb( rim,gim,bim ) ; mri_free(rim); mri_free(gim); mri_free(bim); return newImg; } } /* at this point, imfl is in MRI_float format */ far = mri_data_pointer( imfl ) ; /* easy access to float data */ newImg = mri_new( nxnew , nynew , MRI_float ) ; /* output image */ nar = mri_data_pointer( newImg ) ; /* output image data */ bot = top = far[0] ; /* 29 Mar 2003: */ for( ii=1 ; ii < imfl->nvox ; ii++ ){ /* clip output data range */ if( far[ii] > top ) top = far[ii] ; else if( far[ii] < bot ) bot = far[ii] ; } /*** loop over output points and warp to them ***/ for( jj=0 ; jj < nynew ; jj++ ){ ypr = jj ; for( ii=0 ; ii < nxnew ; ii++ ){ xpr = ii ; wf( xpr,ypr , &xx,&yy ) ; /* get xx,yy in original image */ ix = floor( xx ) ; fx = xx - ix ; /* integer and */ jy = floor( yy ) ; fy = yy - jy ; /* fractional coords */ /* define cubic interpolation polynomials and data from original grid */ #define P_M1(x) (-(x)*((x)-1)*((x)-2)) #define P_00(x) (3*((x)+1)*((x)-1)*((x)-2)) #define P_P1(x) (-3*(x)*((x)+1)*((x)-2)) #define P_P2(x) ((x)*((x)+1)*((x)-1)) wt_m1 = P_M1(fx) ; wt_00 = P_00(fx) ; /* weights for interpolating */ wt_p1 = P_P1(fx) ; wt_p2 = P_P2(fx) ; /* in the x-direction */ f_jm1 = wt_m1 * FINS(ix-1,jy-1) /* interpolate to ix + fx */ + wt_00 * FINS(ix ,jy-1) /* at levels jy-1 .. jy+2 */ + wt_p1 * FINS(ix+1,jy-1) + wt_p2 * FINS(ix+2,jy-1) ; f_j00 = wt_m1 * FINS(ix-1,jy) + wt_00 * FINS(ix ,jy) + wt_p1 * FINS(ix+1,jy) + wt_p2 * FINS(ix+2,jy) ; f_jp1 = wt_m1 * FINS(ix-1,jy+1) + wt_00 * FINS(ix ,jy+1) + wt_p1 * FINS(ix+1,jy+1) + wt_p2 * FINS(ix+2,jy+1) ; f_jp2 = wt_m1 * FINS(ix-1,jy+2) + wt_00 * FINS(ix ,jy+2) + wt_p1 * FINS(ix+1,jy+2) + wt_p2 * FINS(ix+2,jy+2) ; /* interpolate between y-levels to jy+fy */ val = ( P_M1(fy) * f_jm1 + P_00(fy) * f_j00 + P_P1(fy) * f_jp1 + P_P2(fy) * f_jp2 ) / 36.0 ; if( val > top ) val = top ; /* 29 Mar 2003 */ else if( val < bot ) val = bot ; nar[ii+jj*nxnew] = val ; } } /*** cleanup and return ***/ if( im != imfl ) mri_free(imfl) ; /* throw away unneeded workspace */ return newImg ; } /*************************************************************************/ MRI_IMAGE *mri_warp_bilinear( MRI_IMAGE *im , int nxnew , int nynew , void wf( float,float,float *,float *) ) { MRI_IMAGE *imfl , *newImg ; float *far , *nar ; float xpr,ypr , xx,yy , fx,fx1,fy,fy1 , f00,f10,f01,f11 ; int ii,jj, nx,ny , ix,jy ; nx = im->nx ; /* dimensions, for convenience */ ny = im->ny ; nxnew = (nxnew > 0) ? nxnew : nx ; /* default output image sizes */ nynew = (nynew > 0) ? nynew : ny ; if( im->kind == MRI_float ){ /* convert input to float, if needed */ imfl = im ; } else { imfl = mri_to_float( im ) ; } far = mri_data_pointer( imfl ) ; /* easy access to float data */ newImg = mri_new( nxnew , nynew , MRI_float ) ; /* output image */ nar = mri_data_pointer( newImg ) ; /* output image data */ /*** loop over output points and warp to them ***/ for( jj=0 ; jj < nynew ; jj++ ){ ypr = jj ; for( ii=0 ; ii < nxnew ; ii++ ){ xpr = ii ; wf( xpr,ypr , &xx,&yy ) ; /* get xx,yy in original image */ ix = floor( xx ) ; fx = xx - ix ; fx1 = 1.0 - fx ; jy = floor( yy ) ; fy = yy - jy ; fy1 = 1.0 - fy ; f00 = FINS(ix ,jy ) ; f01 = FINS(ix+1,jy ) ; f10 = FINS(ix ,jy+1) ; f11 = FINS(ix+1,jy+1) ; nar[ii+jj*nxnew] = fx1 * ( fy1 * f00 + fy * f01 ) +fx * ( fy1 * f10 + fy * f11 ) ; } } /*** cleanup and return ***/ if( im != imfl ) mri_free(imfl) ; /* throw away unneeded workspace */ return newImg ; } /**********************************************************************/ static float rot_dx , rot_dy , rot_cph , rot_sph ; /* global rotfunc data */ static INLINE void xxMRI_rotfunc(float xpr , float ypr , float *xx , float *yy) { *xx = rot_cph * xpr + rot_sph * ypr + rot_dx ; *yy = -rot_sph * xpr + rot_cph * ypr + rot_dy ; return ; } /**-------------------------------------------------------------------------------- Rotate and shift an image, using bicubic interpolation: aa = shift in x bb = shift in y phi = angle in radians scl = size scale factor (0.0 --> leave the same size) -----------------------------------------------------------------------------------**/ MRI_IMAGE *mri_rotate( MRI_IMAGE *im, float aa, float bb, float phi, float scl ) { MRI_IMAGE *imwarp ; int nxnew , nynew ; rot_cph = cos(phi) ; rot_sph = sin(phi) ; rot_dx = (0.5 * im->nx) * (1.0-rot_cph) - aa*rot_cph - bb*rot_sph -(0.5 * im->ny) * rot_sph ; rot_dy = (0.5 * im->nx) * rot_sph + aa*rot_sph - bb*rot_cph +(0.5 * im->ny) * (1.0-rot_cph) ; if( scl <= 0.0 ){ nxnew = nynew = 0 ; } else { nxnew = scl * im->nx + 0.49 ; nynew = scl * im->ny + 0.49 ; rot_cph /= scl ; rot_sph /= scl ; } return mri_warp_bicubic( im , nxnew,nynew , xxMRI_rotfunc ) ; } MRI_IMAGE *mri_rotate_bilinear( MRI_IMAGE *im, float aa, float bb, float phi, float scl ) { MRI_IMAGE *imwarp ; int nxnew , nynew ; rot_cph = cos(phi) ; rot_sph = sin(phi) ; rot_dx = (0.5 * im->nx) * (1.0-rot_cph) - aa*rot_cph - bb*rot_sph -(0.5 * im->ny) * rot_sph ; rot_dy = (0.5 * im->nx) * rot_sph + aa*rot_sph - bb*rot_cph +(0.5 * im->ny) * (1.0-rot_cph) ; if( scl <= 0.0 ){ nxnew = nynew = 0 ; } else { nxnew = scl * im->nx + 0.49 ; nynew = scl * im->ny + 0.49 ; rot_cph /= scl ; rot_sph /= scl ; } return mri_warp_bilinear( im , nxnew,nynew , xxMRI_rotfunc ) ; } #undef WARP_POINT_ROUTINES #ifdef WARP_POINT_ROUTINES /*-------------------------------------------------------------------- Return one point from a warped image ----------------------------------------------------------------------*/ #define INSIDE(i,j) ( ( (i)<0 || (j)<0 || (i)>=nx || (j)>=ny ) ? 0.0 : \ (kk==MRI_byte) ? (float) MRI_BYTE_PIXEL(im,i,j) : \ (kk==MRI_short) ? (float) MRI_SHORT_PIXEL(im,i,j) : \ (kk==MRI_int) ? (float) MRI_INT_PIXEL(im,i,j) : \ (kk==MRI_float) ? (float) MRI_FLOAT_PIXEL(im,i,j) : \ (kk==MRI_double) ? (float) MRI_DOUBLE_PIXEL(im,i,j) : \ (kk==MRI_complex) ? (float) CABS(MRI_COMPLEX_PIXEL(im,i,j)) : 0.0 ) float mri_warp_bicubic_point( MRI_IMAGE *im , int ii , int jj , void wf( float,float,float *,float *) ) { float xx,yy , fx,fy , newPt ; int nx,ny , ix,jy , kk ; float f_jm1,f_j00,f_jp1,f_jp2 , wt_m1,wt_00,wt_p1,wt_p2 ; nx = im->nx ; /* input image dimensions, for convenience */ ny = im->ny ; kk = im->kind ; /*** warp to output point ***/ wf( (float) ii , (float) jj , &xx,&yy ) ; /* get xx,yy in original image */ ix = floor( xx ) ; fx = xx - ix ; /* integer and */ jy = floor( yy ) ; fy = yy - jy ; /* fractional coords */ wt_m1 = P_M1(fx) ; wt_00 = P_00(fx) ; /* weights for interpolating */ wt_p1 = P_P1(fx) ; wt_p2 = P_P2(fx) ; /* in the x-direction */ f_jm1 = wt_m1 * INSIDE(ix-1,jy-1) /* interpolate to ix + fx */ + wt_00 * INSIDE(ix ,jy-1) /* at levels jy-1 .. jy+2 */ + wt_p1 * INSIDE(ix+1,jy-1) + wt_p2 * INSIDE(ix+2,jy-1) ; f_j00 = wt_m1 * INSIDE(ix-1,jy) + wt_00 * INSIDE(ix ,jy) + wt_p1 * INSIDE(ix+1,jy) + wt_p2 * INSIDE(ix+2,jy) ; f_jp1 = wt_m1 * INSIDE(ix-1,jy+1) + wt_00 * INSIDE(ix ,jy+1) + wt_p1 * INSIDE(ix+1,jy+1) + wt_p2 * INSIDE(ix+2,jy+1) ; f_jp2 = wt_m1 * INSIDE(ix-1,jy+2) + wt_00 * INSIDE(ix ,jy+2) + wt_p1 * INSIDE(ix+1,jy+2) + wt_p2 * INSIDE(ix+2,jy+2) ; /* interpolate between y-levels to jy+fy */ newPt = ( P_M1(fy) * f_jm1 + P_00(fy) * f_j00 + P_P1(fy) * f_jp1 + P_P2(fy) * f_jp2 ) / 36.0 ; return newPt ; } /*-------------------------------------------------------------------- Return one point from a rotated image ----------------------------------------------------------------------*/ float mri_rotate_point( MRI_IMAGE *im, float aa, float bb, float phi, float scl , int ix , int jy ) { MRI_IMAGE *imwarp ; int nxnew , nynew ; rot_cph = cos(phi) ; rot_sph = sin(phi) ; rot_dx = (0.5 * im->nx) * (1.0-rot_cph) - aa*rot_cph - bb*rot_sph -(0.5 * im->ny) * rot_sph ; rot_dy = (0.5 * im->nx) * rot_sph + aa*rot_sph - bb*rot_cph +(0.5 * im->ny) * (1.0-rot_cph) ; if( scl > 0.0 ){ rot_cph /= scl ; rot_sph /= scl ; } return mri_warp_bicubic_point( im , ix,jy , xxMRI_rotfunc ) ; } #endif /* WARP_POINT_ROUTINES */