/***************************************************************************** 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 ***/ static void (*usammer)(int,int,float *,float *) = upsample_7 ; static int usammer_mode = 7 ; static void upsample_1by2( int, byte *, byte * ) ; /* at end of file */ static void upsample_1by3( int, byte *, byte * ) ; static void upsample_1by4( int, byte *, byte * ) ; static MRI_IMAGE * mri_dup2D_rgb4( MRI_IMAGE *) ; /* 14 Mar 2002 */ static MRI_IMAGE * mri_dup2D_rgb3( MRI_IMAGE *) ; /* 14 Mar 2002 */ static MRI_IMAGE * mri_dup2D_rgb2( MRI_IMAGE *) ; /* 22 Mar 2002 */ static MRI_IMAGE * mri_dup2D_rgb_NN( MRI_IMAGE *, int);/* 22 Feb 2004 [rickr] */ /*----------------------------------------------------------------------------- Set resample mode for mri_dup2D (1 or 7) -------------------------------------------------------------------------------*/ void mri_dup2D_mode( int mm ) { switch( mm ){ case 1: usammer = upsample_1 ; break ; default: usammer = upsample_7 ; break ; } usammer_mode = mm ; } /*------------------------------------------------------------------------------ Blow up a 2D image nup times, using 7th order polynomial for interpolation. --------------------------------------------------------------------------------*/ MRI_IMAGE * mri_dup2D( int nup , MRI_IMAGE *imin ) { MRI_IMAGE *flim , *newim ; float *flar , *newar , *cold , *cnew ; int nx,ny , nxup,nyup , ii,jj,kk, NNmode = 0 ; ENTRY("mri_dup2D") ; /*-- sanity checks --*/ if( nup < 1 || imin == NULL ) RETURN( NULL ); if( nup == 1 ){ newim = mri_to_mri( imin->kind, imin ); RETURN(newim); } /* does the user want neighbor interpolation? 22 Feb 2004 [rickr] */ if( usammer_mode != -7 && AFNI_yesenv("AFNI_IMAGE_ZOOM_NN") ){ mri_dup2D_mode(0); NNmode = 1; } /*-- complex-valued images: do each part separately --*/ if( imin->kind == MRI_complex ){ MRI_IMARR *impair ; MRI_IMAGE *rim, *iim, *tim ; impair = mri_complex_to_pair( imin ) ; if( impair == NULL ){ fprintf(stderr,"*** mri_complex_to_pair fails in mri_dup2D!\n"); EXIT(1); } rim = IMAGE_IN_IMARR(impair,0) ; iim = IMAGE_IN_IMARR(impair,1) ; FREE_IMARR(impair) ; tim = mri_dup2D( nup, rim ); mri_free( rim ); rim = tim ; tim = mri_dup2D( nup, iim ); mri_free( iim ); iim = tim ; newim = mri_pair_to_complex( rim , iim ) ; mri_free( rim ) ; mri_free( iim ) ; MRI_COPY_AUX(newim,imin) ; RETURN(newim) ; } /*-- 14 Mar 2002: RGB image up by 2..4, all colors at once --*/ if( imin->kind == MRI_rgb ){ MRI_IMAGE *qqim=NULL ; if ( NNmode ) qqim = mri_dup2D_rgb_NN(imin, nup); /* 22 Feb 2004 [rickr] */ else { if( usammer_mode != -7 ){ switch(nup){ case 4: qqim = mri_dup2D_rgb4(imin); break; /* special purpose fast codes */ case 3: qqim = mri_dup2D_rgb3(imin); break; /* using fixed pt arithmetic */ case 2: qqim = mri_dup2D_rgb2(imin); break; } } if( qqim == NULL ){ /*-- other factors: do each color separately as a byte image --*/ MRI_IMARR *imtriple ; MRI_IMAGE *rim, *gim, *bim, *tim ; imtriple = mri_rgb_to_3byte( imin ) ; if( imtriple == NULL ){ /* should never happen */ fprintf(stderr,"*** mri_rgb_to_3byte fails in mri_dup2D!\n"); RETURN(NULL); } rim = IMAGE_IN_IMARR(imtriple,0) ; gim = IMAGE_IN_IMARR(imtriple,1) ; bim = IMAGE_IN_IMARR(imtriple,2) ; FREE_IMARR(imtriple) ; tim = mri_dup2D( nup, rim ); mri_free(rim); rim = tim; tim = mri_dup2D( nup, gim ); mri_free(gim); gim = tim; tim = mri_dup2D( nup, bim ); mri_free(bim); bim = tim; newim = mri_3to_rgb( rim, gim, bim ) ; mri_free(rim) ; mri_free(gim) ; mri_free(bim) ; MRI_COPY_AUX(newim,imin) ; qqim = newim ; } } RETURN(qqim) ; } /*-- Special case: byte-valued image upsampled by 2/3/4 [13 Mar 2002] --*/ if( imin->kind == MRI_byte && nup <= 4 && usammer_mode != -7 ){ void (*usbyte)(int,byte *,byte *) = NULL ; byte *bar=MRI_BYTE_PTR(imin) , *bnew , *cold, *cnew ; nx = imin->nx; ny = imin->ny; nxup = nx*nup; nyup = ny*nup ; newim = mri_new( nxup,nyup , MRI_byte ); bnew = MRI_BYTE_PTR(newim); switch( nup ){ case 2: usbyte = upsample_1by2 ; break ; /* special fast codes */ case 3: usbyte = upsample_1by3 ; break ; case 4: usbyte = upsample_1by4 ; break ; } for( jj=0 ; jj < ny ; jj++ ) /* upsample rows */ usbyte( nx , bar+jj*nx , bnew+jj*nxup ) ; cold = (byte *) malloc( sizeof(byte) * ny ) ; cnew = (byte *) malloc( sizeof(byte) * nyup ) ; for( ii=0 ; ii < nxup ; ii++ ){ /* upsample cols */ for( jj=0 ; jj < ny ; jj++ ) cold[jj] = bnew[ii+jj*nxup] ; usbyte( ny , cold , cnew ) ; for( jj=0 ; jj < nyup ; jj++ ) bnew[ii+jj*nxup] = cnew[jj] ; } free(cold); free(cnew); MRI_COPY_AUX(newim,imin); RETURN(newim); } /*-- otherwise, make sure we operate on a float image --*/ if( imin->kind == MRI_float ) flim = imin ; else flim = mri_to_float( imin ) ; flar = MRI_FLOAT_PTR(flim) ; nx = flim->nx ; ny = flim->ny ; nxup = nx*nup ; nyup = ny*nup ; newim = mri_new( nxup , nyup , MRI_float ) ; newar = MRI_FLOAT_PTR(newim) ; /*-- upsample rows --*/ for( jj=0 ; jj < ny ; jj++ ) usammer( nup , nx , flar + jj*nx , newar + jj*nxup ) ; if( flim != imin ) mri_free(flim) ; /*-- upsample columns --*/ cold = (float *) malloc( sizeof(float) * ny ) ; cnew = (float *) malloc( sizeof(float) * nyup ) ; if( cold == NULL || cnew == NULL ){ fprintf(stderr,"*** mri_dup2D malloc failure!\n"); EXIT(1); } for( ii=0 ; ii < nxup ; ii++ ){ for( jj=0 ; jj < ny ; jj++ ) cold[jj] = newar[ii + jj*nxup] ; usammer( nup , ny , cold , cnew ) ; for( jj=0 ; jj < nyup ; jj++ ) newar[ii+jj*nxup] = cnew[jj] ; } free(cold) ; free(cnew) ; /*-- type convert output, if necessary --*/ switch( imin->kind ){ default: break ; case MRI_byte:{ byte * bar ; MRI_IMAGE * bim ; float fmin , fmax ; bim = mri_new( nxup,nyup , MRI_byte ) ; bar = MRI_BYTE_PTR(bim) ; fmin = mri_min(imin) ; fmax = mri_max(imin) ; for( ii=0 ; ii < newim->nvox ; ii++ ) bar[ii] = (newar[ii] < fmin) ? fmin : (newar[ii] > fmax) ? fmax : newar[ii] ; mri_free(newim) ; newim = bim ; } break ; case MRI_short:{ short * sar ; MRI_IMAGE * sim ; float fmin , fmax ; sim = mri_new( nxup,nyup , MRI_short ) ; sar = MRI_SHORT_PTR(sim) ; fmin = mri_min(imin) ; fmax = mri_max(imin) ; for( ii=0 ; ii < newim->nvox ; ii++ ) sar[ii] = (newar[ii] < fmin) ? fmin : (newar[ii] > fmax) ? fmax : newar[ii] ; mri_free(newim) ; newim = sim ; } break ; case MRI_float:{ float fmin , fmax ; fmin = mri_min(imin) ; fmax = mri_max(imin) ; for( ii=0 ; ii < newim->nvox ; ii++ ) if( newar[ii] < fmin ) newar[ii] = fmin ; else if( newar[ii] > fmax ) newar[ii] = fmax ; } } /*-- finito --*/ MRI_COPY_AUX(newim,imin) ; RETURN( newim ); } /*======================================================================*/ /*-- seventh order Lagrange polynomials --*/ #define S_M3(x) (x*(x*x-1.0)*(x*x-4.0)*(x-3.0)*(4.0-x)*0.0001984126984) #define S_M2(x) (x*(x*x-1.0)*(x-2.0)*(x*x-9.0)*(x-4.0)*0.001388888889) #define S_M1(x) (x*(x-1.0)*(x*x-4.0)*(x*x-9.0)*(4.0-x)*0.004166666667) #define S_00(x) ((x*x-1.0)*(x*x-4.0)*(x*x-9.0)*(x-4.0)*0.006944444444) #define S_P1(x) (x*(x+1.0)*(x*x-4.0)*(x*x-9.0)*(4.0-x)*0.006944444444) #define S_P2(x) (x*(x*x-1.0)*(x+2.0)*(x*x-9.0)*(x-4.0)*0.004166666667) #define S_P3(x) (x*(x*x-1.0)*(x*x-4.0)*(x+3.0)*(4.0-x)*0.001388888889) #define S_P4(x) (x*(x*x-1.0)*(x*x-4.0)*(x*x-9.0)*0.0001984126984) /* ZFILL (zero fill off edges) is not set by default: would have to be set by compile command or by a file #include-ing this one */ #ifdef ZFILL # define FINS(i) ( ((i)<0 || (i)>=nar) ? 0.0 : far[(i)] ) #else # define FINS(i) ( ((i)<0) ? far[0] : ((i)>=nar) ? far[nar-1] : far[(i)] ) #endif #define INT7(k,i) ( fm3[k] * far[i-3] + fm2[k] * far[i-2] \ + fm1[k] * far[i-1] + f00[k] * far[i ] \ + fp1[k] * far[i+1] + fp2[k] * far[i+2] \ + fp3[k] * far[i+3] + fp4[k] * far[i+4] ) #define FINT7(k,i) ( fm3[k] * FINS(i-3) + fm2[k] * FINS(i-2) \ + fm1[k] * FINS(i-1) + f00[k] * FINS(i ) \ + fp1[k] * FINS(i+1) + fp2[k] * FINS(i+2) \ + fp3[k] * FINS(i+3) + fp4[k] * FINS(i+4) ) #define RENUP_VEC(vv,kk) { (vv) = (float *)realloc((vv),(kk)*sizeof(float)); } /*---------------------------------------------------------------------------- Up sample an array far[0..nar-1] nup times to produce fout[0..nar*nup-1]. Uses 7th order polynomial interpolation. ------------------------------------------------------------------------------*/ void upsample_7( int nup , int nar , float * far , float * fout ) { int kk,ii , ibot,itop ; static int nupold = -1 ; static int nupmax = 0; static float *fm3=NULL, *fm2=NULL, *fm1=NULL, *f00=NULL, *fp1=NULL, *fp2=NULL, *fp3=NULL, *fp4=NULL; /*-- sanity checks --*/ if( nup < 1 || nar < 2 || far == NULL || fout == NULL ) return ; if (nupmax < nup) { nupmax = nup; RENUP_VEC(fm3,nup); RENUP_VEC(fm2,nup); RENUP_VEC(fm1,nup); RENUP_VEC(f00,nup); RENUP_VEC(fp1,nup); RENUP_VEC(fp2,nup); RENUP_VEC(fp3,nup); RENUP_VEC(fp4,nup); } if( nup == 1 ){ memcpy( fout, far, sizeof(float)*nar ); return; } /*-- initialize interpolation coefficient, if nup has changed --*/ if( nup != nupold ){ float val ; for( kk=0 ; kk < nup ; kk++ ){ val = ((float)kk) / ((float)nup) ; fm3[kk] = S_M3(val); fm2[kk] = S_M2(val); fm1[kk] = S_M1(val); f00[kk] = S_00(val); fp1[kk] = S_P1(val); fp2[kk] = S_P2(val); fp3[kk] = S_P3(val); fp4[kk] = S_P4(val); } nupold = nup ; } /*-- interpolate the intermediate places --*/ ibot = 3 ; itop = nar-5 ; switch( nup ){ default: /* outer and inner loops */ for( ii=ibot ; ii <= itop ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = INT7(kk,ii) ; break ; case 2: /* unrolled for optimizer */ for( ii=ibot ; ii <= itop ; ii++ ){ fout[ii*nup] = INT7(0,ii) ; fout[ii*nup+1] = INT7(1,ii) ; } break ; case 3: /* unrolled for optimizer */ for( ii=ibot ; ii <= itop ; ii++ ){ fout[ii*nup] = INT7(0,ii) ; fout[ii*nup+1] = INT7(1,ii) ; fout[ii*nup+2] = INT7(2,ii) ; } break ; case 4: /* unrolled for optimizer */ for( ii=ibot ; ii <= itop ; ii++ ){ fout[ii*nup] = INT7(0,ii) ; fout[ii*nup+1] = INT7(1,ii) ; fout[ii*nup+2] = INT7(2,ii) ; fout[ii*nup+3] = INT7(3,ii) ; } break ; } /*-- do what has not be done --*/ if( ibot > itop ){ /* for very short input arrays (nar < 8) */ for( ii=0 ; ii < nar ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = FINT7(kk,ii) ; } else { /* just the edges for longer arrays */ for( ii=0 ; ii < ibot ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = FINT7(kk,ii) ; for( ii=itop+1 ; ii < nar ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = FINT7(kk,ii) ; } return ; } /*======================================================================*/ #define INT1(k,i) (f00[k]*far[i] + fp1[k]*far[i+1] ) #define FINT1(k,i) (f00[k]*FINS(i) + fp1[k]*FINS(i+1)) /*---------------------------------------------------------------------------- Up sample an array far[0..nar-1] nup times to produce fout[0..nar*nup-1]. Uses linear polynomial interpolation. ------------------------------------------------------------------------------*/ void upsample_1( int nup , int nar , float * far , float * fout ) { int kk,ii , ibot,itop ; static int nupold=-1 ; static int nupmax=0; static float *f00=NULL, *fp1=NULL ; /*-- sanity checks --*/ if( nup < 1 || nar < 2 || far == NULL || fout == NULL ) return ; if (nupmax < nup) { nupmax = nup; RENUP_VEC(f00,nup); RENUP_VEC(fp1,nup); } if( nup == 1 ){ memcpy( fout, far, sizeof(float)*nar ); return; } /*-- initialize interpolation coefficient, if nup has changed --*/ if( nup != nupold ){ float val ; for( kk=0 ; kk < nup ; kk++ ){ val = ((float)kk) / ((float)nup) ; f00[kk] = 1.0 - val ; fp1[kk] = val ; } nupold = nup ; } /*-- interpolate the intermediate places --*/ ibot = 0 ; itop = nar-2 ; switch( nup ){ default: for( ii=ibot ; ii <= itop ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = INT1(kk,ii) ; break ; case 2: for( ii=ibot ; ii <= itop ; ii++ ){ fout[ii*nup] = INT1(0,ii) ; fout[ii*nup+1] = INT1(1,ii) ; } break ; case 3: for( ii=ibot ; ii <= itop ; ii++ ){ fout[ii*nup] = INT1(0,ii) ; fout[ii*nup+1] = INT1(1,ii) ; fout[ii*nup+2] = INT1(2,ii) ; } break ; case 4: for( ii=ibot ; ii <= itop ; ii++ ){ fout[ii*nup] = INT1(0,ii) ; fout[ii*nup+1] = INT1(1,ii) ; fout[ii*nup+2] = INT1(2,ii) ; fout[ii*nup+3] = INT1(3,ii) ; } break ; } /*-- interpolate the outside edges --*/ #if 0 /* nugatory */ for( ii=0 ; ii < ibot ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = FINT1(kk,ii) ; #endif for( ii=itop+1 ; ii < nar ; ii++ ) for( kk=0 ; kk < nup ; kk++ ) fout[kk+ii*nup] = FINT1(kk,ii) ; return ; } /*------------------------------------------------------------------*/ /*! Upsample an array of bytes by exactly 2. --------------------------------------------------------------------*/ static void upsample_1by2( int nar, byte *bar , byte *bout ) { int ii ; if( nar < 1 || bar == NULL || bout == NULL ) return ; for( ii=0 ; ii < nar-1 ; ii++ ){ bout[2*ii] = bar[ii] ; bout[2*ii+1] = (bar[ii]+bar[ii+1]) >> 1 ; } bout[2*nar-1] = bout[2*nar-2] = bar[nar-1] ; } /*------------------------------------------------------------------*/ /*! Upsample an array of bytes by exactly 3. --------------------------------------------------------------------*/ static void upsample_1by3( int nar, byte *bar , byte *bout ) { int ii ; if( nar < 1 || bar == NULL || bout == NULL ) return ; /* Note that 85/256 is about 1/3 and 171/256 is about 2/3; */ /* by using this trick, we avoid division and so are faster */ for( ii=0 ; ii < nar-1 ; ii++ ){ bout[3*ii] = bar[ii] ; bout[3*ii+1] = (171*bar[ii]+ 85*bar[ii+1]) >> 8 ; bout[3*ii+2] = ( 85*bar[ii]+171*bar[ii+1]) >> 8 ; } bout[3*nar-1] = bout[3*nar-2] = bout[3*nar-3] = bar[nar-1] ; } /*------------------------------------------------------------------*/ /*! Upsample an array of bytes by exactly 4. --------------------------------------------------------------------*/ static void upsample_1by4( int nar, byte *bar , byte *bout ) { int ii ; if( nar < 1 || bar == NULL || bout == NULL ) return ; for( ii=0 ; ii < nar-1 ; ii++ ){ bout[4*ii] = bar[ii] ; bout[4*ii+1] = (3*bar[ii]+ bar[ii+1]) >> 2 ; bout[4*ii+2] = ( bar[ii]+ bar[ii+1]) >> 1 ; bout[4*ii+3] = ( bar[ii]+3*bar[ii+1]) >> 2 ; } bout[4*nar-1] = bout[4*nar-2] = bout[4*nar-3] = bout[4*nar-4] = bar[nar-1]; } /*************************************************************************/ /*************************************************************************/ /* added option for nearest neighbor (if AFNI_IMAGE_ZOOM_NN is Y/y) 22 Feb 2004 [rickr] */ static MRI_IMAGE * mri_dup2D_rgb_NN( MRI_IMAGE *inim, int nup ) { rgbyte *bin , *bout , *bin1 ; MRI_IMAGE *outim ; int ii,jj,kk,ll , nx,ny , nxup,nyup ; ENTRY("mri_dup2D_rgb_NN") ; if( inim == NULL || inim->kind != MRI_rgb ) RETURN(NULL); bin = (rgbyte *) MRI_RGB_PTR(inim); if( bin == NULL ) RETURN(NULL); /* make output image **/ nx = inim->nx ; ny = inim->ny ; nxup = nup*nx ; nyup = nup*ny ; outim = mri_new( nxup , nyup , MRI_rgb ) ; bout = (rgbyte *) MRI_RGB_PTR(outim) ; for( jj=0 ; jj < ny ; jj++ ){ /* loop over input rows */ for ( kk= 0; kk < nup; kk++ ) { /* do rows nup times */ bin1 = bin; for( ii=0 ; ii < nx ; ii++ ){ for ( ll= 0; ll < nup; ll++ ) { *bout++ = *bin1; } bin1++; } } bin += nx ; } MRI_COPY_AUX(outim,inim) ; RETURN(outim) ; } /*************************************************************************/ /*************************************************************************/ static MRI_IMAGE * mri_dup2D_rgb4( MRI_IMAGE *inim ) { rgbyte *bin , *bout , *bin1,*bin2 , *bout1,*bout2,*bout3,*bout4 ; MRI_IMAGE *outim ; int ii,jj , nx,ny , nxup,nyup ; ENTRY("mri_dup2D_rgb4") ; if( inim == NULL || inim->kind != MRI_rgb ) RETURN(NULL); bin = (rgbyte *) MRI_RGB_PTR(inim); if( bin == NULL ) RETURN(NULL); /* make output image **/ nx = inim->nx ; ny = inim->ny ; nxup = 4*nx ; nyup = 4*ny ; outim = mri_new( nxup , nyup , MRI_rgb ) ; bout = (rgbyte *) MRI_RGB_PTR(outim) ; /** macros for the 16 different interpolations between the four corners: ul ur > 00 10 20 30 >=> 01 11 21 31 >=> 02 12 22 32 ll lr > 03 13 23 33 **/ #define BOUT(ul,ur,ll,lr,a,b,c,d) ((a*ul+b*ur+c*ll+d*lr) >> 6) #define BOUT_00(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,49, 7, 7, 1) #define BOUT_10(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,35,21, 5, 3) #define BOUT_20(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,21,35, 3, 5) #define BOUT_30(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 7,49, 1, 7) #define BOUT_01(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,35, 5,21, 3) #define BOUT_11(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,25,15,15, 9) #define BOUT_21(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,15,25, 9,15) #define BOUT_31(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 5,35, 3,21) #define BOUT_02(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,21, 3,35, 5) #define BOUT_12(ul,ur,ll,lr) BOUT(ul,ur,ll,lr,15, 9,25,15) #define BOUT_22(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 9,15,15,25) #define BOUT_32(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 3,21, 5,35) #define BOUT_03(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 7, 1,49, 7) #define BOUT_13(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 5, 3,35,21) #define BOUT_23(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 3, 5,21,35) #define BOUT_33(ul,ur,ll,lr) BOUT(ul,ur,ll,lr, 1, 7, 7,49) /** do 16 interpolations between ul ur ll lr for index #k, color #c **/ #define FOUR_ROWS(k,c,ul,ur,ll,lr) \ { bout1[4*k+2].c = BOUT_00(ul.c,ur.c,ll.c,lr.c) ; \ bout1[4*k+3].c = BOUT_10(ul.c,ur.c,ll.c,lr.c) ; \ bout1[4*k+4].c = BOUT_20(ul.c,ur.c,ll.c,lr.c) ; \ bout1[4*k+5].c = BOUT_30(ul.c,ur.c,ll.c,lr.c) ; \ bout2[4*k+2].c = BOUT_01(ul.c,ur.c,ll.c,lr.c) ; \ bout2[4*k+3].c = BOUT_11(ul.c,ur.c,ll.c,lr.c) ; \ bout2[4*k+4].c = BOUT_21(ul.c,ur.c,ll.c,lr.c) ; \ bout2[4*k+5].c = BOUT_31(ul.c,ur.c,ll.c,lr.c) ; \ bout3[4*k+2].c = BOUT_02(ul.c,ur.c,ll.c,lr.c) ; \ bout3[4*k+3].c = BOUT_12(ul.c,ur.c,ll.c,lr.c) ; \ bout3[4*k+4].c = BOUT_22(ul.c,ur.c,ll.c,lr.c) ; \ bout3[4*k+5].c = BOUT_32(ul.c,ur.c,ll.c,lr.c) ; \ bout4[4*k+2].c = BOUT_03(ul.c,ur.c,ll.c,lr.c) ; \ bout4[4*k+3].c = BOUT_13(ul.c,ur.c,ll.c,lr.c) ; \ bout4[4*k+4].c = BOUT_23(ul.c,ur.c,ll.c,lr.c) ; \ bout4[4*k+5].c = BOUT_33(ul.c,ur.c,ll.c,lr.c) ; } /** do the above for all 3 colors */ #define FOUR_RGB(k,ul,ur,ll,lr) { FOUR_ROWS(k,r,ul,ur,ll,lr) ; \ FOUR_ROWS(k,g,ul,ur,ll,lr) ; \ FOUR_ROWS(k,b,ul,ur,ll,lr) ; } bin1 = bin ; /* 2 input rows */ bin2 = bin+nx ; bout1 = bout+2*nxup ; /* 4 output rows */ bout2 = bout1+nxup ; bout3 = bout2+nxup ; bout4 = bout3+nxup ; for( jj=0 ; jj < ny-1 ; jj++ ){ /* loop over input rows */ for( ii=0 ; ii < nx-1 ; ii++ ){ FOUR_RGB(ii,bin1[ii],bin1[ii+1],bin2[ii],bin2[ii+1]) ; } /* at this point, output rows have elements [2..4*nx-3] filled; now copy [2] into [0..1] and [4*nx-3] into [4*nx-2..4*nx-1] */ bout1[0] = bout1[1] = bout1[2] ; bout2[0] = bout2[1] = bout2[2] ; bout3[0] = bout3[1] = bout3[2] ; bout4[0] = bout4[1] = bout4[2] ; bout1[nxup-2] = bout1[nxup-1] = bout1[nxup-2] ; bout2[nxup-2] = bout2[nxup-1] = bout2[nxup-2] ; bout3[nxup-2] = bout3[nxup-1] = bout3[nxup-2] ; bout4[nxup-2] = bout4[nxup-1] = bout4[nxup-2] ; /* advance input and output rows */ bin1 = bin2; bin2 += nx ; bout1 = bout4+nxup; bout2 = bout1+nxup; bout3 = bout2+nxup; bout4 = bout3+nxup; } /* copy row 2 into rows 0 and row 1 */ bout1 = bout ; bout2 = bout1+nxup ; bout3 = bout2+nxup ; for( ii=0 ; ii < nxup ; ii++ ) bout1[ii] = bout2[ii] = bout3[ii] ; /* copy rown nyup-3 into rows nyup-2 and nyup-1 */ bout1 = bout + (nyup-3)*nxup ; bout2 = bout1+nxup ; bout3 = bout2+nxup ; for( ii=0 ; ii < nxup ; ii++ ) bout2[ii] = bout3[ii] = bout1[ii] ; MRI_COPY_AUX(outim,inim) ; RETURN(outim) ; } /*************************************************************************/ static MRI_IMAGE * mri_dup2D_rgb3( MRI_IMAGE *inim ) { rgbyte *bin , *bout , *bin1,*bin2 , *bout1,*bout2,*bout3 ; MRI_IMAGE *outim ; int ii,jj , nx,ny , nxup,nyup ; ENTRY("mri_dup2D_rgb3") ; if( inim == NULL || inim->kind != MRI_rgb ) RETURN(NULL) ; bin = (rgbyte *) MRI_RGB_PTR(inim); if( bin == NULL ) RETURN(NULL); /* make output image **/ nx = inim->nx ; ny = inim->ny ; nxup = 3*nx ; nyup = 3*ny ; outim = mri_new( nxup , nyup , MRI_rgb ) ; bout = (rgbyte *) MRI_RGB_PTR(outim) ; /** macros for the 9 different interpolations between the four corners: ul ur > 00 10 20 >=> 01 11 21 ll lr > 02 12 22 **/ #define COUT_00(ul,ur,ll,lr) ( ul ) #define COUT_10(ul,ur,ll,lr) ((171*ul + 85*ur ) >> 8) #define COUT_20(ul,ur,ll,lr) (( 85*ul +171*ur ) >> 8) #define COUT_01(ul,ur,ll,lr) ((171*ul + 85*ll ) >> 8) #define COUT_11(ul,ur,ll,lr) ((114*ul + 57*ur + 57*ll + 28*lr) >> 8) #define COUT_21(ul,ur,ll,lr) (( 57*ul +114*ur + 28*ll + 57*lr) >> 8) #define COUT_02(ul,ur,ll,lr) (( 85*ul + 171*ll ) >> 8) #define COUT_12(ul,ur,ll,lr) (( 57*ul + 28*ur +114*ll + 57*lr) >> 8) #define COUT_22(ul,ur,ll,lr) (( 28*ul + 57*ur + 57*ll +114*lr) >> 8) /** do 9 interpolations between ul ur ll lr for index #k, color #c **/ #define THREE_ROWS(k,c,ul,ur,ll,lr) \ { bout1[3*k+1].c = COUT_00(ul.c,ur.c,ll.c,lr.c) ; \ bout1[3*k+2].c = COUT_10(ul.c,ur.c,ll.c,lr.c) ; \ bout1[3*k+3].c = COUT_20(ul.c,ur.c,ll.c,lr.c) ; \ bout2[3*k+1].c = COUT_01(ul.c,ur.c,ll.c,lr.c) ; \ bout2[3*k+2].c = COUT_11(ul.c,ur.c,ll.c,lr.c) ; \ bout2[3*k+3].c = COUT_21(ul.c,ur.c,ll.c,lr.c) ; \ bout3[3*k+1].c = COUT_02(ul.c,ur.c,ll.c,lr.c) ; \ bout3[3*k+2].c = COUT_12(ul.c,ur.c,ll.c,lr.c) ; \ bout3[3*k+3].c = COUT_22(ul.c,ur.c,ll.c,lr.c) ; } /** do the above for all 3 colors **/ #define THREE_RGB(k,ul,ur,ll,lr) { THREE_ROWS(k,r,ul,ur,ll,lr) ; \ THREE_ROWS(k,g,ul,ur,ll,lr) ; \ THREE_ROWS(k,b,ul,ur,ll,lr) ; } bin1 = bin ; bin2 = bin+nx ; /* 2 input rows */ bout1 = bout +nxup; bout2 = bout1+nxup; /* 3 output rows */ bout3 = bout2+nxup; for( jj=0 ; jj < ny-1 ; jj++ ){ /* loop over input rows */ for( ii=0 ; ii < nx-1 ; ii++ ){ THREE_RGB(ii,bin1[ii],bin1[ii+1],bin2[ii],bin2[ii+1]) ; } /* here, ii=nx-1; can't use ii+1 */ /* do the 3*ii+1 output only, */ /* and copy into 3*ii+2 column */ bout1[3*ii+1].r = COUT_00(bin1[ii].r,0,bin2[ii].r,0) ; bout2[3*ii+1].r = COUT_01(bin1[ii].r,0,bin2[ii].r,0) ; bout3[3*ii+1].r = COUT_02(bin1[ii].r,0,bin2[ii].r,0) ; bout1[3*ii+1].g = COUT_00(bin1[ii].g,0,bin2[ii].g,0) ; bout2[3*ii+1].g = COUT_01(bin1[ii].g,0,bin2[ii].g,0) ; bout3[3*ii+1].g = COUT_02(bin1[ii].g,0,bin2[ii].g,0) ; bout1[3*ii+1].b = COUT_00(bin1[ii].b,0,bin2[ii].b,0) ; bout2[3*ii+1].b = COUT_01(bin1[ii].b,0,bin2[ii].b,0) ; bout3[3*ii+1].b = COUT_02(bin1[ii].b,0,bin2[ii].b,0) ; bout1[3*ii+2] = bout1[3*ii+1] ; bout2[3*ii+2] = bout2[3*ii+1] ; bout3[3*ii+2] = bout3[3*ii+1] ; /* also copy [0] column output from column [1] */ bout1[0] = bout1[1] ; bout2[0] = bout2[1] ; bout3[0] = bout3[1] ; /* advance input and output rows */ bin1 = bin2; bin2 += nx ; bout1 = bout3+nxup; bout2 = bout1+nxup; bout3 = bout2+nxup; } /* here, jj=ny-1, so can't use jj+1 (bin2) */ /* do the bout1 output row only, copy into bout2 */ for( ii=0 ; ii < nx-1 ; ii++ ){ bout1[3*ii+1].r = COUT_00(bin1[ii].r,bin1[ii+1].r,0,0) ; bout1[3*ii+2].r = COUT_10(bin1[ii].r,bin1[ii+1].r,0,0) ; bout1[3*ii+3].r = COUT_20(bin1[ii].r,bin1[ii+1].r,0,0) ; bout1[3*ii+1].g = COUT_00(bin1[ii].g,bin1[ii+1].g,0,0) ; bout1[3*ii+2].g = COUT_10(bin1[ii].g,bin1[ii+1].g,0,0) ; bout1[3*ii+3].g = COUT_20(bin1[ii].g,bin1[ii+1].g,0,0) ; bout1[3*ii+1].b = COUT_00(bin1[ii].b,bin1[ii+1].b,0,0) ; bout1[3*ii+2].b = COUT_10(bin1[ii].b,bin1[ii+1].b,0,0) ; bout1[3*ii+3].b = COUT_20(bin1[ii].b,bin1[ii+1].b,0,0) ; bout2[3*ii+1] = bout1[3*ii+1] ; bout2[3*ii+2] = bout1[3*ii+2] ; bout2[3*ii+3] = bout1[3*ii+3] ; } /* do bottom corners */ bout1[0] = bout2[0] = bout2[1] = bout1[1] ; bout1[nxup-2] = bout1[nxup-1] = bout2[nxup-2] = bout2[nxup-1] = bout1[nxup-3] ; /* do first row of output as well */ bout3 = bout+nxup ; for( ii=0 ; ii < nxup ; ii++ ) bout[ii] = bout3[ii] ; MRI_COPY_AUX(outim,inim) ; RETURN(outim) ; } /*************************************************************************/ /*************************************************************************/ static MRI_IMAGE * mri_dup2D_rgb2( MRI_IMAGE *inim ) { rgbyte *bin , *bout , *bin1,*bin2 , *bout1,*bout2 ; MRI_IMAGE *outim ; int ii,jj , nx,ny , nxup,nyup ; ENTRY("mri_dup2D_rgb2") ; if( inim == NULL || inim->kind != MRI_rgb ) RETURN(NULL) ; bin = (rgbyte *) MRI_RGB_PTR(inim); if( bin == NULL ) RETURN(NULL); /* make output image **/ nx = inim->nx ; ny = inim->ny ; nxup = 2*nx ; nyup = 2*ny ; outim = mri_new( nxup , nyup , MRI_rgb ) ; bout = (rgbyte *) MRI_RGB_PTR(outim) ; /** macros for the 4 different interpolations between the four corners: ul ur >=> 00 10 ll lr >=> 01 11 **/ #define DOUT(ul,ur,ll,lr,a,b,c,d) ((a*ul+b*ur+c*ll+d*lr) >> 4) #define DOUT_00(ul,ur,ll,lr) DOUT(ul,ur,ll,lr,9,3,3,1) #define DOUT_10(ul,ur,ll,lr) DOUT(ul,ur,ll,lr,3,9,1,3) #define DOUT_01(ul,ur,ll,lr) DOUT(ul,ur,ll,lr,3,1,9,3) #define DOUT_11(ul,ur,ll,lr) DOUT(ul,ur,ll,lr,1,3,3,9) /** do r interpolations between ul ur ll lr for index #k, color #c **/ #define TWO_ROWS(k,c,ul,ur,ll,lr) \ { bout1[2*k+1].c = DOUT_00(ul.c,ur.c,ll.c,lr.c) ; \ bout1[2*k+2].c = DOUT_10(ul.c,ur.c,ll.c,lr.c) ; \ bout2[2*k+1].c = DOUT_01(ul.c,ur.c,ll.c,lr.c) ; \ bout2[2*k+2].c = DOUT_11(ul.c,ur.c,ll.c,lr.c) ; } /** do the above for all 3 colors */ #define TWO_RGB(k,ul,ur,ll,lr) { TWO_ROWS(k,r,ul,ur,ll,lr) ; \ TWO_ROWS(k,g,ul,ur,ll,lr) ; \ TWO_ROWS(k,b,ul,ur,ll,lr) ; } bin1 = bin ; /* 2 input rows */ bin2 = bin+nx ; bout1 = bout +nxup ; /* 2 output rows */ bout2 = bout1+nxup ; for( jj=0 ; jj < ny-1 ; jj++ ){ /* loop over input rows */ for( ii=0 ; ii < nx-1 ; ii++ ){ TWO_RGB(ii,bin1[ii],bin1[ii+1],bin2[ii],bin2[ii+1]) ; } /* at this point, output rows have elements [1..2*nx-2] filled; now copy [1] into [0] and [2*nx-2] into [2*nx-1] */ bout1[0] = bout1[1] ; bout2[0] = bout2[1] ; bout1[nxup-1] = bout1[nxup-2] ; bout2[nxup-1] = bout2[nxup-2] ; /* advance input and output rows */ bin1 = bin2; bin2 += nx ; bout1 = bout2+nxup; bout2 = bout1+nxup; } /* copy row 1 into row 0 */ bout1 = bout ; bout2 = bout1+nxup ; for( ii=0 ; ii < nxup ; ii++ ) bout1[ii] = bout2[ii] ; /* copy rown nyup-2 into row nyup-1 */ bout1 = bout + (nyup-2)*nxup ; bout2 = bout1+nxup ; for( ii=0 ; ii < nxup ; ii++ ) bout2[ii] = bout1[ii] ; MRI_COPY_AUX(outim,inim) ; RETURN(outim) ; }