Loop for frame extraction matlab - matlab

Im currently trying to make a loop to do the same action to multiply videofiles. Currently my code looks like this:
close all
clear all
clc
movFiles = dir('*.mov');
numFiles = length(movFiles);
mydata = cell(1,numFiles);
% mydata = zeros(numFiles);
for k = 1:numFiles
mydata{1,k} = VideoReader(movFiles(k).name);
end
for k=1:numFiles
figure;
video = read(mydata{k},[1 Inf]);
for img = 60:60:360;
filename=strcat('File',num2str(img),'.jpg');
b = read(mydata{k}, img);
imwrite(b,filename);
end
end
The problem is that the frames get overwritten so what i need is a way to not make that happened. The moviefiles are named 1-200 so the filename i would like is something like 1framenr, 2framenr. Hope that somebody can help me with that

The problem is in the way you are defining the filename for each frame inside the loop. If you look at the line:
filename=strcat('File',num2str(img),'.jpg');
It is only composed of the frame number (img), which will repeat for every video file. Try replacing that line with following:
filename = ['Video_' num2str(k) '_frame_' num2str(img) '.jpg'];
This will give you files called Video_1_frame_1.jpg, Video_1_frame_2.jpg, etc.

Related

Matlab help to read multiple file images and save the final image to directory

im trying to do some facial recognition as im currently trying to figure out an idea i want to put in place
Ive never had to read multiple images from a folder before and i gave it my best shot but have come across an error that i cant seem to work ou
myPath = 'C:\Users\Callum\Desktop\Msc Computer Science\CN7023\CW\Faces_easy\';
a = dir(fullfile(myPath, '*.jpg'));
fileName = arrayfun( #(x) fullfile( myPath, x.name ), a, 'UniformOutput', false );
for k = 1:length(fileName)
I = imread(fileName{k});
end
// Code to add in
files = dir('C:\Users\Callum\Desktop\Msc Computer Science\CN7023\CW\Faces_easy\*.jpg');
files_len = numel(files);
result = cell(files_len,2);
for ii = 1:files_len
file = fullfile(files(ii).folder,files(ii).name);
img = imread(file);
result(ii,:) = {file perform_analysis(img)}; % or whatever your function is called
end
//
faceDetect = vision.CascadeObjectDetector();
bbox=step(faceDetect,I);
face=imcrop(I,bbox);
centerx=size(face,1)/2+bbox(1);
centery=size(face,2)/2+bbox(2);
eyeDetect = vision.CascadeObjectDetector('RightEye');
eyebox=step(eyeDetect,face);
n=size(eyebox,1);
e=[];
for it=1:n
for j=1:n
if (j > it)
if ((abs(eyebox(j,2)-eyebox(it,2))<68)&& (abs(eyebox(j,1)-eyebox(it,1))>40))
e(1,:)=eyebox(it,:);
e(2,:)=eyebox(j,:);
d=1;break;
end
end
end
if(d == 1)
break;
end
end
eyebox(1,:)=e(1,:);
eyebox(2,:)=e(2,:);
c=eyebox(1,3)/2;
d=eyebox(1,4)/2;
eyeCenter1x=eyebox(1,1)+c+bbox(1);
eyeCenter1y=eyebox(1,2)+d+bbox(2);
e=eyebox(2,3)/2;
f=eyebox(2,4)/2;
eyeCenter2x=eyebox(2,1)+e+bbox(1);
eyeCenter2y=eyebox(2,2)+f+bbox(2);
ndetect=vision.CascadeObjectDetector('Nose','MergeThreshold',16);
nosebox=step(ndetect,face);
noseCenterx=nosebox(1,1)+(nosebox(1,3)/2)+bbox(1);
noseCentery=nosebox(1,2)+(nosebox(1,4)/2);
m=[1,noseCentery,size(face,1),((size(face,2))-noseCentery)];
mouth=imcrop(face,m);
mdetect=vision.CascadeObjectDetector('Mouth','MergeThreshold' ,20);
mouthbox=step(mdetect,mouth);
for it=1:size(mouthbox,1)
if(mouthbox(it,2)>20)
mouthbox(1,:)=mouthbox(it,:);
break;
end
end
mouthbox(1,2)=mouthbox(1,2)+noseCentery;
noseCentery=noseCentery+bbox(2);
mouthCenterx=mouthbox(1,1)+(mouthbox(1,3)/2)+bbox(1);
mouthCentery=mouthbox(1,2)+(mouthbox(1,4)/2)+bbox(2);
shape=[centerx centery;eyeCenter1x eyeCenter1y;eyeCenter2x eyeCenter2y;noseCenterx noseCentery;mouthCenterx mouthCentery];
imshow(I);
hold on;
plot(shape(:,1),shape(:,2),'+','MarkerSize',10);
eyebox(1,1:2)=eyebox(1,1:2)+bbox(1,1:2);
eyebox(2,1:2)=eyebox(2,1:2)+bbox(1,1:2);
nosebox(1,1:2)=nosebox(1,1:2)+bbox(1,1:2);
mouthbox(1,1:2)=mouthbox(1,1:2)+bbox(1,1:2);
all_points=[eyebox(1,:);eyebox(2,:);nosebox(1,:);mouthbox(1,:)];
dpoints=size(all_points,1);
label=cell(dpoints,1);
i=1;
for i = 1: dpoints
label{i}= num2str(i);
end
videoout=insertObjectAnnotation(I,'rectangle',all_points,label,'TextBoxOpacity',0.3,'Fontsize',9);
imshow(videoout);hold on;plot(shape(:,1),shape(:,2),'+','MarkerSize',10);
dt=delaunayTriangulation(shape(:,1),shape(:,2));
imshow(videoout);hold on;triplot(dt);hold off
So i have changed it to what i currently have and it works but only on the last image, i want to make it do it on all images in a folder... I have 435 images in the folder it is calling, i dont want to all open as a figure once done, i would like them to save to a certain folder or workspace if that is possible
Print "fileName{k}" to verify if you are getting the required path for file.
secondly do not update fileName inside loop, you need to use different variable here inside loop.
If you want to perform your analysis on every image, you have to put your logics inside the loop itself and collect their result into a cell array or something across the lines. For instance, you can also simplify your folder search:
files = dir('C:\Users\Callum\Desktop\Msc Computer Science\CN7023\CW\Faces_easy\*.jpg');
files_len = numel(files);
result = cell(files_len,2);
for ii = 1:files_len
file = fullfile(files(ii).folder,files(ii).name);
img = imread(file);
result(ii,:) = {file perform_analysis(img)}; % or whatever your function is called
end
Once this is done, every row of the result variable will contain the file name in the first column and the analysis outcome in the second column.
EDIT
files = dir('C:\Users\Callum\Desktop\Msc Computer Science\CN7023\CW\Faces_easy\*.jpg');
files_len = numel(files);
for ii = 1:files_len
file = fullfile(files(ii).folder,files(ii).name);
I = imread(file);
faceDetect = vision.CascadeObjectDetector();
bbox=step(faceDetect,I);
face=imcrop(I,bbox);
centerx=size(face,1)/2+bbox(1);
centery=size(face,2)/2+bbox(2);
eyeDetect = vision.CascadeObjectDetector('RightEye');
eyebox=step(eyeDetect,face);
n=size(eyebox,1);
e=[];
for it=1:n
for j=1:n
if (j > it)
if ((abs(eyebox(j,2)-eyebox(it,2))<68)&& (abs(eyebox(j,1)-eyebox(it,1))>40))
e(1,:)=eyebox(it,:);
e(2,:)=eyebox(j,:);
d=1;break;
end
end
end
if(d == 1)
break;
end
end
eyebox(1,:)=e(1,:);
eyebox(2,:)=e(2,:);
c=eyebox(1,3)/2;
d=eyebox(1,4)/2;
eyeCenter1x=eyebox(1,1)+c+bbox(1);
eyeCenter1y=eyebox(1,2)+d+bbox(2);
e=eyebox(2,3)/2;
f=eyebox(2,4)/2;
eyeCenter2x=eyebox(2,1)+e+bbox(1);
eyeCenter2y=eyebox(2,2)+f+bbox(2);
ndetect=vision.CascadeObjectDetector('Nose','MergeThreshold',16);
nosebox=step(ndetect,face);
noseCenterx=nosebox(1,1)+(nosebox(1,3)/2)+bbox(1);
noseCentery=nosebox(1,2)+(nosebox(1,4)/2);
m=[1,noseCentery,size(face,1),((size(face,2))-noseCentery)];
mouth=imcrop(face,m);
mdetect=vision.CascadeObjectDetector('Mouth','MergeThreshold' ,20);
mouthbox=step(mdetect,mouth);
for it=1:size(mouthbox,1)
if(mouthbox(it,2)>20)
mouthbox(1,:)=mouthbox(it,:);
break;
end
end
mouthbox(1,2)=mouthbox(1,2)+noseCentery;
noseCentery=noseCentery+bbox(2);
mouthCenterx=mouthbox(1,1)+(mouthbox(1,3)/2)+bbox(1);
mouthCentery=mouthbox(1,2)+(mouthbox(1,4)/2)+bbox(2);
shape=[centerx centery;eyeCenter1x eyeCenter1y;eyeCenter2x eyeCenter2y;noseCenterx noseCentery;mouthCenterx mouthCentery];
imshow(I);
hold on;
plot(shape(:,1),shape(:,2),'+','MarkerSize',10);
eyebox(1,1:2)=eyebox(1,1:2)+bbox(1,1:2);
eyebox(2,1:2)=eyebox(2,1:2)+bbox(1,1:2);
nosebox(1,1:2)=nosebox(1,1:2)+bbox(1,1:2);
mouthbox(1,1:2)=mouthbox(1,1:2)+bbox(1,1:2);
all_points=[eyebox(1,:);eyebox(2,:);nosebox(1,:);mouthbox(1,:)];
dpoints=size(all_points,1);
label=cell(dpoints,1);
i=1;
for i = 1: dpoints
label{i}= num2str(i);
end
videoout=insertObjectAnnotation(I,'rectangle',all_points,label,'TextBoxOpacity',0.3,'Fontsize',9);
imshow(videoout);hold on;plot(shape(:,1),shape(:,2),'+','MarkerSize',10);
dt=delaunayTriangulation(shape(:,1),shape(:,2));
imshow(videoout);hold on;triplot(dt);hold off
end

How to print the current filename in a plot in matlab?

I have one .m file per plot and want to see in my draft printouts, which file was used to create it.
This should be done with a function which can be placed in my .m file and
commented out, for the final version.
% addWatermarkFilename() %
So far I found mfilename(), but it could not get the name of the calling function. I am looking also for a good way to put the text in the picture without changing the size.
Solution:
I combined the suggestions by Luis Mendo and NKN to:
function [ output_args ] = watermarkfilename( )
% WATERMARKFILENAME prints the filename of the calling script in the
% current plot
s = dbstack;
fnames = s(2).name;
TH = text(0,0,fnames,'Interpreter','none');
TH.Color = [0.7 0.7 0.7];
TH.FontSize = 14;
TH.Rotation = 45;
uistack(TH,'bottom');
end
I suggest instead of commenting out a function from the code, use a proper flag. For instance the code can be something like this:
clc,clear,close all
addWaterMark = true; % if true you will get the filename in the title
fname = mfilename; % get file name mfilename('fullpath') for the full-path
t=-2*pi:0.1:2*pi;
y = sin(t);
plot(t,y); grid on;
xlabel('t');ylabel('y');
if addWaterMark
title(['filename: ' fname '.m']);
else
title('plot no.1');
end
A little bit playing with the text function, you can make a proper watermark. something like this:
clc,clear,close all
addWaterMark = true;
fname = mfilename;
fnames = [fname '.m'];
t=-2*pi:0.1:2*pi;
y = sin(t);
plot(t,y); grid on;
xlabel('t');ylabel('y');
if addWaterMark
title(['filename: ' fnames]);
t = text(-3,-0.4,fnames);
t.Color = [0.7 0.7 0.7];
t.FontSize = 40;
t.Rotation = 45;
else
title('plot no.1');
end
Note: Obviously the code between the if and else can be stored as a function that receives the string (char) from the fnames variable and a handle for the figure.
If you want to get the name of the function or script that called the current function or script, use dbstack as follows:
s = dbstack; % get struct with function call stack information
callerName = s(2).name; % get name of second function in the stack
The first entry in s refers to the current function; the second refers to the one that called it.

Background frame loop matlab

Im trying to make a loop for doing the same operation to a lot of .mov files in matlab. The code i have right now looks like this:
close all
clear all
clc
movFiles = dir('*.mov');
numFiles = length(movFiles);
mydata = cell(1,numFiles);
% mydata = zeros(numFiles);
for k = 1:numFiles
mydata{1,k} = VideoReader(movFiles(k).name);
end
for k=1:numFiles
bk_downsample = 5; %The downsample factor for frame averaging
%disp('Opening video...') %lower number =longer computation time
vob = mydata;
frame = vob.read(inf); %Reads to end = vob knows the number of frames
vidHeight = vob.Height;
vidWidth = vob.Width;
nFrames = vob.NumberOfFrames;
%% First-iteration background frame
background_frame = double(frame*0);
disp('Calculating background...')
for k = 1:bk_downsample:nFrames
background_frame = background_frame + double(read(vob, k));
disp(k/(nFrames)*100)
end
%background_frame = uint8(bk_downsample*background_frame/(nFrames));
background_frame = bk_downsample*background_frame/(nFrames);
%imshow(background_frame)
%% Second-iteration background frame
%This section re-calculates the background frame while attempting to
%minimize the effect of moving objects in the calculation
background_frame2 = double(frame*0);
pixel_sample_density = im2bw(double(frame*0));
diff_frame = double(frame*0);
stream_frame = diff_frame(:,:,1);
bk_downsample = 10;
figure
hold on
for k = 1:bk_downsample:nFrames
diff_frame = imabsdiff(double(read(vob, k)), background_frame);
diff_frame = 1-im2bw(uint8(diff_frame),.25);
pixel_sample_density = pixel_sample_density + diff_frame;
stream_frame = stream_frame + (1-diff_frame)/(nFrames/bk_downsample);
nonmoving = double(read(vob, k));
nonmoving(:,:,1) = nonmoving(:,:,1).*diff_frame;
nonmoving(:,:,2) = nonmoving(:,:,2).*diff_frame;
nonmoving(:,:,3) = nonmoving(:,:,3).*diff_frame;
background_frame2 = background_frame2 + nonmoving;
%pause
disp(k/(nFrames)*100)
end
background_frame2(:,:,1) = background_frame2(:,:,1)./pixel_sample_density;
background_frame2(:,:,2) = background_frame2(:,:,2)./pixel_sample_density;
background_frame2(:,:,3) = background_frame2(:,:,3)./pixel_sample_density;
imshow(uint8(background_frame2))
%imshow(stream_frame)
filename = ['Ring_' num2str(k) '_background_' num2str(img) '.jpg'];
imwrite((uint8(background_frame2)),filename)
end
I know that the error starts with vob=mydata; but im not sure how to correct it, hope that someone is able to help me since it would save me a lot of time in my data-analysis.
Have a great day! :)
Your code doesn't make much sense... You're creating a cell array:
mydata = cell(1,numFiles);
%// . . .
mydata{1,k} = . . .
but however you try to access it like a structure:
vob = mydata;
frame = vob.read(inf);
If I'd guess, then your error stems from you forgetting to index in the cell array, i.e.:
vob = mydata{k};
Other programming oddity I noticed in your code is the fact you're using the same looping variable k, in two nested for lops, the outer one being on k=1:numFiles and the inner ones being on k=1:bk_downsample:nFrames; don't do that unless you're trying to drive yourself crazy while figuring out why your for loop executes only once. Name them k1 for the outer loop and k2 for the inner loops and you'll be happier.
I'm no expert in video processing, but for me it looks like your line should be:
vob=mydata{1,k};
That's why that error shows up, because you are treating a cell of structs as if it was a single struct.

sprintf confusion (Matlab)

Quick question,
I would like to make a count from 50-70 using sprintf in Matlab. This example prints 0101-0120
for i = 1:20
filename = sprintf('Brain_01%02d.dcm', i);
[X(:,:,1,i), amap] = dicomread(filename);
end
How would I change this to print 0151-0170?
The answer seemed obvious at first, but it seems like another issue might be related to the indexing of X getting broken if i doesn't start at one. Here's one way to address that while handling pre-allocation of X,
imgInds = 151:170;
di = dicominfo(sprintf('Brain_%04d.dcm',imgInds(1)));
X = zeros(di.Height,di.Width,1,numel(imgInds),class(dicomread(di))); % modify
for i = 1:numel(imgInds),
filename = sprintf('Brain_%04d.dcm', imgInds(i));
[X(:,:,1,i), amap] = dicomread(filename);
end
For clarity, I think it is better to build your sprintf with %04d instead of 01%02d. You should set the size of X accordingly on the line labeled modify, particularly the third dimension since I assume your actual code will not have this be 1.
I'm guessing this should do it:
for i = 51:70
filename = sprintf('Brain_01%02d.dcm', i);
[X(:,:,1,i), amap] = dicomread(filename);
end
Thank you for your responses! Actually all I needed to do (for my purposes) was:
for i = 1:20
filename = sprintf('Brain_01%02d.dcm', i + 49);
[X(:,:,1,i), amap] = dicomread(filename);
end
which made the count start from 50.

Batch Processing Videos (Matlab) - Issue

I've wrote some code that imports a video and takes some DCT coefficients form a specific region of the image frame by frame, it then output a binary file (containing the coefficients) using a separate function. This works fine when doing it individually but I've tried to implement a batch version of the code as I'm working with over 200 videos files.
However their is a problem, when it goes through the loop it output the wrong file each time. If the number of frames in the next iteration has less frames it writes to the previous frames. I was told that i need to initialise one of my for loops before it runs. However I'm sure how to do this, i think the problem lies in the 2nd for loop but I'm not sure.
Any suggestion would be greatly appreciated!
files = dir('Videos/*.mov');
for m = 1:numel(files);
readerobj = mmreader(files(m).name);
vidFrames = read(readerobj);
numFrames = get(readerobj, 'numberOfFrames');
% Create a MATLAB movie struct from the video frames.
for k = 1 : numFrames
mov(k).cdata = vidFrames(:,:,:,k);
mov(k).colormap = [];
end
firstFrame = mov(1).cdata;
rect = [172,225,271,143;];
numFrames = length(mov);
dctCoeff = zeros((10*10),numFrames);
for i = 1 : numFrames
frameImage = imcrop(mov(i).cdata, rect);
frameImage = rgb2gray(frameImage);
dctImage = dct2(frameImage);
dctImage = dctImage(1:10,1:10);
dctCoeff(:,i) = reshape(dctImage,1,(10*10));
end
sRate = (1/29.9701)*1e7;
[status, error] = htk_write_mfc(files(m).name, size(dctCoeff,2),sRate,4*size(dctCoeff,1),9,dctCoeff);
status
error
end
Just remove the
numFrames = length(mov);
and it should work fine!
I was told that i need to initialise one of my for loops before it runs
Jup! You're not initializing mov.
I would also recommend you to put the code for one file into a function which you call from your first loop. That is better code!
Try setting mov to [] for each movie that you load. It's going to keep frames from the previous mov and extend that array to match your longest video. Before your loop for k = 1 : ... try writing a line that says mov = [];.
I am not entirely clear on why you are creating the movie struct. You can use the read() function to read specific frames in the video file. You can try the code below:
files = dir('Videos/*.mov');
numDctCoeffs = 100;
for m = 1:numel(files)
readerObj = mmreader(files(m).name);
numFrames = readerObj.NumberOfFrames;
rect = [172,225,271,143];
sRate = (1/29.9701)*1e7;
dctCoeff = zeros(numDctCoeffs, numFrames);
for cnt = 1:numFrames
frameImage = imcrop(read(readerObj, cnt), rect);
frameImage = rgb2gray(frameImage);
dctImage = dct2(frameImage);
dctImage = dctImage(1:10,1:10);
dctCoeff(:, cnt) = dctImage(:);
[status, error] = htk_write_mfc(files(m).name, size(dctCoeff,2),sRate,4*size(dctCoeff,1),9,dctCoeff);
end
end
Also mmreader has been replaced with VideoReader in newer versions of MATLAB. The syntax is the same just a name change.
Hope this helps.
Dinesh