Skip to content
Snippets Groups Projects
Commit 3ac69118 authored by Hieu LE XUAN's avatar Hieu LE XUAN
Browse files

first version

parent 7f9e6826
No related branches found
No related tags found
No related merge requests found
function IQ_filt = BSRPCA_convergent(S1,H,dx,dz)
%%%% ARGUMENTS %%%%
% S1: Input Volume
% H : The PSF
% dx,dz: super resolution scale
ULM = struct('numberOfParticles', 90,... % Number of particles per frame. (30-100)
'size',[322 128 500],... % size of input data [nb_pixel_z nb_pixel_x nb_frame_per_bloc]
'scale',[1 1 1/1000],...% Scale [z x dt], size of pixel in the scaling unit. (here, pixsize = 1*lambda)
'res',10,... % Resolution factor. Typically 10 for final image rendering at lambda/10.
'SVD_cutoff',[5 500],... % SVD filtering, to be adapted to your clutter/SNR levels
'max_linking_distance',2,... % Maximum linking distance between two frames to reject pairing, in pixels units (UF.scale(1)). (2-4 pixel).
'min_length', 15,... % Minimum allowed length of the tracks in time. (5-20 frames)
'fwhm',[1 1]*3,... % Size [pixel] of the mask for localization. (3x3 for pixel at lambda, 5x5 at lambda/2). [fmwhz fmwhx]
'max_gap_closing', 0,... % Allowed gap in microbubbles' pairing. (if you want to skip frames 0)
'interp_factor',1/10,... % Interpfactor (decimation of tracks)
'LocMethod','radial'... % Select localization algorithm (WA,Interp,Radial,CurveFitting,NoLocalization)
);
ULM.numberOfParticles = 110;
ULM.LocMethod = 'nolocalization';
S = (S1);
[Nz,Nx,Nt] = size(S);
[M,m,n,p] = convert_video3d_to_2d(S);
% unobserved = isnan(M);
% M(unobserved) = 0;
normV = norm(M, 'fro');
%%%
% S is observations with size Nz , Nx , Nt
%%%% M is of size NzNx , Nt
% H is of size NzdzNxdx,Nt %
if (nargin<3)
dz =1;
dx =1;
end
dt = 1;
%%% make H from h %%%
H_volume = repmat(H,[1 1 Nt]);
FB = fft2(H); % 2D
FBC = conj(FB);
F2B = abs(FB).^2;
Nb = dz*dx; % either of this should be 1
nr = Nz; %original size
nc = Nx; % original size
m = nr*nc;
%% %% initialize solutions
x = zeros(Nz*dz*Nx*dx,Nt);
z = zeros(Nz*dz*Nx*dx,Nt); %% ?
T = zeros(Nx*Nz,Nt);
gamma2=zeros(Nx*Nz,Nt); %% ?
y=zeros(Nx*Nz,Nt); %% ?
gamma1=zeros(Nz*dz*Nx*dx,Nt); %% ?
mu = 1e-4; %% effective for T
tol = 1e-4;
Niter = 2;
all_loss = [];
ro = 0.005;
lambda = 0.005; % tang lambda co ve se tang contrast small vessels
tau = 2*0.8; %% skip %%
rang = guessRank(M);
fprintf("rang = %d \n",rang)
lambda/mu
for i=1:Niter
t1 = tic;
%% step 1 %%
t1 = tic;
H_volume = reshape(H_volume,Nz*dz*Nx*dx,Nt);
degraded = H_volume.*x;
degraded = reshape(degraded,Nz*dz,Nx*dx,Nt);
degraded = degraded(1:dz:end,1:dx:end,1:dt:end); %% use default resize strategy
degraded = reshape(degraded,Nz*Nx,Nt);%% resize with bicubic?
y = (M - degraded + ro*T -gamma2)*(1/(1+ro));
t2=toc(t1);
fprintf("\n time for step 1 : %f \n",t2);
t1=tic;
%% step 2
tau = ro/2;
dec = temporal_filtering(M-y,Nz,Nx) ; %%y
dec = reshape(dec,[Nz Nx Nt]);
if (i>=2)
dec2 = temporal_filtering(M-T,Nz,Nx) ;
dec2 = reshape(dec2,[Nz Nx Nt]);
else
dec2 = z-gamma1/ro;
dec2 = reshape(dec2,[Nz*dz Nx*dx Nt]);
end
dec2 = imresize(dec2,[Nz*dz Nx*dx],'lanczos3');
decsize = size(dec);
decrup = decsize(1)*dz;
deccup = decsize(2)*dx;
decsup = decsize(3)*dt;
DTy=zeros(decrup,deccup,decsup);
% decup_im = zeros(decrup,deccup,decsup);
DTy(1:dz:end,1:dx:end,1:dt:end)=dec;
%%% a close guess
decup_im = reshape(dec2,[Nz*dz Nx*dx Nt]);
torch = ro/2;
for fra=1:Nt
x_hat = decup_im(:,:,fra);
FR = fft2(2*torch*x_hat) + FBC.*fft2(DTy(:,:,fra)); %2D
[Xest,FX] = INVLS(FB,FBC,F2B,FR,tau,Nb,nr,nc,m);
x(:,fra) = reshape(Xest,Nz*dz*Nx*dx,[]);
end
x = reshape(x,[Nz*dz*Nx*dx Nt]);
t2=toc(t1);
fprintf("time for step 2 : %f \n",t2);
t1=tic;
% step 3
%% verified
[Ulan,Slan,Vlan] = svdsecon(y+gamma2/ro, 4); % fastest => ignore or not
T = Ulan*Slan*Vlan';
t2=toc(t1);
fprintf("time for step 3 : %f \n",t2);
t1 = tic;
% step 4
z = So(lambda/ro,x+gamma1/ro);
% step 5
gamma2 = gamma2 + ro*(y-T);
% step 6
gamma1 = gamma1+ ro*(x-z);
t2=toc(t1);
fprintf("time for step 4+5+6 : %f \n",t2);
ro = 2*ro;
%% loss %%
H_volume = reshape(H_volume,Nz*dz*Nx*dx,Nt);
degraded = ifft2(H_volume.*fft2(x));
degraded = reshape(degraded,Nz*dz,Nx*dx,Nt);
degraded = degraded(1:dz:end,1:dx:end,1:1:end);
degraded = reshape(degraded,Nz*Nx,Nt);
loss = norm(M-degraded-T,'fro')+lambda*norm(x,1);
loss = loss/normV;
fprintf("loss iter %d = %.5f \n",i,loss)
end
IQ_filt = reshape(x, [Nz*dz Nx*dx Nt]);
end
function IQ_filt = temporal_filtering(IQ_filt,Nz,Nx)
[~,Nt] = size(IQ_filt);
IQ_filt = reshape(IQ_filt,Nz,Nx,Nt);
ULM.ButterCuttofFreq = [50 249];
framerate = 1000;
[but_b,but_a] = butter(2,ULM.ButterCuttofFreq/(framerate/2),'bandpass');
IQ_filt = filter(but_b,but_a,IQ_filt,[],3); %(optional)
IQ_filt(~isfinite(IQ_filt))=0;
IQ_filt = reshape(IQ_filt,Nz*Nx,Nt);
IQ_filt = abs(IQ_filt);
end
%% PALA_InVivoULM_example.m : Post Processing - filtering, localization and tracking for in vivo data
% Simple script to perform ULM on in vivo data
% IQ are loaded, filtered and sent into ULM processing.
% Bubbles are detected, selected, then localized, and paired into tracks.
% The result is a list of interpolated tracks to reconstructed a full brain vascularization.
%
% This code can be easily adapted for any other in vivo datasets.
%
% Created by Arthur Chavignon 25/02/2020
%
% DATE 2020.12.17 - VERSION 1.1
% AUTHORS: Arthur Chavignon, Baptiste Heiles, Vincent Hingot. CNRS, Sorbonne Universite, INSERM.
% Laboratoire d'Imagerie Biomedicale, Team PPM. 15 rue de l'Ecole de Medecine, 75006, Paris
% Code Available under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (see https://creativecommons.org/licenses/by-nc-sa/4.0/)
% ACADEMIC REFERENCES TO BE CITED
% Details of the code in the article by Heiles, Chavignon, Hingot, Lopez, Teston and Couture.
% Performance benchmarking of microbubble-localization algorithms for ultrasound localization microscopy, Nature Biomedical Engineering, 2021.
% General description of super-resolution in: Couture et al., Ultrasound localization microscopy and super-resolution: A state of the art, IEEE UFFC 2018
clear
% DEFINE THE ADDONS DIRECTORY ON YOUR COMPUTER
% cd ./..
% PALA_addons_folder = [cd]; % location of the addons folder
% DEFINE THE DATA DIRECTORY ON YOUR COMPUTER
% addpath(genpath(PALA_addons_folder))
%% Adapt parameters to your data
% A few parameters must be provided by the user depending of your input images (size of pixel, wavelength)
% These parameters will be copied and used later during the creation of the ULM structure.
% in this example, UF.TwFreq = 15MHz, UF.FrameRateUF = 1000Hz;
UF.TwFreq = 14.8;
UF.FrameRateUF = 1000;
% Here you put the size of your data
SizeOfBloc = [160 128 500];
% Here you put the size of pixel in the prefered unit. It can be um, mm, m, wavelength, or an arbitrary scale.
ScaleOfPixel = [1 1]; % [pixel_size_z, pixel_size_x]
% In that example, the size of pixels is lambda x lambda. The localization process will be
% performs in wavelength. For velocity rendering, velocities in [wavelength/s] will be converted in [mm/s].
% The imaging frame rate is required for velocity calculation, and temporal filtering.
framerate = 1000; % imaging framerate in [Hz]
% Number of blocs to process
Nbuffers = 80; % number of bloc to process (used in the parfor)
% If pixel sizes are in wavelength, lambda must be provided for a velocity maps in mm/s,
lambda = 1480/(UF.TwFreq*1e3);
%% ULM parameters
% this script can be run using different scaling, it can be wavelength, pixel size, mm, um.
% In this example, input pixel are isotropic and equal to lambda (pixelPitch_x = pixelPitch_y = lambda)
% All size defined later are expressed in lambda
res = 10; % final ratio of localization rendering, it's approximately resolution factor of localization in scale(1) units.
% for a pixel size of 100um, we can assume that ULM algorithm provides precision 10 (res) times
% smaller than pixel size. Final rendering will be reconstructed on a 10x10um grid.
ULM = struct('numberOfParticles', 90,... % Number of particles per frame. (30-100)
'size',[SizeOfBloc(1) SizeOfBloc(2) SizeOfBloc(3)],... % size of input data [nb_pixel_z nb_pixel_x nb_frame_per_bloc]
'scale',[ScaleOfPixel 1/framerate],...% Scale [z x dt], size of pixel in the scaling unit. (here, pixsize = 1*lambda)
'res',res,... % Resolution factor. Typically 10 for final image rendering at lambda/10.
'SVD_cutoff',[5 SizeOfBloc(3)],... % SVD filtering, to be adapted to your clutter/SNR levels
'max_linking_distance',2,... % Maximum linking distance between two frames to reject pairing, in pixels units (UF.scale(1)). (2-4 pixel).
'min_length', 15,... % Minimum allowed length of the tracks in time. (5-20 frames)
'fwhm',[1 1]*3,... % Size [pixel] of the mask for localization. (3x3 for pixel at lambda, 5x5 at lambda/2). [fmwhz fmwhx]
'max_gap_closing', 0,... % Allowed gap in microbubbles' pairing. (if you want to skip frames 0)
'interp_factor',1/res,... % Interpfactor (decimation of tracks)
'LocMethod','nolocalization'... % Select localization algorithm (WA,Interp,Radial,CurveFitting,NoLocalization)
);
ULM.ButterCuttofFreq = [50 249]; % Cutoff frequency (Hz) for additional filter. Typically [20 300] at 1kHz.
ULM.parameters.NLocalMax = 3; % Safeguard on the number of maxLocal in the fwhm*fwhm grid (3 for fwhm=3, 7 for fwhm=5)
[but_b,but_a] = butter(2,ULM.ButterCuttofFreq/(framerate/2),'bandpass');
ULM.lambda = lambda;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Load data and localize microbubbles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tic;Track_tot = {};
fprintf('--- ULM PROCESSING --- \n\n');t1=tic;
%parpool(16)
parfor hhh = 1:80 %min(999,Nbuffers) % can be used with parallel pool par
% for hhh = 1:Nbuffers
%fprintf('Processing bloc %d/%d\n',hhh,Nbuffers);
% Load IQ data (or other kind of images without compression)
tmp = load(strcat('C:\Users\hlexuan\Desktop\PALA_raw\Data\data_ibrain\IQ\iqbfc',int2str(hhh),'.mat'),'data');
tmp.IQ = tmp.data.iqbfc(45:204,:,:);
% load the psf %
psf1 = loadload(strcat('C:\Users\hlexuan\Desktop\PALA_raw\Data\data_ibrain\IQ\psf_',int2str(hhh),'.mat'),'psf1');
psf1 = psf1.psf1;
[Nz,Nx,Nt] = size(tmp.IQ);
dz=4; dx=4; %% super resolution scale
m = Nz*dz; n=dx*Nx;
h = psf1;
[m0,n0]=size(h);
Bpad=padarray(h,floor([m-m0+1,n-n0+1]/2),'pre');
H=padarray(Bpad,round([m-m0-1,n-n0-1]/2),'post');
H = fftshift(H);
%% do BSRPCA
IQ_filt = BSRPCA_convergent(tmp.IQ,H,dx,dz);
% Detection and localization process (return a list of coordinates in pixel)
[MatTracking] = ULM_localization2D(abs(IQ_filt),ULM); IQ_filt=[];
% Convert pixel into isogrid (pixel are not necessary isometric);
MatTracking(:,2:3) = (MatTracking(:,2:3) - [1 1]).*ULM.scale(1:2);
% Tracking algorithm (list of tracks)
Track_tot_i = ULM_tracking2D(MatTracking,ULM);
% Track_tot_i = ULM_tracking2D(MatTracking,ULM,'nointerp');
% Saving part:
%--- if for, you can save tracks at each loop to avoid RAM out of memory
% save([workingdir filesep filename '_tracks' num2str(hhh,'%.3d') '.mat'],'Track_tot_i','ULM') %
%--- if parfor you can cat all tracks in a huge cells variable
Track_tot{hhh} = Track_tot_i;
Track_tot_i={};MatTracking = [];
fprintf("finishing block %d \n",hhh);
end
Track_tot = cat(1,Track_tot{:});
Tend = toc(t1);disp('Done')
fprintf('ULM done in %d hours %.1f minutes.\n', floor(Tend/60/60), rem(Tend/60,60));
%% Create individual variable to save using v6 version.
% By cutting Tracks into different variables small than 2GB, the save v6 is faster than save v7.3
CutTracks = round(linspace(1,numel(Track_tot),4));
Track_tot_1 = Track_tot(CutTracks(1):CutTracks(2)-1);
Track_tot_2 = Track_tot(CutTracks(2):CutTracks(3)-1);
Track_tot_3 = Track_tot(CutTracks(3):end);
save(['example_tracks.mat'],'Track_tot_1','Track_tot_2','Track_tot_3','Tend','ULM','-v6')
clear Track_tot_1 Track_tot_2 Track_tot_3
% load([workingdir filesep filename 'example_tracks.mat'])
% Track_tot = cat(1,Track_tot_1,Track_tot_2,Track_tot_3);clear Track_tot_1 Track_tot_2 Track_tot_3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Create MatOut %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% create the MatOut density with interpolated tracks for visual analysis, and with non interpolated tracks for aliasing index calculation.
% Define the size of SRpixel for displaying (default 10)
ULM.SRscale = ULM.scale(1)/ULM.res;
ULM.SRsize = round(ULM.size(1:2).*ULM.scale(1:2)/ULM.SRscale);
% Convert tracks into SRpixel
Track_matout = cellfun(@(x) (x(:,[1 2 3 4])+[1 1 0 0]*1)./[ULM.SRscale ULM.SRscale 1 1],Track_tot,'UniformOutput',0);
llz = [0:ULM.SRsize(1)]*ULM.SRscale;llx = [0:ULM.SRsize(2)]*ULM.SRscale;
%% Accumulate tracks on the final MatOut grid.
fprintf('--- CREATING MATOUTS --- \n\n')
MatOut = ULM_Track2MatOut(Track_matout,ULM.SRsize+[1 1]*1); %pos in superpix [z x]
MatOut_zdir = ULM_Track2MatOut(Track_matout,ULM.SRsize+[1 1]*1,'mode','2D_vel_z'); %pos in superpix [z x]
MatOut_vel = ULM_Track2MatOut(Track_matout,ULM.SRsize+[1 1]*1,'mode','2D_velnorm'); %pos in superpix [z x]
MatOut_vel = MatOut_vel*ULM.lambda; % Convert into [mm/s]
% %% MatOut intensity rendering, with compression factor
fprintf('--- GENERATING IMAGE RENDERINGS --- \n\n')
figure(1);clf,set(gcf,'Position',[652 393 941 585]);
IntPower = 1/3;SigmaGauss=0;
im=imagesc(llx,llz,MatOut.^IntPower);axis image; colormap hot;
if SigmaGauss>0,im.CData = imgaussfilt(im.CData,SigmaGauss);end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment