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:
Related
I am trying to properly convert a RAW image so that I can view it in MATLAB. Image can be downloaded here. I am using the version of the code provided in How can I read in a RAW image in MATLAB?
However, it is not working properly for me. Here is my slightly modified version below:
clear;
row=966; col=1296;
fin=fopen('C:\Users\user\Desktop\test2.raw','r');
I=fread(fin, col*row*3,'uint8=>uint8'); %// Read in as a single byte stream
I = reshape(I, [col row 3]); %// Reshape so that it's a 3D matrix - Note that this is column major
Ifinal = flipdim(imrotate(I, -90),2); % // The clever transpose
imshow(Ifinal);
fclose(fin); %// Close the file
What I get:
What I should get:
I'm not sure why it's not working for me but if I use an imaging program (ImageJ) I can correctly convert the RAW file if I select Image type as '24-bit BGR'. The pixel format of the image is 8 Bit BAYRG.
There you go:
function q43127920
row=966; col=1296;
fin=fopen('test.raw','r');
I = fread(fin, col*row*3,'ubit24=>uint32');
I = reshape(I, col, row, []);
B = uint8(bitand(bitshift(I,-00),uint32(255)));
G = uint8(bitand(bitshift(I,-08),uint32(255)));
R = uint8(bitand(bitshift(I,-16),uint32(255)));
I = cat(3,R,G,B);
Ifinal = flip(imrotate(I, -90),2);
imagesc(Ifinal);
fclose(fin);
Result:
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.
I have a 3 dimension matrix of data (a stack of images across a dimension, time for example.
I want to display an image, and have a slider below to navigate across the images.
I wrote a piece of code which works, but it's bulky and kinda ugly I think...I want to write a clean function and so I would like to know if anyone know of a cleaner, nicer way to do it.
Here is my code:
interv = [min max]; % interval for image visualization
imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv);
title('My Title');
xlabel('X (cm)');
ylabel('Y (cm)');
pos = get(gca,'position');
% slider position
Newpos = [pos(1) pos(2)-0.1 pos(3) 0.05];
pp = 1;
% callback slider
S = ['pp=floor(get(gcbo,''value''));imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv));' ...
'set_axes_elasto;title(''My Title'');disp(pp);'];
Mz = size(MyMatrix,3);
% Creating Uicontrol
h = uicontrol('style','slider',...
'units','normalized',...
'position',Newpos,...
'callback',S,...
'min',1,'max',Mz,...
'value',pp,...
'sliderstep',[1/(Mz-1) 10/(Mz-1)]);
Here is a way to do it using a listener object for smooth visualization of your stack. I made up a dummy stack using grayscale variations of the same image (i.e. only 4 frames) but the principle will be the same for your application. Notice that I use imshow to display the images, but using imagesc as you do won't cause any problem.
The code is commented so hopefully this is clear enough. If not please don't hesitate to ask for help!
Code:
function SliderDemo
clc
clear all
NumFrames = 4; %// Check below for dummy 4D matrix/image sequence
hFig = figure('Position',[100 100 500 500],'Units','normalized');
handles.axes1 = axes('Units','normalized','Position',[.2 .2 .6 .6]);
%// Create slider and listener object for smooth visualization
handles.SliderFrame = uicontrol('Style','slider','Position',[60 20 400 50],'Min',1,'Max',NumFrames,'Value',1,'SliderStep',[1/NumFrames 2/NumFrames],'Callback',#XSliderCallback);
handles.SliderxListener = addlistener(handles.SliderFrame,'Value','PostSet',#(s,e) XListenerCallBack);
handles.Text1 = uicontrol('Style','Text','Position',[180 420 60 30],'String','Current frame');
handles.Edit1 = uicontrol('Style','Edit','Position',[250 420 100 30],'String','1');
%// Create dummy image sequence, here 4D sequence of grayscale images.
MyImage = imread('peppers.png');
MyMatrix = cat(4,rgb2gray(MyImage),MyImage(:,:,1),MyImage(:,:,2),MyImage(:,:,3));
%// Use setappdata to store the image stack and in callbacks, use getappdata to retrieve it and use it. Check the docs for the calling syntax.
setappdata(hFig,'MyMatrix',MyMatrix); %// You could use %//setappdata(0,'MyMatrix',MyMatrix) to store in the base workspace.
%// Display 1st frame
imshow(MyMatrix(:,:,:,1))
%// IMPORTANT. Update handles structure.
guidata(hFig,handles);
%// Listener callback, executed when you drag the slider.
function XListenerCallBack
%// Retrieve handles structure. Used to let MATLAB recognize the
%// edit box, slider and all UI components.
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
%// Get current frame
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
%// Display appropriate frame.
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
%// Slider callback; executed when the slider is release or you press
%// the arrows.
function XSliderCallback(~,~)
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
end
The figure looks like this:
Hope that helps!
I am writing a function that generates a movie mimicking a particle in a fluid. The movie is coloured and I would like to generate a grayscaled movie for the start. Right now I am using avifile instead of videowriter. Any help on changing this code to get grayscale movie? Thanks in advance.
close all;
clear variables;
colormap('gray');
vidObj=avifile('movie.avi');
for i=1:N
[nx,ny]=coordinates(Lx,Ly,Nx,Ny,[x(i),-y(i)]);
[xf,yf]=ndgrid(nx,ny);
zf=zeros(size(xf))+z(i);
% generate a frame here
[E,H]=nfmie(an,bn,xf,yf,zf,rad,ns,nm,lambda,tf_flag,cc_flag);
Ecc=sqrt(real(E(:,:,1)).^2+real(E(:,:,2)).^2+real(E(:,:,3)).^2+imag(E(:,:,1)).^2+imag(E(:,:,2)).^2+imag(E(:,:,3)).^2);
clf
imagesc(nx/rad,ny/rad,Ecc);
writetif(Ecc,i);
if i==1
cl=caxis;
else
caxis(cl)
end
axis image;
axis off;
frame=getframe(gca);
cdata_size = size(frame.cdata);
data = uint8(zeros(ceil(cdata_size(1)/4)*4,ceil(cdata_size(2)/4)*4,3));
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
frame.cdata = data;
vidObj = addframe(vidObj,frame);
end
vidObj = close(vidObj);
For your frame data, use rgb2gray to convert a colour frame into its grayscale counterpart. As such, change this line:
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
To these two lines:
frameGray = rgb2gray(frame.cdata);
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = ...
cat(3,frameGray,frameGray,frameGray);
The first line of the new code will convert your colour frame into a single channel grayscale image. In colour, grayscale images have all of the same values for all of the channels, which is why for the second line, cat(3,frameGray,frameGray,frameGray); is being called. This stacks three copies of the grayscale image on top of each other as a 3D matrix and you can then write this frame to your file.
You need to do this stacking because when writing a frame to file using VideoWriter, the frame must be colour (a.k.a. a 3D matrix). As such, the only workaround you have if you want to write a grayscale frame to the file is to replicate the grayscale image into each of the red, green and blue channels to create its colour equivalent.
BTW, cdata_size(3) will always be 3, as getframe's cdata structure always returns a 3D matrix.
Good luck!
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