Batch Processing Videos (Matlab) - Issue - matlab

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

Related

How to save a single .mat file of features for many images (loop for)?

I trained two-class-classification (svmtrain) with 15 features for 18 images and I have many objects in a single image. I want to save single .mat file of features of these images. My problem is when I run this code, I have just the variables of last image.
This is my code:
NbIm = size(names1,1);
n1 = 1;
n2 = NbIm;
for n = n1:n2
%1- Read the original image
%2- Processing : Segmentation
%3- characterization :
[B3,L3,N3] = bwboundaries(ICellules); (see picture)
CC = bwconncomp(L3);
BW = bwlabel(L3);
stats1 = regionprops(CC,'Area','Centroid','Eccentricity','Perimeter','ConvexArea','ConvexHull','ConvexImage','MajorAxisLength','MinorAxisLength','Orientation','Solidity','BoundingBox');
for k = 1:length(B3),
V = []; glcm = [];
V = Im_originale(BW==k);
glcm = graycomatrix(V,'Offset',[2 0],'Symmetric', true);
stats= graycoprops(glcm);
Contrast_Cellule = stats.Contrast;
Correlation_Cellule = stats.Correlation;
Energy_Cellule = stats.Energy;
Homogeneity_Cellule = stats.Homogeneity;
Area_cellule = stats1(k).Area;
Perimeter_cellule = stats1(k).Perimeter;
Circularity_cellule = (4*pi*Area_cellule)/Perimeter_cellule^2;
Centroid_cellule = stats1(k).Centroid;
Compactness_cellule = Perimeter_cellule^2/(4*pi*Area_cellule);
MajorAxis_cellule = stats1(k). MajorAxisLength;
MinorAxis_cellule = stats1(k). MinorAxisLength;
Orientation_cellule = stats1(k).Orientation;
Eccentricity_cellule = stats1(k).Eccentricity;
Solidity_cellule = stats1(k).Solidity;
boundary3 = B3{k};
[cc] = chaincode(boundary3);
ai = cc.code;
ai = ai.';
output = calc_harmonic_coefficients(ai,30);
Ampl = 0.5*sqrt((output(1)^2)+(output(2)^2)+(output(3)^2)+(output(4)^2));
Feat(k,:) = [Area_cellule,Perimeter_cellule,Circularity_cellule,Compactness_cellule, Solidity_cellule,Eccentricity_cellule,MajorAxis_cellule,MinorAxis_cellule, Centroid_cellule,Ampl,Contrast_Cellule,Correlation_Cellule,Energy_Cellule,Homogeneity_Cellule];
end
end
save('FeatTrain.mat', 'Feat');
Every time you run the inner loop (k=...) you overwrite Feat, without ever saving it.
If you want to have a single variable for Feat, instead of saving multiple .mat files there are 2 ways to it:
If every time you run the inner loop the size of Feat is the same, you can make it a 3D matrix, by changing you line to Feat(n-n1+1,k,:)=[.... This will make a 3D matrix where each Feat(n,:,:) will be the features of each image.
If instead every time you run the inner loop Feat can change size, then use a cell array, as in Feat{n-n1+1}(k,:)=[....

Making (MPEG-4) movie from multi images (JPG) in MatLab

Please, I used below code to make a video from multi images (JPG). and it works fine. My problem that I have 10000 images and the code generate the movie with extension avi. This making the size of the movie very large. Are there anyways to save the movie with mp4 extension?
cd('\\Desktop\Movies');
Files = dir('*.jpg');
NumFiles= size(Files,1);
Megamind_Images = uint8(zeros([600 1000 3 NumFiles*5]));
VideoObj = VideoWriter('Create_Video');
VideoObj.FrameRate = 5;
VideoObj.Quality = 80;
count=1;
for i = 1 : NumFiles
I = imread(Files(i).name);
ResizeImg = imresize(I,[600 1000]);
for j = 1 : 5
Megamind_Images(:,:,:,count)=ResizeImg;
count = count + 1;
end
end
open(VideoObj);
writeVideo(VideoObj, Megamind_Images);
close(VideoObj);
Try manually specifying the output profile of your video before writing frames to the object.
VideoObj = VideoWriter('Create_Video.mp4', 'MPEG-4');

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.

Loop for frame extraction 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.

Matlab - combine two videos into a single split-screen video

I have 2 videos I would like to play side by side in a split screen. They are same duration and dimensions. I found a code developed few years back to do the job. The problem is, it is full of errors maybe due to the fact I am using a newer Matlab version (2014a). The errors start from (%name of the new avi file) onward.
Can anyone please try and fix it:
% select two files:
[filename1,pathname1] = uigetfile('.avi','pick first AVI file');
[filename2,pathname2] = uigetfile('.avi','pick second AVI file');
file1 = fullfile(pathname1,filename1);
file2 = fullfile(pathname2,filename2);
pdMovie1 = aviread(file1);
pdMovie2 = aviread(file2);
fileinfo1 = aviinfo(file1);
fileinfo2 = aviinfo(file2);
% check if AVI files have the same length and height:
if fileinfo1.NumFrames~=fileinfo2.NumFrames || ...
fileinfo1.Height~=fileinfo2.Height
errordlg('files are not compatible!')
else
% inspired by Herbert Ramoser in Message-ID:
% <art0c0$l9fip$1#ID-148798.news.dfncis.de>
for i=1:size(pdMovie1,2)
output(i).cdata = [pdMovie1(i).cdata, pdMovie2(i).cdata];
output(i).colormap = pdMovie1(i).colormap;
end;
% name of the new avi file:
[pathstr,name,ext,versn] = fileparts(filename1);
newmoviename = [pathname1,name,'_combined', ...
num2str(fileinfo1.FramesPerSecond;),ext];
% create the avi file:
movie2avi(output, newmoviename, ...
'fps', fileinfo1.FramesPerSecond;, ...
'compression', 'none');
close
end
If it is just for playing the videos side-by-side, this simplker code will work,
close all
clc
clear
vid1 = vision.VideoFileReader('video1.avi');
vid2 = vision.VideoFileReader('video2.avi');
vidP = vision.VideoPlayer;
while ~isDone(vid1)
frame1 = step(vid1);
frame2 = step(vid2);
frame = horzcat(frame1, frame2);
step(vidP,frame);
end
release(vid1);
release(vid2);
release(vidP);
UPDATE:
I'm assuming both input videos have the same length and frame dimension.
Ok, now if you want to record a new video from the first 2, with the same frame rate of the previous, it is better to use the following code,
close all
clc
clear
vid1 = VideoReader('video1.avi');
vid2 = VideoReader('video2.avi');
videoPlayer = vision.VideoPlayer;
% new video
outputVideo = VideoWriter('newvideo.avi');
outputVideo.FrameRate = vid1.FrameRate;
open(outputVideo);
while hasFrame(vid1) && hasFrame(vid2)
img1 = readFrame(vid1);
img2 = readFrame(vid2);
imgt = horzcat(img1, img2);
% play video
step(videoPlayer, imgt);
% record new video
writeVideo(outputVideo, imgt);
end
release(videoPlayer);
close(outputVideo);
If you have two video clips with different frame rates and resolutions or you would like to join/cut pairs of video clips, use the code below.
For example: My dashcam is able to record video in the front and the rear of the car at the same time. But the front and rear videos come in separate files. I want to show them side by side as well as to join 6 files (3 pairs) into a single file.
%Read video
clc
clear
vidObj_f = VideoReader('video1.mp4');
FrameRate_f = vidObj_f.FrameRate;
vidObj_b = VideoReader('video2.mp4');
FrameRate_b = vidObj_b.FrameRate;
%New video
outputVideo = VideoWriter('combinedvideo.avi');
outputVideo.FrameRate = 24;
open(outputVideo);
skip = 95; %first seconds
j=skip*24;
try
while 1
front = read(vidObj_f,1+round(j*FrameRate_f*1/24));
back = read(vidObj_b,1+round(j*FrameRate_b*1/24));
front = imresize(front,[720 1280]);
videoframe = [front;back];
writeVideo(outputVideo, videoframe);
j = j+1;
end
catch
disp('...end 1');
end
vidObj_f = VideoReader('video3.mp4');
FrameRate_f = vidObj_f.FrameRate;
vidObj_b = VideoReader('video4.mp4');
FrameRate_b = vidObj_b.FrameRate;
skip = 0; %first seconds
j=skip*24;
try
while 1
front = read(vidObj_f,1+round(j*FrameRate_f*1/24));
back = read(vidObj_b,1+round(j*FrameRate_b*1/24));
front = imresize(front,[720 1280]);
videoframe = [front;back];
writeVideo(outputVideo, videoframe);
j = j+1;
end
catch
disp('...end 2');
end
vidObj_f = VideoReader('video5.mp4');
FrameRate_f = vidObj_f.FrameRate;
vidObj_b = VideoReader('video6.mp4');
FrameRate_b = vidObj_b.FrameRate;
skip = 0; %first seconds
j=skip*24;
cut = 30; %after playing 'cut' seconds
try
while 1
front = read(vidObj_f,1+round(j*FrameRate_f*1/24));
back = read(vidObj_b,1+round(j*FrameRate_b*1/24));
front = imresize(front,[720 1280]);
videoframe = [front;back];
writeVideo(outputVideo, videoframe);
if j>cut*24
disp('...end 3 (cut)');
break
end
j = j+1;
end
catch
disp('...end 3');
end
close(outputVideo);