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.