video processing for motion detection

can i track the motion of a motor from a video? i tried histogram plotting but exporting data is hard

12 Comments

Depends what footage you have and what you want to track. Are you looking for rpm? You should attach a shortish video.
i attached the footage . and yes. i want to measure rpm
You could do it alright, I would probably look at just processing a single pixel in each image to detect the flash from the laser. Is there are reason have to use video footage? You could set up a photodiode to detect the laser, like a laser tachometer, and that would be much more efficient (MATLAB also supports arduino).
the main idea behind this was to generate histogram for each frame , combine them together and then calculate the frequency. i could generate the histograms but can not combine them in one plot to perform further opertaions. how can i do that? or how can i directly measure the rpm form the video?
Do you want each histogram to go into one row or one column, and then build up an image of histograms and then show them with imshow()? Like
histImage = zeros(numberOfFrames, 256);
for k = 1 : numberOfFrames
thisFrame = .......whatever.
counts = histcounts(thisFrame); % Get histogram of this frame.
histImage(row, :) = counts; % Add this frame's histogram to the image.
imshow(histImage, []); % Display the histogram image.
drawnow;
end
workingDir = 'C:\Users\Documents\MATLAB';
mkdir(workingDir);
mkdir(workingDir,'images');
shuttleVideo = VideoReader('20190504_181751.mp4');
for ii = 1:shuttleVideo.NumberOfFrames
img = read(shuttleVideo,ii);
[rows,cols] = size(img);
histogram_values = zeros(256,1);
color('RGB');
for i = 1:rows
for j = 1:cols
p = double(img(i,j)) + 1;
histogram_values(p) = histogram_values(p) + 1;
end
end
%// Show histogram
ll=bar(0:255, histogram_values, 'histc');
saveas(ll, sprintf('HIS%d.png',ii));
% Write out to a JPEG file (img1.jpg, img2.jpg, etc.)
imwrite(img,fullfile(workingDir,'images',sprintf('img%d.jpg',ii)));
end
imageNames = dir(fullfile(workingDir,'images','*.jpg'));
imageNames = {imageNames.name}';
imageStrings = regexp([imageNames{:}],'(\d*)','match');
imageNumbers = str2double(imageStrings);
[~,sortedIndices] = sort(imageNumbers);
sortedImageNames = imageNames(sortedIndices);
this is my code, i am getting invidual histgram plot for each frame. what i have to modify here?
How do you want the histograms to appear? As an image where the brightness of the pixel is related to the counts in the bin, or as a bunch of overlapping line plots where you can see a line plot of all the histograms superimposed on each other?
a single line plot, where the histograms are plotted side by side. not imposed. they have to be distinguished or else i cant have that one re apprearing frame .
Like concatenated? Stitched end-to-end? Maybe with a vertical line at the place that separates the different line plots?
yes, concatenated. separation of plots is not necessery.
help me out please :(

Sign in to comment.

 Accepted Answer

So the method I suggested was to look at a single pixel, though you could also look at a few, or the entire image histogram, up to you. Here I track the R component of the mid pixel of each frame and then find local maxima which are greater than a nominal threshold value.
framerate=29.53; % I don't see how to get this from the video object directly.
threshold=0.15;
v=vision.VideoFileReader('vid.mp4');
c=0;
while ~isDone(v)
c=c+1;
f=step(v);
data(c)=f(360,720,1); % for green just replace the with, data(c)=f(360,720,2);
end
figure(), plot(data)
idx1=find(data(2:end-1) > data(1:end-2) & data(2:end-1) > data(3:end))+1; % find local maxima, 'data2'
data2=data(idx1);
hold on, plot(idx1,data2,'or'); % shows local maxima in plot
idx2=find(data2>threshold); % local maxima satisfying threshold
peakFrame=idx1(idx2);
hold on, plot(peakFrame,data2(idx2),'.k','MarkerSize',15) % shows peaks that pass threshold.
numFrames=peakFrame(end)-peakFrame(1) % number of frames from first to last flash.
revs=length(data2(idx2))-1; % Corresponding number of revolutions.
duration=numFrames/framerate; % numFrames/FramesPerSecond = duration in seconds
rpm=revs/(duration/60)
EDIT: as per comments below.

11 Comments

For VideoReader it could go something like this:
framerate=29.53;
threshold=50;
v=VideoReader('vid.mp4');
c=0;
while hasFrame(v)
c=c+1;
f=readFrame(v);
data(c)=f(360,720,1);
end
figure(), plot(data)
data2=data(islocalmax(data));
revs=length(data2(data2>threshold));
duration=framerate/c;
rpm=revs/(duration/60)
it shows=Undefined function 'hasFrame' for input arguments of type 'VideoReader'.
and with the vision toolbox it shows=Undefined function 'islocalmax' for input arguments of type 'single'.
Sounds like you have an old version of Matlab. Can you confirm what version of MATLAB you have? hasFrame was introduced in 2014b while islocalmax was introduced in 2017b. Just type in
ver
Ok, I used the vision toolbox functions and some logic to replace islocalmax. I've included some plotting for you to step through to see how the code is working. This gets your rpm directly by processing just the middle pixel of the image.
framerate=29.53;
threshold=0.15;
v=vision.VideoFileReader('vid.mp4');
c=0;
while ~isDone(v)
c=c+1;
f=step(v);
data(c)=f(360,720,1);
end
figure(), plot(data)
idx1=find(data(2:end-1) > data(1:end-2) & data(2:end-1) > data(3:end))+1; % find local maxima, 'data2'
data2=data(idx1);
hold on, plot(idx1,data2,'or'); % shows local maxima in plot
idx2=find(data2>threshold); % local maxima satisfying threshold
hold on, plot(idx1(idx2),data2(idx2),'.k','MarkerSize',15) % shows peaks that pass threshold.
revs=length(data2(idx2));
duration=c/framerate; % numFrames/FramesPerSecond = duration in seconds
rpm=revs/(duration/60)
edit; equation for duration was incorrect.
it gave me a result but i dont understand how it is working and also the rpm is in exponential form.
Each frame is a 720 by 1280 by 3 rgb image, ie 720 by 1280 pixel where each pixel an r,g,b component. I nominally chose to study the intensity of the r value of the center pixel of each frame in your video to detect a flash from the laser. You can see these flashes as as prominent peaks in the plot, (red intensity on y axis, frame number on x axis). The next part of the code defines some rules to autmatically locate the peaks in your data, they are:
  • that the intensity of r for this pixel on the given frame is a local max. ie where the r intensity of adjacent frames is less than the current one (results are red circle point plots)
  • that this local max is also greater than a certain threshold value. (results are the black dots)
The revolutions, 'revs', corresponds to the number of laser flashes, and then to get revs per second you divide the number of revolutions by the duration in minutes.
One can get the duration in seconds by dividing the number of frames, c, by the framerate, then dividing again by 60 to convert from seconds to minutes.
Regarding the format that data is printed to the screen, see the following documentation.
what if i want to know the intensity of green or blue light in the center pixel, where will it be changed?
also. the rpm isnt correct. the thing is i will get the duration by multiplying the framerate with number of frames. in the code, u used framerate directly. framerate wasnt calculated. the rpm should be around 217 but it is giving a resul of much higher . cant i extract the info about duration of the video directly?
i cant find any function to determine the framerate with vision.videofilereader.
i cant find any function to determine the framerate with vision.videofilereader.
Neither can I. I took the framerate from looking at file details. Surely there's a way to get it with code but I can't see how. I see you've opened another question on this though.
what if i want to know the intensity of green or blue light in the center pixel
See comments in my edit to my original answer, also have a look at the following documentation.
the thing is i will get the duration by multiplying the framerate with number of frames
you get duration from NumberOfFrames/framerate: . I originally had framerate/NumberOfFrames but had fixed that before my last comment.
hey,
so i could extract the framerate using videoReader.
now, the number of frames is showing 446, wheres the number of frames of the whole video is 265. shouldnt the number be less? cause i am only taking the frames with the flashes, no?

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!