Clear Filters
Clear Filters

How to iterate through a cell array and link elements in particle tracking?

8 views (last 30 days)
Hi. I have tried several times to get this to work but I cant get my head around it, so any help is much appreciated.
I am trying to do some particle tracking across frame images. The output from the particle tracking is a cell array with the number of tracks made and the index to the row of the coordinate matrix where the particles are stored (Points matrix).
For example, Index_matrix{1} = [108; 0; 373] means that there are 3 frames (size of the track), but that on the second frame, the particle was not tracked but then was again picked up in the last frame. To get the coordinates of the points this track refers to, I would then index into the Points matrix for all tracks in a loop eg code below.
for u=1:Number_of_frames
for i_track=1:size(Index_matrix,1)
track_points = (Points(track_in(u), :));
I want to be able to plot the tracks on a per image basis, for example, for frame 1 I dont need to plot as its the first frame in the sequence. Frame 2, I would like to plot the tracks made from u=1 particles to u=2 particles. For frame 3, i would like to plot frame 2 - frame 3 for example. So I can do this with a change to code below track_points = (all_points(adj_track_inside(u-1:u), :));. But this actually fails with the example given above where there is a zero in the second frame, so if u=3, indexing with (u-1:u) wont work.
I also have to account for the occasion that Index_matrix{2} = [0; 0; 373] eg. particle only located in one frame
and Index_matrix{1} = [0; 108; 373] for example, where the particle track starts in second frame.
This is just an example of three frame tracks, but in theory it could be "n" frames. So i could be seeing tracks such as [103;0;25;0;29;38], and here my ideal scenario is I would plot 6 images: 1st image, no track (as its the 1st particle). 2nd image; no track(0 in track), 3rd image, draw the track connecting rows 103 and 25 so it would be u and u-2. 4th image no track (0 in track matrix), 5th image, draw the track connecting 29 to 25, so here it would be u and u-2 again here but the last image would be connecting consecutive tracks, so u and u-1.
I just cant seem to find a way to generalise this. Really sorry if this doesnt make sense.
I've attached my work in progess code below and the variables needed to make it run.
Thanks a lot!
%Input: Tracked particles per frame
% Index_matrix - cell array with number of rows == number of tracks made.
%zeros in the track means its not been picked up in this frame
%tracks has an old ID in there that I stored for later use and has NaNs in
%place of the 0s in the index matrix. I used this in the loop below so I
%could use logical 1,0 expressions.
if track_drawing
if full_frame==0 %track particles that are missed in some frames but picked up in later frames
for u=1:Number_of_frames
%read in image per frame and plot coordinates of the
%particles - done
for m=1:number_particles
if u~=1 % There will be no tracks for the first frame.
for j_track = 1 : number_particles
adj_track_inside = Index_matrix{j_track}; %Index of the points where tracks need to be made.
if size(size_checking,1)==1
disp 'no tracking' %only detected in one frame across all track so dont need to plot it.
if tf(u-1,1) ==1 || tf(u,1) ==1 %if theres a zero in that frame or in the frame before skip it.
elseif tf(u,1) ~=1 && tf(u-1,1)~=1
track_points = (all_points(adj_track_inside(u-1:u), :));
elseif tf(u,1) ~=1 && tf(u-1,1)==1
track_points = (all_points(adj_track_inside(u-2:u-1), :));
hold on
plot(track_points(:,1), track_points(:, 2), 'Color', CM(j_track,:),'LineWidth',3)
no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking no tracking
  1 Comment
Ruby 19
Ruby 19 on 20 Oct 2023
I should have added that whilst this code techincally works with no error messages, it is not correct. In attached variables, j_track = 108 and u=3 satisfies tf(u-1,1) ==1 || tf(u,1) ==1 where Index_matrix{108}= [108; 0; 373]. So here I instead need that the link can be made from the 3rd particle to the first, for u=3, where the particle in the 2nd frame is missing.

Sign in to comment.

Answers (2)

dpb on 20 Oct 2023
Moved: dpb on 20 Oct 2023
I don't have time at the moment to attack in earnest, but I'd probably start by simplifying and instead of trying to make it all work in one nested loop with deep logic, I'd first build a list of the frames found indices for each track, then process that list -- that eliminates the zero indexing. If there's not supposed to do anything between non-adjacent frames, then diff(indices)>1 will tell you that...
Index_matrix{1} = [108; 0; 373];
for i=1:numel(Index_matrix)
indices=find(Index_matrix{i}) % which frames to process
delta=diff(indices) % the difference in frames vector
for j=1:numel(delta)
indices = 2×1
1 3
delta = 2

Voss on 20 Oct 2023
This plots using only the "good" (i.e., non-zero) indices from Index_matrix{jj}. Note that three additional particle tracks are plotted by this code vs by your original code, corresponding to the three particles that "disappeared" for a frame and then came back (particle #108, #115, and #122).
Based on your description of your ultimate goal (multiple images plotted), the code here doesn't get you there, but maybe it's a start. In any case, hopefully it's useful to see this simpler code that does what your code did (plus a little bit more).
load Index_matrix
load Points
all_points = vertcat(Points{:});
number_particles = size(Index_matrix,1);
CM = jet(number_particles);
hold on
for jj = 1:number_particles
idx = Index_matrix{jj}; %Index of the points where tracks need to be made.
is_good = idx ~= 0;
if nnz(is_good) < 2
% disp 'no tracking' %only detected in (at most) one frame across all track so dont need to plot it.
track_points = all_points(idx(is_good),:);
plot(track_points(:,1), track_points(:, 2), 'Color', CM(jj,:),'LineWidth',3);
dpb on 21 Oct 2023
OK, what I had sorta' presumed. The way to do this is same idea as above excepting the use of the difference is now going to be important to flag empty frames.
The way to then build frames will be to not create a zillion files for each but to use im2frame to build the move struct in memory and then save it.
What's not clear to me from your statement is whether you want a single-particle movie for each particle individually, or whether all particles are to be shown...
Ruby 19
Ruby 19 on 22 Oct 2023
Thankyou for your reply and for pointing me to the im2frame option, I had not heard of this and I was planning on saving each image corresponding to each frame into a .Tiff and then building the movie outside of Matlab. So Thankyou!
I would need a movie where all particles and their tracks are shown at the same time, rather than a movie per particle.

Sign in to comment.


Find more on Convert Image Type in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!