Scanbox Searches for a Population

In some instances, people need to image the same population of neurons across days.   It can be easy to go back to approximately the same position, but finding the best alignment can be time consuming.

Now Scanbox provides a plugin that searches for the optimal location and automatically moves the microscope to the estimated position, and the entire process takes ~2 min.

Here is an example of how to do this:

In this demo, I first accumulate a few frames and take a snapshot that is stored as a reference image.  This is the population we will want to return to.

Then, I image the same area again but move the microsocope in (x,y) and also depth. This simulates returning to roughly the same location in a subsequent day.

Once we are in roughly the same location, we can enable the “searchref” plug-in and allow it to run while focusing.

As we start imaging again, the plugin will request the name of the file with the reference image we want to align.  I selected the one I had created earlier.

A z-stack starts automatically and the plugin displays in real-time a fused image with the reference image in red and the incoming images from the z-stack in green.

Once the z-stack is complete, the plugin computes the optimal (x,y,z) translation and moves the scope to best align the images.

Here is the searchref.m plug-in code:

% Searches for a reference image

global refimg fnum

if(flag) % first call? Format chA/chB according to lines/columns in data
    
    scanbox_config;
    
    sb = udp('localhost','RemotePort',7000);  % local connection to Scanbox
    fopen(sb);
    
    mmfile.Format = {'int16' [1 16] 'header' ; ...
        'uint16' double([mmfile.Data.header(2) mmfile.Data.header(3)]) 'chA' ; ...
        'uint16' double([mmfile.Data.header(2) mmfile.Data.header(3)]) 'chB'};
    mchA = double(intmax('uint16')-mmfile.Data.chA);
    
    % setup fig
    
    pickref([],[]); % select reference image
    
    close all
    f = figure(1);
    f.MenuBar = 'none';
    f.NumberTitle = 'off';
    f.Name = 'Search Display';
    figure(f);
    
    C = imfuse(refimg,mchA,'falsecolor','ColorChannels',[1 2 0]);
    h = imshow(C);
    ttl = title('');
    
    zrange  = sbconfig.plugin_param.searchref.zrange;
    zdelta  = sbconfig.plugin_param.searchref.zdelta;
    nframes = sbconfig.plugin_param.searchref.nframes;
    
    zpos = round(zrange:-zdelta:-zrange);
    idx = 0;
    midx = length(zpos);
    acc = zeros([size(mchA) midx]);
    
    fprintf(sb,'Ks'); % set knobby in superfine mode
    pause(0.5);
    fprintf(sb,sprintf('PZ%d',zrange)); % move to start zstack
    pause(1);
    
    flag = 0;
    newblock = true;
    done = false;
    k = 1;
    
else
    
    if ~done
        %%[idx k newblock fnum]
        
        mchA = double(intmax('uint16')-mmfile.Data.chA);
        
        if idx<=midx
            if newblock
                idx = idx + 1;
                k = 1;
                acc(:,:,idx) = mchA;
                newblock = false;
                ttl.String = sprintf('z-stack: slice %d of %d (red = reference image)',idx,midx);
            else
                acc(:,:,idx) = acc(:,:,idx) + mchA;    % accumulate
                k = k + 1;
                newblock = (k>=nframes);
                if newblock
                    C = imfuse(refimg,squeeze(acc(:,:,idx)),'falsecolor','ColorChannels',[1 2 0]);
                    h.CData = C;
                    fprintf(sb,sprintf('PZ-%d',zdelta)); % move down by delta
                    pause(0.2);
                end
            end
        else
            pause(.5);
            fprintf(sb,sprintf('PZ%d',zrange+zdelta)); % move back to center
            pause(1);
            
            % compute optimal translation
            cc = zeros(1,midx);
            u = zeros(1,midx);
            v = zeros(1,midx);
            for i = 1:midx
                [u(i),v(i),cc(i)] = search_fftalign(refimg,squeeze(acc(:,:,i)));
            end
            
            [mcc,q] = max(cc);
            fprintf(sb,sprintf('PZ%d',zpos(q))); % move to optimal location
            fprintf(sb,sprintf('Pa%d',-u(q)));
            fprintf(sb,sprintf('Pb%d',-v(q)));
            done = true;
            
            %         fprintf(sb,'S');      % stop sampling...
            %         fprintf(sb,'I0');     % disable plugins
            
        end
    else
        % just display result...
        ttl.String = 'Optimal alignment';
        mchA = double(intmax('uint16')-mmfile.Data.chA);
        C = imfuse(refimg,mchA,'falsecolor','ColorChannels',[1 2 0]);
        h.CData = C;        
    end
end

drawnow;

You will also need this search_fftalign.m file:

function [u,v,mc] = search_fftalign(A,B)

N = min(size(A))-80;    % leave out margin

yidx = round(size(A,1)/2)-N/2 + 1 : round(size(A,1)/2)+ N/2;
xidx = round(size(A,2)/2)-N/2 + 1 : round(size(A,2)/2)+ N/2;

A = A(yidx,xidx);
B = B(yidx,xidx);

C = fftshift(real(ifft2(fft2(A).*fft2(rot90(B,2)))));
[mc,i] = max(C(:));
[ii jj] = ind2sub(size(C),i);

u = N/2-ii;
v = N/2-jj;

Ba = circshift(B,-[u,v]);
mc = corrcoef(A(:),Ba(:));
mc = mc(1,2);

Place them both in the scanbox/mmap folder and define the ‘searchref’ plugin option in the sbconfig.plugin configuration variable.