how to select specific frames from a video in MATLAB? - image

I am working on a project about lip recognition and I have to read a recorded a video at a frame rate of 30 fps so, if I have 70 frames I need just to acquire or select a representative frame every 8 frames as the shortest video which has number of frames in the data set is of 16 frames but my problem is to adjust the for loop every 8 frames,and it can't read any frame is the problem about the video reader??so,please if you have any idea I would be grateful
thanks,,
v = VideoReader('1 - 1.avi');
s = floor((size(v,4))/8);
for t =1:s:size(v,4)
img = read(s,i);
y = imresize(img,[100,120];

I would take the example for VideoReader and modify the code to explain -
%%// Paramters
sampling_factor = 8;
resizing_params = [100 120];
%%// Input video
xyloObj = VideoReader('xylophone.mpg');
%%// Setup other parameters
nFrames = floor(xyloObj.NumberOfFrame/sampling_factor); %%// xyloObj.NumberOfFrames;
vidHeight = resizing_params(1); %// xyloObj.Height;
vidWidth = resizing_params(1); %// xyloObj.Width;
%// Preallocate movie structure.
mov(1:nFrames) = struct('cdata', zeros(vidHeight, vidWidth, 3, 'uint8'),'colormap',[]);
%// Read one frame at a time.
for k = 1 :nFrames
IMG = read(xyloObj, (k-1)*sampling_factor+1);
%// IMG = some_operation(IMG);
mov(k).cdata = imresize(IMG,[vidHeight vidWidth]);
end
%// Size a figure based on the video's width and height.
hf = figure;
set(hf, 'position', [150 150 vidWidth vidHeight])
%// Play back the movie once at the video's frame rate.
movie(hf, mov, 1, xyloObj.FrameRate);
Basically the only change I have made are for 'nFrames' and the other factors revolving around it. Try changing the 'sampling_factor' and see if that makes sense . Also, I have added the image resizing that you are performing at the end of your code.

you can achieve this task by reading frames from video and store it in cell array. From cell array , you can easily read whatever frame you want by customizing for loop as follows.
for i=1:8:n
frame = cell{i};
process(frame)
end
cell: it contains all frames in video
process: it is a function to perform your task
n: number of frames in video
If you want to get more information for reading frames from video and store into cell array, visit the following link:
https://naveenideas.blogspot.in/2016/07/reading-frames-from-video.html

Related

FFMPEG Determine average color of an area of a video

I have a use case where I'd want to insert one of two watermarks - one designed for a dark-ish background, the other for a light background into a video. Let's say that I'd want to do this on the top right corner of the video.
How do I determine the average color of the top right section of the video? Post this, how do I determine which watermark to use by looking at the average color?
I have a solution right now where I am taking equally spaced screenshots and then measuring the average color, but it's excruciatingly slow, especially for longer videos.
# Calculate average color
black_distances = []
white_distances = []
movie = FFMPEG::Movie.new(video_file)
(0..movie.duration / 10).each do |second|
# extract a frame
filename = "tmp/watermark/#{SecureRandom.uuid}.jpg"
movie.screenshot filename.to_s, seek_time: second
# analyse frame for color distance
frame = MiniMagick::Image.open(filename)
frame.crop('20%x20%+80%+0')
frame.resize('1x1')
pixel = frame.get_pixels.flatten
distance_from_black = Math.sqrt(((black[0] - pixel[0])**2 + (black[1] - pixel[1])**2 + (black[2] - pixel[2])**2))
distance_from_white = Math.sqrt(((white[0] - pixel[0])**2 + (white[1] - pixel[1])**2 + (white[2] - pixel[2])**2))
black_distances.push distance_from_black
white_distances.push distance_from_white
File.delete(filename) if File.exist?(filename)
end
average_black_distance = black_distances.reduce(:+).to_f / black_distances.size
average_white_distance = white_distances.reduce(:+).to_f / white_distances.size
I am also confused about how to use the resulting average_black_distance and average_white_distance to determine which watermark to use.
I was able to make this faster by doing the following:
Taking screenshots using a single ffmpeg command, instead of iterating over movie.length and taking an individual shot every x seconds.
Cropping and scaling the screenshot in the same ffmpeg command, instead of doing that with MiniMagick.
Deleting with rm_rf instead of doing so inside the loop.
# Create folder for screenshots
foldername = "tmp/watermark/screenshots/#{medium.id}/"
FileUtils.mkdir_p foldername
# Take screenshots
movie = FFMPEG::Movie.new(video_file)
`ffmpeg -i #{video_file} -f image2 -vf fps=fps=0.2,crop=in_w/6:in_h/14:0:0,scale=1:1 #{foldername}/out%d.png`
# Calculate distances
white = Color .new('#ffffff')
black = Color .new('#000000')
distances = []
Dir.foreach foldername do |f|
next if %w[. .. .DS_Store].include? f
f = MiniMagick::Image.open(foldername + f)
color = f.get_pixels.flatten
distance_from_black = Color.new(color).color_distance(white)
distance_from_white = Color.new(color).color_distance(black)
distances.push distance_from_white - distance_from_black
end
If the value of distances.inject(0, :+) is positive, the video area captured is on the brighter side. Thanks to #Aetherus!

MATLAB: How to change pixel values after using VideoReader

I'm trying to read a video file using VideoReader and change some pixel values and save it back to the video file. I can easily change the matrix values but how do I save it back into the video file?
obj = VideoReader('DemoClip.asf');
imageData = read(obj);
imageData(17,32,:) = 65;
Here is a way to do it using videoWriter. The code is commented; if something is unclear please ask. I used the demo xylophone.mp4 file from Mathworks.
clear
clc
close all
xyloObj = VideoReader('xylophone.mp4');
imageData = read(xyloObj);
%// Open writer object
writerObj = VideoWriter('NewVideo.avi');
open(writerObj);
%// Show 1st frame
hIm = imshow(imageData(:,:,:,1));
for k = 1:size(imageData,4)
%// Change pixel values
imageData(1:200,1:200,:,k) = uint8(0);
%// Refresh cdata property. Faster than calling repetitevely imshow
set(hIm,'CData',imageData(:,:,:,k));
drawnow
frame = getframe;
%// Write to video file
writeVideo(writerObj,frame);
end
close(writerObj);
Sample frame of the resulting video:

Motion History Image (MHI) in Matlab

My project is to detect human activity through stored video clips.
I am successfully able to do the following:
Get the Motion History Image (MHI) from a video using OpenCV
Train and classify the set of images using Matlab
However, I want to use Matlab in order to get the Motion History Image (MHI). Is it possible, and if yes can someone guide me? Thank you.
I have attached a sample Motion History Image (MHI)
I have used the following code for MHI:
http://www.ece.iastate.edu/~alexs/classes/2007_Fall_401/code/09_MotionHistory/motempl.c
MHI is just a ways of implementing motion detection (and uses silhouettes as the basis of it).
Let suppose that the silhouette of the most recent object has been created. It also uses a timestamp to identify if the current silhouette is recent or not. The older silhouettes have to be compared with the current silhouette in order to achieve movement detection. Hence, earlier silhouettes are also saved in the image, with an earlier timestamp.
MHI describes the changes of some moving objects over the image sequence. Basically, you should only maintain an image where every pixel encodes a time information - whether the silhouette is recent or not or where the movement occurs at a given time.
Therefore the implementation of MHI is very simple e.g.:
function MHI = MHI(fg)
% Initialize the output, MHI a.k.a. H(x,y,t,T)
MHI = fg;
% Define MHI parameter T
T = 15; % # of frames being considered; maximal value of MHI.
% Load the first frame
frame1 = fg{1};
% Get dimensions of the frames
[y_max x_max] = size(frame1);
% Compute H(x,y,1,T) (the first MHI)
MHI{1} = fg{1} .* T;
% Start global loop for each frame
for frameIndex = 2:length(fg)
%Load current frame from image cell
frame = fg{frameIndex};
% Begin looping through each point
for y = 1:y_max
for x = 1:x_max
if (frame(y,x) == 255)
MHI{frameIndex}(y,x) = T;
else
if (MHI{frameIndex-1}(y,x) > 1)
MHI{frameIndex}(y,x) = MHI{frameIndex-1}(y,x) - 1;
else
MHI{frameIndex}(y,x) = 0;
end
end
end
end
end
Code from: https://searchcode.com/codesearch/view/8509149/
Update #1:
Try to draw it as follows:
% showMHI.m
% Input frame number and motion history vector to display normalized MHI
% at the specified frame.
function showMHI(n, motion_history)
frameDisp = motion_history{n};
frameDisp = double(frameDisp);
frameDisp = frameDisp ./ 15;
figure, imshow(frameDisp)
title('MHI Image');

Change Range Of Displayed Pixel Values from Command Line?

I'm working with some MRI data in Matlab 2014b, but the data is formed of intensity values not RGB. To get around this I use the code below to form a movie out of the MRI frames (I'm working on dynamic data here)
My problem is that the images need to have altered display values for the pixels, as the default only displays between -Inf and Inf, and I need between 0 and 0.25 to get a sensible image out of my data.
Are there any ways to pass that change from the script in to the movie, and then to write to file? I can only seem to do this per image in implay, and I'd like an automated way to edit each image and then store as a frame for a movie..?
%Code for producing movie.
graymap = gray(256);
for i = 1:32
a(:,:,i) = cmunique(Reformed_Data_Colourmap(:,:,i));
end
for i = 1:32
b = im2frame(a(:,:,i),graymap);
a(:,:,1) = ((b.cdata));
image(a(:,:,1))
colormap 'gray'
%The change needs to be here, to display pixel values from 0 to 0.25, to allow for a sensible image from the MR data.
frames(1,i) = getframe;
end
movie(frames)
The solution is provided:
for i = 1:32
b = im2frame(a(:,:,i),graymap);
a(:,:,1) = ((b.cdata));
clims = [0 250];
%image(a(:,:,1),clims)
colormap 'gray'
imagesc(a(:,:,1),clims);
%set('window', [0 400])
frames(1,i) = getframe;
end
clims solves the issue.

Create real-time anaglyph video matlab

I currently have this code which overlays two images, however it is only in semi-realtime.
Can anyone point me in the right direction as to how to create live anaglyph preview in matlab. Thanks
clear all
close all
clc;
vid = videoinput('winvideo',1, 'YUY2_640x480');
vid1 = videoinput('winvideo',2, 'YUY2_640x480');
% to convert to rgb colors
vid.ReturnedColorSpace = 'rgb';
vid1.ReturnedColorSpace = 'rgb';
set(vid,'FramesPerTrigger',1);
set(vid1,'FramesPerTrigger',1);
% set(vid, 'TriggerRepeat',inf);
% set(vid1, 'TriggerRepeat',inf);
while (1)
start(vid);
start(vid1);
%retrieves all the frames acquired at the last trigger
data = getdata(vid);
data1 = getdata(vid1);
% processes the color channels of the videos
data(:,:,1)=0;
data(:,:,2)=0;
data1(:,:,2)=0;
data1(:,:,3)=0;
%to display them in one video
result=data+data1;
imshow(result);
drawnow;
end
stop(vid),delete(vid),clear vid;

Resources