Пример #1
0
def aligner(target_and_frame):
    frameRed = target_and_frame[0]
    frameGreen = target_and_frame[1]
    target_fft = target_and_frame[2]
    usfac = target_and_frame[3]
    return_registered = target_and_frame[4]
    return_error = target_and_frame[5]
    zeromean = target_and_frame[6]
    DEBUG = target_and_frame[7]
    maxoff = target_and_frame[8]
    nthreads = target_and_frame[9]
    use_numpy_fft = target_and_frame[10]

    fft2, ifft2 = fftn, ifftn = fast_ffts.get_ffts(nthreads=1,
                                                   use_numpy_fft=use_numpy_fft)

    frameRed_fft = fft2(frameRed)
    frameGreen_fft = fft2(frameGreen)
    output = dftregistration(target_fft, frameRed_fft, frameGreen_fft, usfac,
                             return_registered, return_error, zeromean, DEBUG,
                             maxoff, nthreads, use_numpy_fft)

    output[-1] = np.abs(ifft2(output[-1]))  #green registered fourier
    output[-2] = np.abs(ifft2(output[-2]))  #red registered fourier
    return (output[-2], output[-1], -output[1], -output[0])
def register_series_parallel(series, target=None, usfac=1, return_registered=True,
        return_error=False, zeromean=False, DEBUG=False, maxoff=None,
        nthreads=1, use_numpy_fft=False):
    """
    Sub-pixel image registration of a series of images (see dftregistration
    for lots of details)

    Parameters
    ----------
    series : np.ndarray, 3d, x by y by frames
    target : np.ndarray.  If none, use the first image from the series
    usfac : int
        upsampling factor; governs accuracy of fit (1/usfac is best accuracy)
    return_registered : bool
        Return the registered image as the last parameter
    return_error : bool
        Does nothing at the moment, but in principle should return the "fit
        error" (it does nothing because I don't know how to compute the "fit
        error")
    zeromean : bool
        Subtract the mean from the images before cross-correlating?  If no, you
        may get a 0,0 offset because the DC levels are strongly correlated.
    maxoff : int
        Maximum allowed offset to measure (setting this helps avoid spurious
        peaks)
    DEBUG : bool
        Test code used during development.  Should DEFINITELY be removed.

    Returns
    -------
    newseries, dx,dy : 3d array, 2d array, 2d array
    """
    if target is None:
        target = series[:,:,0]
    target[np.isnan(target)] = 0
    series[np.isnan(series)] = 0
    
    # import the fft functions
    fft2,ifft2 = fftn,ifftn = fast_ffts.get_ffts(nthreads=1, use_numpy_fft=use_numpy_fft)

    # let's pre-transform just the target
    targetfft = fft2(target)

    list_of_target_and_frames = [(frame, targetfft, usfac, return_registered, 
                                  return_error, zeromean, DEBUG, 
                                  maxoff, nthreads, use_numpy_fft) for frame in list(np.rollaxis(series, 2))]

    pool = mp.Pool(processes=nthreads)
    out = pool.map(aligner, list_of_target_and_frames) # returns image, x, y
    pool.close()

    x_shifts = np.array([o[1] for o in out])
    y_shifts = np.array([o[2] for o in out])

    newseries = np.empty_like(series)
    for i, output in enumerate(out):
        newseries[:,:,i] = output[0]
    
    return newseries, x_shifts, y_shifts
def aligner(target_and_frame):
    frame = target_and_frame[0]
    target_fft = target_and_frame[1]
    usfac = target_and_frame[2]
    return_registered = target_and_frame[3]
    return_error = target_and_frame[4]
    zeromean = target_and_frame[5]
    DEBUG = target_and_frame[6]
    maxoff = target_and_frame[7]
    nthreads = target_and_frame[8]
    use_numpy_fft = target_and_frame[9]

    fft2,ifft2 = fftn,ifftn = fast_ffts.get_ffts(nthreads=1, use_numpy_fft=use_numpy_fft)

    frame_fft = fft2(frame)

    output = dftregistration(target_fft, frame_fft, usfac, return_registered, return_error, 
                             zeromean, DEBUG, maxoff, nthreads, use_numpy_fft)

    output[-1] = np.abs(ifft2(output[-1]))
    return (output[-1], -output[1], -output[0])
Пример #4
0
def aligner(target_and_frame):
    frameRed = target_and_frame[0]
    frameGreen = target_and_frame[1]
    target_fft = target_and_frame[2]
    usfac = target_and_frame[3]
    return_registered = target_and_frame[4]
    return_error = target_and_frame[5]
    zeromean = target_and_frame[6]
    DEBUG = target_and_frame[7]
    maxoff = target_and_frame[8]
    nthreads = target_and_frame[9]
    use_numpy_fft = target_and_frame[10]

    fft2,ifft2 = fftn,ifftn = fast_ffts.get_ffts(nthreads=1, use_numpy_fft=use_numpy_fft)

    frameRed_fft = fft2(frameRed)
    frameGreen_fft = fft2(frameGreen)
    output = dftregistration(target_fft, frameRed_fft, frameGreen_fft, usfac, return_registered, return_error, 
                             zeromean, DEBUG, maxoff, nthreads, use_numpy_fft)

    output[-1] = np.abs(ifft2(output[-1])) #green registered fourier
    output[-2] = np.abs(ifft2(output[-2])) #red registered fourier
    return (output[-2], output[-1], -output[1], -output[0])
def dftregistration(buf1ft,buf2ft,usfac=1, return_registered=False,
        return_error=False, zeromean=True, DEBUG=False, maxoff=None,
        nthreads=1, use_numpy_fft=False):
    """
    translated from matlab:
    http://www.mathworks.com/matlabcentral/fileexchange/18401-efficient-subpixel-image-registration-by-cross-correlation/content/html/efficient_subpixel_registration.html

    Efficient subpixel image registration by crosscorrelation. This code
    gives the same precision as the FFT upsampled cross correlation in a
    small fraction of the computation time and with reduced memory 
    requirements. It obtains an initial estimate of the crosscorrelation peak
    by an FFT and then refines the shift estimation by upsampling the DFT
    only in a small neighborhood of that estimate by means of a 
    matrix-multiply DFT. With this procedure all the image points are used to
    compute the upsampled crosscorrelation.
    Manuel Guizar - Dec 13, 2007

    Portions of this code were taken from code written by Ann M. Kowalczyk 
    and James R. Fienup. 
    J.R. Fienup and A.M. Kowalczyk, "Phase retrieval for a complex-valued 
    object by using a low-resolution image," J. Opt. Soc. Am. A 7, 450-458 
    (1990).

    Citation for this algorithm:
    Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup, 
    "Efficient subpixel image registration algorithms," Opt. Lett. 33, 
    156-158 (2008).

    Inputs
    buf1ft    Fourier transform of reference image, 
           DC in (1,1)   [DO NOT FFTSHIFT]
    buf2ft    Fourier transform of image to register, 
           DC in (1,1) [DO NOT FFTSHIFT]
    usfac     Upsampling factor (integer). Images will be registered to 
           within 1/usfac of a pixel. For example usfac = 20 means the
           images will be registered within 1/20 of a pixel. (default = 1)

    Outputs
    output =  [error,diffphase,net_row_shift,net_col_shift]
    error     Translation invariant normalized RMS error between f and g
    diffphase     Global phase difference between the two images (should be
               zero if images are non-negative).
    net_row_shift net_col_shift   Pixel shifts between images
    Greg      (Optional) Fourier transform of registered version of buf2ft,
           the global phase difference is compensated for.
    """

    # this function is translated from matlab, so I'm just going to pretend
    # it is matlab/pylab
    from numpy import conj,abs,arctan2,sqrt,real,imag,shape,zeros,trunc,ceil,floor,fix
    from numpy.fft import fftshift,ifftshift
    fft2,ifft2 = fftn,ifftn = fast_ffts.get_ffts(nthreads=nthreads, use_numpy_fft=use_numpy_fft)

    # Compute error for no pixel shift
    if usfac == 0:
        raise ValueError("Upsample Factor must be >= 1")
        CCmax = sum(sum(buf1ft * conj(buf2ft))); 
        rfzero = sum(abs(buf1ft)**2);
        rgzero = sum(abs(buf2ft)**2); 
        error = 1.0 - CCmax * conj(CCmax)/(rgzero*rfzero); 
        error = sqrt(abs(error));
        diffphase=arctan2(imag(CCmax),real(CCmax)); 
        output=[error,diffphase];
            
    # Whole-pixel shift - Compute crosscorrelation by an IFFT and locate the
    # peak
    elif usfac == 1:
        [m,n]=shape(buf1ft);
        CC = ifft2(buf1ft * conj(buf2ft));
        if maxoff is None:
            rloc,cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax=CC[rloc,cloc]; 
        else:
            # set the interior of the shifted array to zero
            # (i.e., ignore it)
            CC[maxoff:-maxoff,:] = 0
            CC[:,maxoff:-maxoff] = 0
            rloc,cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax=CC[rloc,cloc]; 
        rfzero = sum(abs(buf1ft)**2)/(m*n);
        rgzero = sum(abs(buf2ft)**2)/(m*n); 
        error = 1.0 - CCmax * conj(CCmax)/(rgzero*rfzero);
        error = sqrt(abs(error));
        diffphase=arctan2(imag(CCmax),real(CCmax)); 
        md2 = fix(m/2); 
        nd2 = fix(n/2);
        if rloc > md2:
            row_shift = rloc - m;
        else:
            row_shift = rloc;

        if cloc > nd2:
            col_shift = cloc - n;
        else:
            col_shift = cloc;
        #output=[error,diffphase,row_shift,col_shift];
        output=[row_shift,col_shift]
        
    # Partial-pixel shift
    else:
        
        if DEBUG: import pylab
        # First upsample by a factor of 2 to obtain initial estimate
        # Embed Fourier data in a 2x larger array
        [m,n]=shape(buf1ft);
        mlarge=m*2;
        nlarge=n*2;
        CClarge=zeros([mlarge,nlarge], dtype='complex');
        #CClarge[m-fix(m/2):m+fix((m-1)/2)+1,n-fix(n/2):n+fix((n-1)/2)+1] = fftshift(buf1ft) * conj(fftshift(buf2ft));
        CClarge[round(mlarge/4.):round(mlarge/4.*3),round(nlarge/4.):round(nlarge/4.*3)] = fftshift(buf1ft) * conj(fftshift(buf2ft));
        # note that matlab uses fix which is trunc... ?
      
        # Compute crosscorrelation and locate the peak 
        CC = ifft2(ifftshift(CClarge)); # Calculate cross-correlation
        if maxoff is None:
            rloc,cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax=CC[rloc,cloc]; 
        else:
            # set the interior of the shifted array to zero
            # (i.e., ignore it)
            CC[maxoff:-maxoff,:] = 0
            CC[:,maxoff:-maxoff] = 0
            rloc,cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax=CC[rloc,cloc]; 

        if DEBUG:
            pylab.figure(1)
            pylab.clf()
            pylab.subplot(131)
            pylab.imshow(real(CC)); pylab.title("Cross-Correlation (upsampled 2x)")
            pylab.subplot(132)
            ups = dftups((buf1ft) * conj((buf2ft)),mlarge,nlarge,2,0,0); pylab.title("dftups upsampled 2x")
            pylab.imshow(real(((ups))))
            pylab.subplot(133)
            pylab.imshow(real(CC)/real(ups)); pylab.title("Ratio upsampled/dftupsampled")
            print "Upsample by 2 peak: ",rloc,cloc," using dft version: ",np.unravel_index(abs(ups).argmax(), ups.shape)
            #print np.unravel_index(ups.argmax(),ups.shape)
        
        # Obtain shift in original pixel grid from the position of the
        # crosscorrelation peak 
        [m,n] = shape(CC); md2 = trunc(m/2); nd2 = trunc(n/2);
        if rloc > md2 :
            row_shift2 = rloc - m;
        else:
            row_shift2 = rloc;
        if cloc > nd2:
            col_shift2 = cloc - n;
        else:
            col_shift2 = cloc;
        row_shift2=row_shift2/2.;
        col_shift2=col_shift2/2.;
        if DEBUG: print "row_shift/col_shift from ups2: ",row_shift2,col_shift2

        # If upsampling > 2, then refine estimate with matrix multiply DFT
        if usfac > 2:
            #%% DFT computation %%%
            # Initial shift estimate in upsampled grid
            zoom_factor=1.5
            if DEBUG: print row_shift2, col_shift2
            row_shift0 = round(row_shift2*usfac)/usfac; 
            col_shift0 = round(col_shift2*usfac)/usfac;     
            dftshift = trunc(ceil(usfac*zoom_factor)/2); #% Center of output array at dftshift+1
            if DEBUG: print 'dftshift,rs,cs,zf:',dftshift, row_shift0, col_shift0, usfac*zoom_factor
            # Matrix multiply DFT around the current shift estimate
            roff = dftshift-row_shift0*usfac
            coff = dftshift-col_shift0*usfac
            upsampled = dftups(
                    (buf2ft * conj(buf1ft)),
                    ceil(usfac*zoom_factor),
                    ceil(usfac*zoom_factor), 
                    usfac, 
                    roff,
                    coff)
            #CC = conj(dftups(buf2ft.*conj(buf1ft),ceil(usfac*1.5),ceil(usfac*1.5),usfac,...
            #    dftshift-row_shift*usfac,dftshift-col_shift*usfac))/(md2*nd2*usfac^2);
            CC = conj(upsampled)/(md2*nd2*usfac**2);
            if DEBUG:
                pylab.figure(2)
                pylab.clf()
                pylab.subplot(221)
                pylab.imshow(abs(upsampled)); pylab.title('upsampled')
                pylab.subplot(222)
                pylab.imshow(abs(CC)); pylab.title('CC upsampled')
                pylab.subplot(223); pylab.imshow(np.abs(np.fft.fftshift(np.fft.ifft2(buf2ft * conj(buf1ft))))); pylab.title('xc')
                yy,xx = np.indices([m*usfac,n*usfac],dtype='float')
                pylab.contour(yy/usfac/2.-0.5+1,xx/usfac/2.-0.5-1, np.abs(dftups((buf2ft*conj(buf1ft)),m*usfac,n*usfac,usfac)))
                pylab.subplot(224); pylab.imshow(np.abs(dftups((buf2ft*conj(buf1ft)),ceil(usfac*zoom_factor),ceil(usfac*zoom_factor),usfac))); pylab.title('unshifted ups')
            # Locate maximum and map back to original pixel grid 
            rloc,cloc = np.unravel_index(abs(CC).argmax(), CC.shape) 
            rloc0,cloc0 = np.unravel_index(abs(CC).argmax(), CC.shape) 
            CCmax = CC[rloc,cloc]
            #[max1,loc1] = CC.max(axis=0), CC.argmax(axis=0)
            #[max2,loc2] = max1.max(),max1.argmax()
            #rloc=loc1[loc2];
            #cloc=loc2;
            #CCmax = CC[rloc,cloc];
            rg00 = dftups(buf1ft * conj(buf1ft),1,1,usfac)/(md2*nd2*usfac**2);
            rf00 = dftups(buf2ft * conj(buf2ft),1,1,usfac)/(md2*nd2*usfac**2);  
            #if DEBUG: print rloc,row_shift,cloc,col_shift,dftshift
            rloc = rloc - dftshift #+ 1 # +1 # questionable/failed hack + 1;
            cloc = cloc - dftshift #+ 1 # -1 # questionable/failed hack - 1;
            #if DEBUG: print rloc,row_shift,cloc,col_shift,dftshift
            row_shift = row_shift0 + rloc/usfac;
            col_shift = col_shift0 + cloc/usfac;    
            #if DEBUG: print rloc/usfac,row_shift,cloc/usfac,col_shift
            if DEBUG: print "Off by: ",(0.25 - float(rloc)/usfac)*usfac , (-0.25 - float(cloc)/usfac)*usfac 
            if DEBUG: print "correction was: ",rloc/usfac, cloc/usfac
            if DEBUG: print "Coordinate went from",row_shift2,col_shift2,"to",row_shift0,col_shift0,"to", row_shift, col_shift
            if DEBUG: print "dftsh - usfac:", dftshift-usfac
            if DEBUG: print  rloc,cloc,row_shift,col_shift,CCmax,dftshift,rloc0,cloc0

        # If upsampling = 2, no additional pixel shift refinement
        else:    
            rg00 = sum(sum( buf1ft * conj(buf1ft) ))/m/n;
            rf00 = sum(sum( buf2ft * conj(buf2ft) ))/m/n;
            row_shift = row_shift2
            col_shift = col_shift2
        error = 1.0 - CCmax * conj(CCmax)/(rg00*rf00);
        error = sqrt(abs(error));
        diffphase=arctan2(imag(CCmax),real(CCmax));
        # If its only one row or column the shift along that dimension has no
        # effect. We set to zero.
        if md2 == 1:
            row_shift = 0;
        if nd2 == 1:
            col_shift = 0;
        #output=[error,diffphase,row_shift,col_shift];
        output=[row_shift,col_shift]

    if return_error:
        # simple estimate of the precision of the fft approach
        output += [1./usfac,1./usfac]

    # Compute registered version of buf2ft
    if (return_registered):
        if (usfac > 0):
            nr,nc=shape(buf2ft);
            Nr = np.fft.ifftshift(np.linspace(-np.fix(nr/2),np.ceil(nr/2)-1,nr))
            Nc = np.fft.ifftshift(np.linspace(-np.fix(nc/2),np.ceil(nc/2)-1,nc))
            [Nc,Nr] = meshgrid(Nc,Nr);
            Greg = buf2ft * exp(1j*2*pi*(-row_shift*Nr/nr-col_shift*Nc/nc));
            Greg = Greg*exp(1j*diffphase);
        elif (usfac == 0):
            Greg = buf2ft*exp(1j*diffphase);
        output.append(Greg)

    return output
def register_images(im1, im2, usfac=1, return_registered=False,
        return_error=False, zeromean=True, DEBUG=False, maxoff=None,
        nthreads=1, use_numpy_fft=False):
    """
    Sub-pixel image registration (see dftregistration for lots of details)

    Parameters
    ----------
    im1 : np.ndarray
    im2 : np.ndarray
        The images to register. 
    usfac : int
        upsampling factor; governs accuracy of fit (1/usfac is best accuracy)
    return_registered : bool
        Return the registered image as the last parameter
    return_error : bool
        Does nothing at the moment, but in principle should return the "fit
        error" (it does nothing because I don't know how to compute the "fit
        error")
    zeromean : bool
        Subtract the mean from the images before cross-correlating?  If no, you
        may get a 0,0 offset because the DC levels are strongly correlated.
    maxoff : int
        Maximum allowed offset to measure (setting this helps avoid spurious
        peaks)
    DEBUG : bool
        Test code used during development.  Should DEFINITELY be removed.

    Returns
    -------
    dx,dy : float,float
        REVERSE of dftregistration order (also, signs flipped) for consistency
        with other routines.
        Measures the amount im2 is offset from im1 (i.e., shift im2 by these #'s
        to match im1)

    """
    if not im1.shape == im2.shape:
        raise ValueError("Images must have same shape.")

    if zeromean:
        im1 = im1 - (im1[im1==im1].mean())
        im2 = im2 - (im2[im2==im2].mean())

    if np.any(np.isnan(im1)):
        im1 = im1.copy()
        im1[im1!=im1] = 0
    if np.any(np.isnan(im2)):
        im2 = im2.copy()
        im2[im2!=im2] = 0

    fft2,ifft2 = fftn,ifftn = fast_ffts.get_ffts(nthreads=nthreads, use_numpy_fft=use_numpy_fft)

    im1fft = fft2(im1)
    im2fft = fft2(im2)

    output = dftregistration(im1fft,im2fft,usfac=usfac,
            return_registered=return_registered, return_error=return_error,
            zeromean=zeromean, DEBUG=DEBUG, maxoff=maxoff)

    output = [-output[1], -output[0], ] + [o for o in output[2:]]

    if return_registered:
        output[-1] = np.abs(np.fft.ifftshift(ifft2(output[-1])))

    return output
def dftregistration(buf1ft,
                    buf2ft,
                    usfac=1,
                    return_registered=False,
                    return_error=False,
                    zeromean=True,
                    DEBUG=False,
                    maxoff=None,
                    nthreads=1,
                    use_numpy_fft=False):
    """
    translated from matlab:
    http://www.mathworks.com/matlabcentral/fileexchange/18401-efficient-subpixel-image-registration-by-cross-correlation/content/html/efficient_subpixel_registration.html

    Efficient subpixel image registration by crosscorrelation. This code
    gives the same precision as the FFT upsampled cross correlation in a
    small fraction of the computation time and with reduced memory 
    requirements. It obtains an initial estimate of the crosscorrelation peak
    by an FFT and then refines the shift estimation by upsampling the DFT
    only in a small neighborhood of that estimate by means of a 
    matrix-multiply DFT. With this procedure all the image points are used to
    compute the upsampled crosscorrelation.
    Manuel Guizar - Dec 13, 2007

    Portions of this code were taken from code written by Ann M. Kowalczyk 
    and James R. Fienup. 
    J.R. Fienup and A.M. Kowalczyk, "Phase retrieval for a complex-valued 
    object by using a low-resolution image," J. Opt. Soc. Am. A 7, 450-458 
    (1990).

    Citation for this algorithm:
    Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup, 
    "Efficient subpixel image registration algorithms," Opt. Lett. 33, 
    156-158 (2008).

    Inputs
    buf1ft    Fourier transform of reference image, 
           DC in (1,1)   [DO NOT FFTSHIFT]
    buf2ft    Fourier transform of image to register, 
           DC in (1,1) [DO NOT FFTSHIFT]
    usfac     Upsampling factor (integer). Images will be registered to 
           within 1/usfac of a pixel. For example usfac = 20 means the
           images will be registered within 1/20 of a pixel. (default = 1)

    Outputs
    output =  [error,diffphase,net_row_shift,net_col_shift]
    error     Translation invariant normalized RMS error between f and g
    diffphase     Global phase difference between the two images (should be
               zero if images are non-negative).
    net_row_shift net_col_shift   Pixel shifts between images
    Greg      (Optional) Fourier transform of registered version of buf2ft,
           the global phase difference is compensated for.
    """

    # this function is translated from matlab, so I'm just going to pretend
    # it is matlab/pylab
    from numpy import conj, abs, arctan2, sqrt, real, imag, shape, zeros, trunc, ceil, floor, fix
    from numpy.fft import fftshift, ifftshift
    fft2, ifft2 = fftn, ifftn = fast_ffts.get_ffts(nthreads=nthreads,
                                                   use_numpy_fft=use_numpy_fft)

    # Compute error for no pixel shift
    if usfac == 0:
        raise ValueError("Upsample Factor must be >= 1")
        CCmax = sum(sum(buf1ft * conj(buf2ft)))
        rfzero = sum(abs(buf1ft)**2)
        rgzero = sum(abs(buf2ft)**2)
        error = 1.0 - CCmax * conj(CCmax) / (rgzero * rfzero)
        error = sqrt(abs(error))
        diffphase = arctan2(imag(CCmax), real(CCmax))
        output = [error, diffphase]

    # Whole-pixel shift - Compute crosscorrelation by an IFFT and locate the
    # peak
    elif usfac == 1:
        [m, n] = shape(buf1ft)
        CC = ifft2(buf1ft * conj(buf2ft))
        if maxoff is None:
            rloc, cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax = CC[rloc, cloc]
        else:
            # set the interior of the shifted array to zero
            # (i.e., ignore it)
            CC[maxoff:-maxoff, :] = 0
            CC[:, maxoff:-maxoff] = 0
            rloc, cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax = CC[rloc, cloc]
        rfzero = sum(abs(buf1ft)**2) / (m * n)
        rgzero = sum(abs(buf2ft)**2) / (m * n)
        error = 1.0 - CCmax * conj(CCmax) / (rgzero * rfzero)
        error = sqrt(abs(error))
        diffphase = arctan2(imag(CCmax), real(CCmax))
        md2 = fix(m / 2)
        nd2 = fix(n / 2)
        if rloc > md2:
            row_shift = rloc - m
        else:
            row_shift = rloc

        if cloc > nd2:
            col_shift = cloc - n
        else:
            col_shift = cloc
        #output=[error,diffphase,row_shift,col_shift];
        output = [row_shift, col_shift]

    # Partial-pixel shift
    else:

        if DEBUG: import pylab
        # First upsample by a factor of 2 to obtain initial estimate
        # Embed Fourier data in a 2x larger array
        [m, n] = shape(buf1ft)
        mlarge = m * 2
        nlarge = n * 2
        CClarge = zeros([mlarge, nlarge], dtype='complex')
        #CClarge[m-fix(m/2):m+fix((m-1)/2)+1,n-fix(n/2):n+fix((n-1)/2)+1] = fftshift(buf1ft) * conj(fftshift(buf2ft));
        CClarge[round(mlarge / 4.):round(mlarge / 4. * 3),
                round(nlarge /
                      4.):round(nlarge / 4. *
                                3)] = fftshift(buf1ft) * conj(fftshift(buf2ft))
        # note that matlab uses fix which is trunc... ?

        # Compute crosscorrelation and locate the peak
        CC = ifft2(ifftshift(CClarge))
        # Calculate cross-correlation
        if maxoff is None:
            rloc, cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax = CC[rloc, cloc]
        else:
            # set the interior of the shifted array to zero
            # (i.e., ignore it)
            CC[maxoff:-maxoff, :] = 0
            CC[:, maxoff:-maxoff] = 0
            rloc, cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax = CC[rloc, cloc]

        if DEBUG:
            pylab.figure(1)
            pylab.clf()
            pylab.subplot(131)
            pylab.imshow(real(CC))
            pylab.title("Cross-Correlation (upsampled 2x)")
            pylab.subplot(132)
            ups = dftups((buf1ft) * conj((buf2ft)), mlarge, nlarge, 2, 0, 0)
            pylab.title("dftups upsampled 2x")
            pylab.imshow(real(((ups))))
            pylab.subplot(133)
            pylab.imshow(real(CC) / real(ups))
            pylab.title("Ratio upsampled/dftupsampled")
            print "Upsample by 2 peak: ", rloc, cloc, " using dft version: ", np.unravel_index(
                abs(ups).argmax(), ups.shape)
            #print np.unravel_index(ups.argmax(),ups.shape)

        # Obtain shift in original pixel grid from the position of the
        # crosscorrelation peak
        [m, n] = shape(CC)
        md2 = trunc(m / 2)
        nd2 = trunc(n / 2)
        if rloc > md2:
            row_shift2 = rloc - m
        else:
            row_shift2 = rloc
        if cloc > nd2:
            col_shift2 = cloc - n
        else:
            col_shift2 = cloc
        row_shift2 = row_shift2 / 2.
        col_shift2 = col_shift2 / 2.
        if DEBUG:
            print "row_shift/col_shift from ups2: ", row_shift2, col_shift2

        # If upsampling > 2, then refine estimate with matrix multiply DFT
        if usfac > 2:
            #%% DFT computation %%%
            # Initial shift estimate in upsampled grid
            zoom_factor = 1.5
            if DEBUG: print row_shift2, col_shift2
            row_shift0 = round(row_shift2 * usfac) / usfac
            col_shift0 = round(col_shift2 * usfac) / usfac
            dftshift = trunc(ceil(usfac * zoom_factor) / 2)
            #% Center of output array at dftshift+1
            if DEBUG:
                print 'dftshift,rs,cs,zf:', dftshift, row_shift0, col_shift0, usfac * zoom_factor
            # Matrix multiply DFT around the current shift estimate
            roff = dftshift - row_shift0 * usfac
            coff = dftshift - col_shift0 * usfac
            upsampled = dftups((buf2ft * conj(buf1ft)),
                               ceil(usfac * zoom_factor),
                               ceil(usfac * zoom_factor), usfac, roff, coff)
            #CC = conj(dftups(buf2ft.*conj(buf1ft),ceil(usfac*1.5),ceil(usfac*1.5),usfac,...
            #    dftshift-row_shift*usfac,dftshift-col_shift*usfac))/(md2*nd2*usfac^2);
            CC = conj(upsampled) / (md2 * nd2 * usfac**2)
            if DEBUG:
                pylab.figure(2)
                pylab.clf()
                pylab.subplot(221)
                pylab.imshow(abs(upsampled))
                pylab.title('upsampled')
                pylab.subplot(222)
                pylab.imshow(abs(CC))
                pylab.title('CC upsampled')
                pylab.subplot(223)
                pylab.imshow(
                    np.abs(np.fft.fftshift(np.fft.ifft2(buf2ft *
                                                        conj(buf1ft)))))
                pylab.title('xc')
                yy, xx = np.indices([m * usfac, n * usfac], dtype='float')
                pylab.contour(
                    yy / usfac / 2. - 0.5 + 1, xx / usfac / 2. - 0.5 - 1,
                    np.abs(
                        dftups((buf2ft * conj(buf1ft)), m * usfac, n * usfac,
                               usfac)))
                pylab.subplot(224)
                pylab.imshow(
                    np.abs(
                        dftups((buf2ft * conj(buf1ft)),
                               ceil(usfac * zoom_factor),
                               ceil(usfac * zoom_factor), usfac)))
                pylab.title('unshifted ups')
            # Locate maximum and map back to original pixel grid
            rloc, cloc = np.unravel_index(abs(CC).argmax(), CC.shape)
            rloc0, cloc0 = np.unravel_index(abs(CC).argmax(), CC.shape)
            CCmax = CC[rloc, cloc]
            #[max1,loc1] = CC.max(axis=0), CC.argmax(axis=0)
            #[max2,loc2] = max1.max(),max1.argmax()
            #rloc=loc1[loc2];
            #cloc=loc2;
            #CCmax = CC[rloc,cloc];
            rg00 = dftups(buf1ft * conj(buf1ft), 1, 1,
                          usfac) / (md2 * nd2 * usfac**2)
            rf00 = dftups(buf2ft * conj(buf2ft), 1, 1,
                          usfac) / (md2 * nd2 * usfac**2)
            #if DEBUG: print rloc,row_shift,cloc,col_shift,dftshift
            rloc = rloc - dftshift  #+ 1 # +1 # questionable/failed hack + 1;
            cloc = cloc - dftshift  #+ 1 # -1 # questionable/failed hack - 1;
            #if DEBUG: print rloc,row_shift,cloc,col_shift,dftshift
            row_shift = row_shift0 + rloc / usfac
            col_shift = col_shift0 + cloc / usfac
            #if DEBUG: print rloc/usfac,row_shift,cloc/usfac,col_shift
            if DEBUG:
                print "Off by: ", (0.25 - float(rloc) / usfac) * usfac, (
                    -0.25 - float(cloc) / usfac) * usfac
            if DEBUG: print "correction was: ", rloc / usfac, cloc / usfac
            if DEBUG:
                print "Coordinate went from", row_shift2, col_shift2, "to", row_shift0, col_shift0, "to", row_shift, col_shift
            if DEBUG: print "dftsh - usfac:", dftshift - usfac
            if DEBUG:
                print rloc, cloc, row_shift, col_shift, CCmax, dftshift, rloc0, cloc0

        # If upsampling = 2, no additional pixel shift refinement
        else:
            rg00 = sum(sum(buf1ft * conj(buf1ft))) / m / n
            rf00 = sum(sum(buf2ft * conj(buf2ft))) / m / n
            row_shift = row_shift2
            col_shift = col_shift2
        error = 1.0 - CCmax * conj(CCmax) / (rg00 * rf00)
        error = sqrt(abs(error))
        diffphase = arctan2(imag(CCmax), real(CCmax))
        # If its only one row or column the shift along that dimension has no
        # effect. We set to zero.
        if md2 == 1:
            row_shift = 0
        if nd2 == 1:
            col_shift = 0
        #output=[error,diffphase,row_shift,col_shift];
        output = [row_shift, col_shift]

    if return_error:
        # simple estimate of the precision of the fft approach
        output += [1. / usfac, 1. / usfac]

    # Compute registered version of buf2ft
    if (return_registered):
        if (usfac > 0):
            nr, nc = shape(buf2ft)
            Nr = np.fft.ifftshift(
                np.linspace(-np.fix(nr / 2),
                            np.ceil(nr / 2) - 1, nr))
            Nc = np.fft.ifftshift(
                np.linspace(-np.fix(nc / 2),
                            np.ceil(nc / 2) - 1, nc))
            [Nc, Nr] = np.meshgrid(Nc, Nr)
            Greg = buf2ft * np.exp(
                1j * 2 * np.pi * (-row_shift * Nr / nr - col_shift * Nc / nc))
            Greg = Greg * np.exp(1j * diffphase)
        elif (usfac == 0):
            Greg = buf2ft * np.exp(1j * diffphase)
        output.append(Greg)

    return output
def register_images(im1,
                    im2,
                    usfac=1,
                    return_registered=False,
                    return_error=False,
                    zeromean=True,
                    DEBUG=False,
                    maxoff=None,
                    nthreads=1,
                    use_numpy_fft=False):
    """
    Sub-pixel image registration (see dftregistration for lots of details)

    Parameters
    ----------
    im1 : np.ndarray
    im2 : np.ndarray
        The images to register. 
    usfac : int
        upsampling factor; governs accuracy of fit (1/usfac is best accuracy)
    return_registered : bool
        Return the registered image as the last parameter
    return_error : bool
        Does nothing at the moment, but in principle should return the "fit
        error" (it does nothing because I don't know how to compute the "fit
        error")
    zeromean : bool
        Subtract the mean from the images before cross-correlating?  If no, you
        may get a 0,0 offset because the DC levels are strongly correlated.
    maxoff : int
        Maximum allowed offset to measure (setting this helps avoid spurious
        peaks)
    DEBUG : bool
        Test code used during development.  Should DEFINITELY be removed.

    Returns
    -------
    dx,dy : float,float
        REVERSE of dftregistration order (also, signs flipped) for consistency
        with other routines.
        Measures the amount im2 is offset from im1 (i.e., shift im2 by these #'s
        to match im1)

    """
    if not im1.shape == im2.shape:
        raise ValueError("Images must have same shape.")

    if zeromean:
        im1 = im1 - (im1[im1 == im1].mean())
        im2 = im2 - (im2[im2 == im2].mean())

    if np.any(np.isnan(im1)):
        im1 = im1.copy()
        im1[im1 != im1] = 0
    if np.any(np.isnan(im2)):
        im2 = im2.copy()
        im2[im2 != im2] = 0

    fft2, ifft2 = fftn, ifftn = fast_ffts.get_ffts(nthreads=nthreads,
                                                   use_numpy_fft=use_numpy_fft)

    im1fft = fft2(im1)
    im2fft = fft2(im2)

    output = dftregistration(im1fft,
                             im2fft,
                             usfac=usfac,
                             return_registered=return_registered,
                             return_error=return_error,
                             zeromean=zeromean,
                             DEBUG=DEBUG,
                             maxoff=maxoff)

    output = [
        -output[1],
        -output[0],
    ] + [o for o in output[2:]]

    if return_registered:
        output[-1] = np.abs(np.fft.ifftshift(ifft2(output[-1])))

    return output
Пример #9
0
def register_series_parallel(seriesRed,
                             seriesGreen,
                             target=None,
                             usfac=1,
                             return_registered=True,
                             return_error=False,
                             zeromean=False,
                             DEBUG=False,
                             maxoff=None,
                             nthreads=1,
                             use_numpy_fft=False):
    """
    Sub-pixel image registration of a series of images (see dftregistration
    for lots of details)

    Parameters
    ----------
    series : np.ndarray, 3d, x by y by frames
    target : np.ndarray.  If none, use the first image from the series
    usfac : int
        upsampling factor; governs accuracy of fit (1/usfac is best accuracy)
    return_registered : bool
        Return the registered image as the last parameter
    return_error : bool
        Does nothing at the moment, but in principle should return the "fit
        error" (it does nothing because I don't know how to compute the "fit
        error")
    zeromean : bool
        Subtract the mean from the images before cross-correlating?  If no, you
        may get a 0,0 offset because the DC levels are strongly correlated.
    maxoff : int
        Maximum allowed offset to measure (setting this helps avoid spurious
        peaks)
    DEBUG : bool
        Test code used during development.  Should DEFINITELY be removed.

    Returns
    -------
    newseries, dx,dy : 3d array, 2d array, 2d array
    """
    if target is None:
        target = series[:, :, 0]
    target[np.isnan(target)] = 0
    seriesRed[np.isnan(seriesRed)] = 0
    seriesGreen[np.isnan(seriesGreen)] = 0

    # import the fft functions
    fft2, ifft2 = fftn, ifftn = fast_ffts.get_ffts(nthreads=1,
                                                   use_numpy_fft=use_numpy_fft)

    # let's pre-transform just the target
    targetfft = fft2(target)

    list_of_target_and_frames = [
        (frameRed, frameGreen, targetfft, usfac, return_registered,
         return_error, zeromean, DEBUG, maxoff, nthreads, use_numpy_fft)
        for frameRed, frameGreen in zip(np.rollaxis(seriesRed, 2),
                                        np.rollaxis(seriesGreen, 2))
    ]

    pool = mp.Pool(processes=nthreads)
    out = pool.map(aligner, list_of_target_and_frames)  # returns image, x, y
    pool.close()

    # redAligned = np.empty_like(seriesRed)
    # for i, output in enumerate(outputs):
    #     redAligned[:,:,i] = output[-2]

    # greenAligned = np.empty_like(seriesGreen)
    # for i, output in enumerate(outputs):
    #     greenAligned[:,:,i] = output[-1]

    # x_shifts = np.array([o[0] for o in outputs])
    # y_shifts = np.array([o[1] for o in outputs])

    # return redAligned, greenAligned, x_shifts, y_shifts

    x_shifts = np.array([o[2] for o in out])
    y_shifts = np.array([o[3] for o in out])

    redAligned = np.empty_like(seriesRed)
    for i, output in enumerate(out):
        redAligned[:, :, i] = output[0]

    greenAligned = np.empty_like(seriesGreen)
    for i, output in enumerate(out):
        greenAligned[:, :, i] = output[1]
    return redAligned, greenAligned, x_shifts, y_shifts
Пример #10
0
def register_series(seriesRed,
                    seriesGreen,
                    target=None,
                    usfac=1,
                    return_registered=True,
                    return_error=False,
                    zeromean=False,
                    DEBUG=False,
                    maxoff=None,
                    nthreads=1,
                    use_numpy_fft=False):
    """
    Sub-pixel image registration of a series of images (see dftregistration
    for lots of details)

    Parameters
    ----------
    series : np.ndarray, 3d, x by y by frames
    target : np.ndarray.  If none, use the first image from the series
    usfac : int
        upsampling factor; governs accuracy of fit (1/usfac is best accuracy)
    return_registered : bool
        Return the registered image as the last parameter
    return_error : bool
        Does nothing at the moment, but in principle should return the "fit
        error" (it does nothing because I don't know how to compute the "fit
        error")
    zeromean : bool
        Subtract the mean from the images before cross-correlating?  If no, you
        may get a 0,0 offset because the DC levels are strongly correlated.
    maxoff : int
        Maximum allowed offset to measure (setting this helps avoid spurious
        peaks)
    DEBUG : bool
        Test code used during development.  Should DEFINITELY be removed.

    Returns
    -------
    dx,dy : float,float
        REVERSE of dftregistration order (also, signs flipped) for consistency
        with other routines.
        Measures the amount im2 is offset from im1 (i.e., shift im2 by these #'s
        to match im1)

    """
    if target is None:
        target = seriesRed[:, :, 0]

    # prepare the target array
    target[np.isnan(target)] = 0

    # prepare the seriesRed and seriesGreen array
    seriesRed[np.isnan(seriesRed)] = 0
    seriesGreen[np.isnan(seriesGreen)] = 0
    # import the fft functions
    fft2, ifft2 = fftn, ifftn = fast_ffts.get_ffts(nthreads=nthreads,
                                                   use_numpy_fft=use_numpy_fft)

    # let's pre-transform everything
    targetfft = fft2(target)

    seriesRedfft = np.empty_like(seriesRed, dtype='complex128')
    for i in range(seriesRed.shape[2]):
        seriesRedfft[:, :, i] = fft2(seriesRed[:, :, i])

    seriesGreenfft = np.empty_like(seriesGreen, dtype='complex128')
    for i in range(seriesGreen.shape[2]):
        seriesGreenfft[:, :, i] = fft2(seriesGreen[:, :, i])

    # loop over seriesRed, using this series for alignment of both red and green channels.
    #make sure red and green sizes are the same. If not, pad.
    outputs = []
    for i in range(seriesRed.shape[2]):
        output = dftregistration(targetfft,
                                 seriesRedfft[:, :, i],
                                 seriesGreenfft[:, :, i],
                                 usfac=usfac,
                                 return_registered=return_registered,
                                 return_error=return_error,
                                 zeromean=zeromean,
                                 DEBUG=DEBUG,
                                 maxoff=maxoff)
        #return a list of outputs for each image.
        #each output in this list contains: [row_shifts, columns_shifts, GregRed, GregGreen]
        outputs.append(output)

    # uh not that clear about this reordering of the outputs, but i do it for all outputs.
    for i, output in enumerate(outputs):
        outputs[i] = [
            -output[1],
            -output[0],
        ] + [o for o in output[2:]]
        if return_registered:
            outputs[i][-1] = np.abs(ifft2(output[-1]))
            outputs[i][-2] = np.abs(ifft2(output[-2]))
    # let's re-arrange the output into a tuple of 3:
    # the new series, the x shifts and the y shifts

    redAligned = np.empty_like(seriesRed)
    for i, output in enumerate(outputs):
        redAligned[:, :, i] = output[-2]

    greenAligned = np.empty_like(seriesGreen)
    for i, output in enumerate(outputs):
        greenAligned[:, :, i] = output[-1]

    x_shifts = np.array([o[0] for o in outputs])
    y_shifts = np.array([o[1] for o in outputs])

    return redAligned, greenAligned, x_shifts, y_shifts
Пример #11
0
def register_series(series, target=None, usfac=1, return_registered=True,
        return_error=False, zeromean=False, DEBUG=False, maxoff=None,
        nthreads=1, use_numpy_fft=False):
    """
    Sub-pixel image registration of a series of images (see dftregistration
    for lots of details)

    Parameters
    ----------
    series : np.ndarray, 3d, x by y by frames
    target : np.ndarray.  If none, use the first image from the series
    usfac : int
        upsampling factor; governs accuracy of fit (1/usfac is best accuracy)
    return_registered : bool
        Return the registered image as the last parameter
    return_error : bool
        Does nothing at the moment, but in principle should return the "fit
        error" (it does nothing because I don't know how to compute the "fit
        error")
    zeromean : bool
        Subtract the mean from the images before cross-correlating?  If no, you
        may get a 0,0 offset because the DC levels are strongly correlated.
    maxoff : int
        Maximum allowed offset to measure (setting this helps avoid spurious
        peaks)
    DEBUG : bool
        Test code used during development.  Should DEFINITELY be removed.

    Returns
    -------
    dx,dy : float,float
        REVERSE of dftregistration order (also, signs flipped) for consistency
        with other routines.
        Measures the amount im2 is offset from im1 (i.e., shift im2 by these #'s
        to match im1)

    """
    if target is None:
        target = series[:,:,0]

    # prepare the target array
    target[np.isnan(target)] = 0

    # prepare the series array
    series[np.isnan(series)] = 0
    
    # import the fft functions
    fft2,ifft2 = fftn,ifftn = fast_ffts.get_ffts(nthreads=nthreads, use_numpy_fft=use_numpy_fft)

    # let's pre-transform everything
    targetfft = fft2(target)
    seriesfft = np.empty_like(series, dtype='complex128')
    for i in range(series.shape[2]):
        seriesfft[:,:,i] = fft2(series[:,:,i])
    
    # loop over series, aligning
    outputs = []
    for i in range(series.shape[2]):
        output = dftregistration(targetfft,seriesfft[:,:,i],usfac=usfac,
                                 return_registered=return_registered, return_error=return_error,
                                 zeromean=zeromean, DEBUG=DEBUG, maxoff=maxoff)
        outputs.append(output)

    # uh not that clear about this reordering of the outputs, but i do it for all outputs.
    for i, output in enumerate(outputs):
        outputs[i] = [-output[1], -output[0], ] + [o for o in output[2:]]
        if return_registered:
            outputs[i][-1] = np.abs(ifft2(output[-1]))

    # let's re-arrange the output into a tuple of 3:
    # the new series, the x shifts and the y shifts

    newseries = np.empty_like(series)
    for i, output in enumerate(outputs):
        newseries[:,:,i] = output[-1]

    x_shifts = np.array([o[0] for o in outputs])
    y_shifts = np.array([o[1] for o in outputs])
        
    return newseries, x_shifts, y_shifts