Code covered by the BSD License  

Highlights from
HybridVel

image thumbnail

HybridVel

by

 

30 May 2013 (Updated )

Improved blood velocity measurements with a hybrid image filtering and iterative Radon transform

hybridvel(inputimg,showimg,saveimg,delx,delt,hi,lineskip,xrange)
function [angle,utheta,uvar] = hybridvel(inputimg,showimg,saveimg,delx,delt,hi,lineskip,xrange)

% Blood velocity measurement on linescan images based on the paper titled:
% Improved blood velocity measurements with a hybrid image filtering and 
% iterative Radon transform algorithm
% published in:
% Frontiers in Brain Imaging Methods / Frontiers in Neuroscience
% 
% Syntax:
% [angle,utheta,uvar] = hybridvel(inputimg,showimg,saveimg,delx,delt,hi,lineskip,xrange)
% 
% Where,
% inputimg = linescan/space-time image with space in X-axis and time in Y-axis
% showimg = display image comparing the effect of elementwise demeaning,
%   vertical demeaning and 3x3 vertical Sobel filtering
% saveimg = save image in various formats (.fig,.jpg,.eps,.ai)
% delx = DeltaX, microns/pixel
% delt = DeltaT, ms/line
% hi = height of image segment to be processed in pixels
% lineskip = number of lines before next image segment starts
% xrange = 2-element vector specifying range of pixels in space-dimension
%   to use in the image segment
% 
% Outputs:
% angle: [angle(deg), minstep(deg), location(pixel), dels1(deg), deln(deg), %dv/v, iter, irl, speed (mm/s)]
% utheta: angles used to process the image segments
% uvar: variance on Radon transform at each angle at each image segment
% 
% Example:
% The linescan image used in the Figure 9 of the paper named 'fig9im.tif'
% is located in the same folder as this code. This image can be used as:
% [angle,utheta,uvar] = hybridvel(imread('fig9im.tif'),1,[],0.47,1,100,25,[1 125]);
% 
% by Pratik Chhatbar, Kara Lab @ MUSC Neurosciences
% Charleston, SC. 5/29/2013
% chhatbar@musc.edu
% pratikchhatbar@gmail.com

%% Initialize

imsize = size(inputimg);
inputimg = double(inputimg);
anglineth = 3; 
dvov = 0.1/100; % dv/v to determine minimum step-size
firstthetastep = 45; thetarange = [0 179];
ds = 4; % 4 um streak distance

if exist('showimg','var') && ~isempty(showimg) && showimg, showimg = 1; else showimg = 0; end
if exist('saveimg','var') && ~isempty(saveimg) && saveimg, saveimg = 1; showimg = 1; else saveimg = 0; end
if exist('delx','var') && ~isempty(delx) && delx, else delx = 1; end
if exist('delt','var') && ~isempty(delt) && delt, else delt = 1; end
if exist('hi','var') && ~isempty(hi) && hi, else hi = imsize(1)-2; end
if exist('lineskip','var') && ~isempty(lineskip) && lineskip, else lineskip = hi; end
if exist('xrange','var') && ~isempty(xrange) && length(xrange)<3
    if length(xrange)==1
        wi = xrange; xrange = [1 wi];
    else
        if xrange(1)>imsize(2)-1
            xrange(1)=1;
        end
        if xrange(2)>imsize(2)-1
            xrange(2)=imsize(2)-2;
        end
        if xrange(2)<xrange(1)
            xrange = [xrange(1) xrange(2)];
        end
        wi = xrange(2)-xrange(1)+1;
    end
else
    wi = imsize(2)-2; xrange = [1 wi];
end

if showimg
    imgtitle = {inputname(1);['HybridVel-' datestr(now,30)]};
end

%% Process the image with different filters

curimtitle = {'edm','vdm','sob'}; curcolor = {'b','g','k','r','c','m'};
imgseg(:,:,1) = inputimg(2:end-1,2:end-1)-mean(mean(inputimg(2:end-1,2:end-1))); % element-wise demean
imgseg(:,:,2) = bsxfun(@minus,inputimg(2:end-1,2:end-1),...
    mean(inputimg(2:end-1,2:end-1),1)); % vertical demean
imgseg(:,:,3) = filter2([1 2 1; 0 0 0; -1 -2 -1],inputimg,'valid');  % 3x3 vertical Sobel filter, Eq. 5,6

imgsegsz = size(imgseg);
firstiter = (thetarange(1):firstthetastep:thetarange(2));
firstiter = firstiter-(firstiter(end)-firstiter(1))/2+1;

segend = hi:lineskip:imgsegsz(1);
segstart = segend-hi+1;
segn = length(segstart);

angle = nan(segn,9,imgsegsz(3)); % angle = [angle,minstep,loc(pix),dels1,deln,%dv/v,iter,irl,speed(mm/s)]
utheta = cell(segn,imgsegsz(3)); 
uvar = cell(segn,imgsegsz(3));

%% Iterative Radon transform

for ii = 1:imgsegsz(3)
    for jj = 1:segn
        irl = 1; % iterative radon level
        curangle = 0; alltheta = []; allvar = []; iter = 0; thetastep = firstthetastep; curvarmax = 0;
        curimgseg = imgseg(segstart(jj):segend(jj),xrange(1):xrange(2),ii);
        if ii==1
            curimgseg = curimgseg-mean(curimgseg(:)); % element-wise demean
        end
        if ii==2
            curimgseg = bsxfun(@minus,curimgseg,mean(curimgseg,1)); % vertical demean
        end
       while irl
            iter = iter+1;
            % smart iterative radon function with graded angle steps
            if iter==1
                theta = firstiter;
            else
                thetastep = thetastep/2;
                theta = (-3*thetastep+curangle):thetastep*2:(3*thetastep+curangle);
            end
            theta = mod(theta+90,180)-90; % ensures angle range of [-90,+90)
            R = radon(curimgseg,theta); % Eq. 7
            R(R==0) = nan; % avoids influence of non-participant pixels
            curvar = nanvar(R);
            alltheta = [alltheta theta];
            allvar = [allvar curvar];
            [Rvarmaxval,Rvarmaxin] = max(curvar);
            if Rvarmaxval>curvarmax
                curangle = theta(Rvarmaxin); % Eq. 8
                curvarmax = Rvarmaxval;
            end
            if irl==1 && thetastep<1 % angle resolution less than 1 deg
                irl=2; % iterative radon level 2, where step-size is decided for given dv/v
                curmpa = abs(atand((dvov+1)*tand(curangle))-curangle); % Eq. 17
                ws = min(wi,ceil(hi*abs(tand(curangle)))); % Eq. 14
                hs = min(hi,ceil(wi*abs(cotd(curangle)))); % Eq. 14
                ns = floor(wi*delx/ds)*(hs==hi)+((hi*delx*ws)/(ds*hs))*(ws==wi); % Eq. 13
                dels1 = abs(atand(ws/hs)-atand((ws-1)/hs)*(ws>hs)-atand(ws/(hs-1))*(ws<=hs)); % Eq. 12
                deln = dels1/ns; % Eq. 11
                
            end
            if irl>1 && thetastep<deln % Eq. 11
                ws = min(wi,ceil(hi*abs(tand(curangle)))); % Eq. 14
                hs = min(hi,ceil(wi*abs(cotd(curangle)))); % Eq. 14
                ns = floor(wi*delx/ds)*(hs==hi)+((hi*delx*ws)/(ds*hs))*(ws==wi); % Eq. 13
                dels1 = abs(atand(ws/hs)-atand((ws-1)/hs)*(ws>hs)-atand(ws/(hs-1))*(ws<=hs)); % Eq. 12
                deln = dels1/ns; % Eq. 11
                if thetastep<deln
                    break
                end
            end
                
            if irl>1 && thetastep<curmpa % Eq. 17
                % actual dv/v calculation
                actdvovper = abs(tand(thetastep+curangle)/tand(curangle)-1)*100; % Eq. 16
                if dvov>actdvovper/100
                    break
                else
                    irl = irl+1;
                    curmpa = atand((dvov+1)*tand(abs(curangle)))-abs(curangle); % Eq. 17
                end
            end
        end
        angle(jj,1,ii) = curangle;

        % actual dv/v 
        actdvovper = abs(tand(thetastep+curangle)/tand(curangle)-1)*100; % Eq. 16
        % deln
        ws = min(wi,ceil(hi*abs(tand(curangle)))); % Eq. 14
        hs = min(hi,ceil(wi*abs(cotd(curangle)))); % Eq. 14
        ns = floor(wi*delx/ds)*(hs==hi)+((hi*delx*ws)/(ds*hs))*(ws==wi); % Eq. 13
        dels1 = abs(atand(ws/hs)-atand((ws-1)/hs)*(ws>hs)-atand(ws/(hs-1))*(ws<=hs)); % Eq. 12
        deln = dels1/ns; % Eq. 11

        angle(jj,2:9,ii) = [thetastep segstart(jj)+hi/2 dels1 deln actdvovper iter irl tand(curangle)*delx/delt];

        % unique angles used for radon and variance measured
        [utheta{jj,ii},um] = sort(alltheta);
        uvar{jj,ii} = allvar(um);
    end
    if showimg
        figure(1496);

        % linescan plot with angle
        subplot(1,imgsegsz(3)*2,ii+imgsegsz(3));
        imagesc(imgseg(:,:,ii)); axis image; title(curimtitle{ii});
        set(gca,'XTickLabel',[],'YTickLabel',[]);
        hold on;
        for jj=1:segn
        [xp,yp] = pol2cart(mod(angle(jj,1,ii)*pi/180-pi/2,pi),wi/2);
        line(xrange(1)+wi/2+[-xp xp],angle(jj,3,ii)-[-yp yp],'Color','black','LineWidth',anglineth,'EraseMode','xor');
        end
        hold off;
        if ii==1
            ylabel({'processed image';...
                ['\Deltax = ' num2str(delx) ' \mum/pixel' ', \Deltat = ' num2str(delt) ...
                ' ms/line, h = ' num2str(imgsegsz(1)) ' pixels']});
            xlabel(['w = ' num2str(imgsegsz(2))]);
        end
        
        % angle plot
        subplot(2,imgsegsz(3)*2,+(1:imgsegsz(3)))
        plot(angle(:,3,ii)*delt,angle(:,1,ii),['-o' curcolor{ii} ]); hold on;
        if ii==imgsegsz(3)
            legend(curimtitle{1:ii}); 
            xlabel('time (ms)'); ylabel('\theta (^o)'); hold off
            title (imgtitle);
        end
            
        % velocity plot
        subplot(2,imgsegsz(3)*2,imgsegsz(3)*2+(1:imgsegsz(3)))
        plot(angle(:,3,ii)*delt,angle(:,9,ii),['-o' curcolor{ii} ]); hold on;
        if ii==imgsegsz(3)
            legend(curimtitle{1:ii}); 
            xlabel('time (ms)'); ylabel('v (mm/s)'); hold off
        end
        
        if saveimg && ii==imgsegsz(3)
            savepath = 'D:\lab stuff\savedRadonImages\';
            saveas(gca,fullfile(savepath,['hybridvel' strcat(imgtitle{:}) 'img' num2str(ii) '.eps']), 'psc2');
            saveas(gca,fullfile(savepath,['hybridvel' strcat(imgtitle{:}) 'img' num2str(ii) '.fig']));
            saveas(gca,fullfile(savepath,['hybridvel' strcat(imgtitle{:}) 'img' num2str(ii) '.jpg']));
            saveas(gca,fullfile(savepath,['hybridvel' strcat(imgtitle{:}) 'img' num2str(ii) '.ai']));
        end
    end    
end

Contact us