indexing in for loop

8 views (last 30 days)
C.G.
C.G. on 4 Jun 2020
Commented: Rik on 4 Jun 2020
I am working off a video of 662 continuously moving footballs and I want to track these through 10 frames in the video.
I have written the code which identifies all the balls using imfindcircles, and uses the coordinates of the centre of each ball to calculate distance moved and hence velocity between each frame.
The next step is for each of the 10 frames, crop all 662 balls into their own individual image using the coordinates if the ball centre. I have written the code for this below, however I cannot work out how to edit my for loop to:
1) Save the individual images it produces when cropping and not overprint the result. I know this involves indexing in the loop but I am not sure where to put the index.
2) Do the steps for all 10 frames in the video.
Can anybody provide any insight?
%% Input video
%Input video using videoreader command and name it 'obj'
obj = VideoReader('2D_football_video.mp4')
%% Define the start and end frames for all the tracking runs
%Define the frames between which particles are going to be tracked
start_frame = 1; %which frame of the video do you want it to start from
numFrames = 10; %which frame of the video do you want it to end on
%% Identify the whole ball in frames 1 and 2 track these through each video frame
% Identify the centres of each football in frames 1 and 2, and use these to
% track velcoity (translation)
%Define the radii of the circles to get MATLAB to search for
min_radiusball = 15;
max_radiusball = 25;
quality = .9; %quality is a number between 0-1 to see how strong a circle must be in order to be found. Values of 1 discard no circles
t = 0.1; % t is the frame rate, used as time in the velocity calculation
% Grid coarseness
n = 5; %spacing in the grid
% Here I am going to do all the same steps but in one move, this will be much more memory efficient.
tmpframe = read(obj,1); %read only the first frame from the video
% Meshgrid creates 2D grid coordinates with x and y coordinates defined by the length of the two inputted vectors
% Grids going from 1 to the length of tmpframe, in spacings of 5 (n)
[X,Y]=meshgrid(1:n:size(tmpframe,2),1:n:size(tmpframe,1));
%Track the whole balls and plot velocity for frames 1 and 2
for k = 1:numFrames; %loop through all the frames in the video
%binarize frames 1 and 2 from the video (using rgb2gray)
frame_1 = rgb2gray(read(obj,k+start_frame-1));
frame_2 = rgb2gray(read(obj,k+start_frame));
%identify the circles in frames 1 and 2 with radii between the defined min and max
%imfindcircles is a function in matlab that finds circles between a radius range
%radius is set to identify the whole ball
ballcentres_1 =imfindcircles(frame_1,[min_radiusball,max_radiusball],'Sensitivity',quality,'Method','TwoStage');
ballcentres_2 =imfindcircles(frame_2,[min_radiusball,max_radiusball],'Sensitivity',quality,'Method','TwoStage');
%identify where each circle has moved between frames 1 and 2
%returns the distance from each point in centres_2 to the corresponding point in centres_1
%indexb = indicies returned as a column vector containing the indicies
%of the data points closest to the query points
%distb = distance, returned as a column vector containing the euclidean
%distance between each query point and the closest input point
[indexb,distb] = dsearchn(ballcentres_2,ballcentres_1);
% here we have the distances not in order
% assign the circles from frames 1 and 2 to x and y coordinate variables
xb_1{k} = ballcentres_1(:,1);
xb_2{k} = ballcentres_2(indexb,1);
yb_1{k} = ballcentres_1(:,2);
yb_2{k} = ballcentres_2(indexb,2);
%check its assigned the centres correctly in each frame
subplot(2,1,1)
imshow(frame_1)
hold on
scatter(xb_1{k},yb_1{k},'r*')
subplot(2,1,2)
imshow(frame_2)
hold on
scatter(xb_2{k},yb_2{k},'b*')
% now we compute the translational velocity of each ball as v = d/t
velb_x{k} = (xb_2{k}-xb_1{k})/t; % x velocity using frame 2 - frame 1
velb_y{k} = (yb_2{k}-yb_1{k})/t; % y velocity using frame 2 - frame 1
velb_res{k} = sqrt(velb_x{k}.^2 + velb_y{k}.^2); % the final velocity vector as a function as its x and y components
% now we can make a overall velocity map, by reshaping the array
% for all the columns in 'loop', reshape the array 'griddata' to define, size U, V and RES
Ub(:,:,k)=reshape(griddata(xb_1{k},yb_1{k},velb_x{k},X(:),Y(:)),size(X,1),size(X,2));
Vb(:,:,k)=reshape(griddata(xb_1{k},yb_1{k},velb_y{k},X(:),Y(:)),size(X,1),size(X,2));
RESb(:,:,k)=reshape(griddata(xb_1{k},yb_1{k},velb_res{k},X(:),Y(:)),size(X,1),size(X,2));
end
% Code works properly up to here
%% Crop the images to only 1 ball per image and run the code again
% We identified the movement of the whole ball (translation), now we want to identify the
% movement of the pentagons (rotation).
% Want to crop each of the balls in frame 1 and 2 to its their own individual image
% Should end up with 662 individual images for each sub frame
% Once they have been cropped, the code can be reapplied to identify the
% centres of the pentagons.
% ISSUE - the code should subimage 662 balls in each of the 10 video frames, currently it only produces 1 image
thresholdvalue = 13; %use as threshold when binarizing
r = 23; %radius of whole ball; grab 20 pixels in each direction of the coordinates
xbcoords1 = xb_1{1}; % the '1' index tabkes all the x_coords from frame 1
ybcoords1 = yb_1{1};
xbcoords2 = xb_2{2}; % the '2' index tabkes all the x_coords from frame 2
ybcoords2 = yb_2{2};
numballs = length(xbcoords1); %define the number of balls in the frame by the number of centroids found
for k = 1:numFrames
for i = 1:numballs %for all the balls identified
ball_xcoord1(i) = xbcoords1(i);
ball_ycoord1(i) = ybcoords1(i);
ball_xcoord2(i) = xbcoords2(i);
ball_ycoord2(i) = ybcoords2(i);
% crop the frame down to a series of coordinates, and do this for each
% ball's coordinates to end up with 662 individual images, for each frame in the video
subframe1 = frame_1(round(ball_ycoord1)-r:round(ball_ycoord1)+r, round(ball_xcoord1)-r:round(ball_xcoord1)+r);
subframe2 = frame_2(round(ball_ycoord2)-r:round(ball_ycoord2)+r, round(ball_xcoord2)-r:round(ball_xcoord2)+r);
end
end
  11 Comments
C.G.
C.G. on 4 Jun 2020
I wrote the code you suggested 3 hours ago out line by line into my own script rather than copying and pasting, so your comment 2. never occured in my own script.
I used the debugger in the code as soon as the error occured, so I know where the error is, and this is caused by the variables ball_xcoord1 etc. only showing 1 value rather than looping through all the balls even though it is in a for loop.
Rik
Rik on 4 Jun 2020
The whole point is that ball_xcoord1 etc are scalars. That makes them easy to work with. Every ball has only 1 x and 1 y in each frame. That is what you are extracting.

Sign in to comment.

Answers (0)

Tags

Community Treasure Hunt

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

Start Hunting!