How to split a binary file into different frames - matlab

So I have a quite big binary file that contains the information of about 70 video frames.
I read the binary file into MATLAB using the following
fid = fopen('data.binary');
B = fread(fid,'int64');
fclose(fid);
But then the variable B still contains a huge number of data. So I was wondering how can we split the variable B such that I can get data from one frame only one by one. Like let's say 30 FPS.
Is that even possible?
Thanks
PS: the pixel precision is uint8 and the Frame size 424X512. This is the code I am using:
fid = fopen('C:\KinectData\Depth\Depth_Raw_0.binary');
B = fread(fid,'uint8');
fclose(fid);
B = uint8(B);
Z = B(1:217088)
n = 424; % No. of columns of T
BB = reshape(Z, n,[]);
BB = uint8(BB);
imshow(BB)
But the picture isn't quite there yet.

OK, so we know a few things given your comments:
Each frame is 424 x 512
The precision of each element in your video is uint8
This is a grayscale video, so colour is not going to be considered
I'm going to assume your data is read in row major format. Bear in mind that MATLAB reads in data in column major format if you want to read in the data as a matrix, so you'll have to do a transpose operation, and ensure that you read the data into a transposed matrix first.
What I'm going to do is put each frame into a cell entry inside a cell array. The reason why I'm doing this is because we don't know how many frames are really in your sequence. You said "70 or so" frames, and since we don't know the exact number, we will dynamically populate the cell array as we go.
The code you have written will predominantly be the same, but we're going to run a while loop until what we read in from file is empty. In the while loop, we will read one frame at a time and store it into the cell array. I'll also make a counter that counts the number of frames we have to for later, and you'll see why. As such:
%// Open the file
fid = fopen('C:\KinectData\Depth\Depth_Raw_0.binary');
col = 424; %// Change if the dimensions are not proper
row = 512;
frames = {}; %// Empty cell array - Put frames in here
numFrames = 0; %// Let's record the number of frames too
while (true) %// Until we reach the end of the file:
B = fread(fin, [col row],'uint8=>uint8'); %// Read in one frame at a time
if (isempty(B)) %// If there are no more frames, get out
break;
end
frames{end+1} = B.'; %// Transpose to make row major and place in cell array
numFrames = numFrames + 1; %// Count frame
end
%// Close the file
fclose(fid);
As such, if you want to access the ith frame, you would simply do:
frm = frames{i};
As an additional bonus, you can play this as a movie in MATLAB. What we can do is preallocate a movie structure that is compatible to play the movie, then when you run the movie command, this will play the frames for you. Let's specify a frame rate of 10 fps, so that it will play slow enough to see the results. Therefore, when you're done do something like this:
%// Preallocate the movie structure array
movieFrames(numFrames) = struct('cdata',[],'colormap',[]);
for idx = 1 : numFrames
img = frames{idx};
movieFrames(idx) = im2frame(cat(3, img, img, img));
end
figure;
imshow(movieFrames(1).cdata); %// Show first frame to establish figure size
movie(movieFrames, 1, 10); %// Play the movie once at 10 FPS
Note that movies can only be played in colour, and so you would have to make your grayscale image artificially into colour. A colour frame is a 3D matrix, where each 2D slice tells you the amount of red, green or blue. For grayscale, each of these slices are the same, and so you would just replicate each grayscale frame for each slice. I used cat to make the grayscale frame into a 3D matrix. I also use im2frame to convert each image into a movie frame structure compatible to be played with movie.
Small caveat
I don't have access to your binary file, so this code is untested. Use at your own risk!

Related

How can I merge multiple images into one and save it on matlab?

I need to merge multiple bitmap of same sizes into one image.That image is basically rotated in different angles and needs to be merged into one whole image. I have tried multiple methods but I come with many issues as I am not able to save that image.
I have tried multiple codes but I actually cannot make sense out of it. What I want to achieve is transparent overlay (not sure) that superimposes two images and you can actually see both one image
figure1 = figure;
ax1 = axes('Parent',figure1);
ax2 = axes('Parent',figure1);
set(ax1,'Visible','off');
set(ax2,'Visible','off');
[a,map,alpha] = imread('E:\training data\0.bmp');
I = imshow(a,'Parent',ax2);
set(I,'AlphaData',alpha);
F = imshow('E:\training data\200.bmp','Parent',ax1);
I just want to superimpose multiple images.
This is my data set:
This is what I want to achieve, i want to add all of the rotated images and achieved into one
This is what I get sadly, I have tried everything
The following does kind of what you want. First load the image, then divide it into 6 equal blocks, and add these. To add the pixel values, I first converted the image to doubles, since uint8 only can go up to pixel values of 255. This would mean that you will just see a large bright spot in the image because you are clipping.
Then add all the blocks. You will see in the output, that the car is not always perfect in the center of the block, so depending on what you are trying to achieve you may want to align the blocks using something like xcorr2.
% load image
A = imread('S82CW.jpg');
fig = figure(1); clf
image(A);
% convert A to double and divide in blocks.
A = double(A);
[img_h, img_w, ~] = size(A);
block_h = img_h/2;
block_w = img_w/3;
% split image in blocks
Asplit = mat2cell(A, repelem(block_h,2), repelem(block_w,3), 3);
% check if splitting makes sense
figure(2); clf
for k = 1:numel(Asplit)
subplot(3,2,k)
image(uint8(Asplit{k}))
end
% superimpose all blocks,
A_super = zeros(size(Asplit{1,1}),'like',Asplit{1,1} ); % init array, make sure same datatype
for k = 1:numel(Asplit)
A_super = A_super + Asplit{k};
end
% divide by max value in A and multiply by 255 to make pixel
% values fit in uint8 (0-255)
A_super_unit8 = uint8(A_super/max(A_super,[],'all')*255);
figure(3); clf;
image(A_super_unit8)

How to find the variance of several images in MATLAB

I am relatively new to MATLAB and Image processing, so understand with me. I am working in experiment on image processing, and my current stage, I need to
1) read some images (about 100 images of same dimension)
2) store them in a variable (either cell array, vector or structure)
3) Find the variance of each pixel in each image
4) Form a new matrix to store each computed variance
Here is my code, but I am not sure it solves this problem not withstanding that I get result
clc;
im_File = dir('*.bmp');
files = {im_File.name};
for k=1:numel(files)
im{k} = imread(files{k});
%# Get the number of dimensions for your arrays
dim = ndims(im{k});
all_images = cat(dim+1,im{:});
% Use linear combine to acquire all the images
Linear_comb_im = imlincomb(1,all_images,'uin');
%get the variance of all images
computed_variance = var(double(Linear_comb_im),1,dim+1);
end
So it seems that you have a redundant variable here : both im and all_im basically save the same information. if the dimensions werent the same i would use a cell array, otherwise matlab likes matrices better.
In addition, I am not sure why you are performing the linear combination.
I would do the following:
clc;
im_File = dir('*.bmp');
files = {im_File.name};
for k=1:numel(files)
im(:,:,k) = imread(files{k}); % to save time you should initialize im begore the loop i.e. im = zeros(m,n,numerl(files)), where m,n are the size of the images
end
%get the variance of all images
computed_variance = var(double(im),1,3);
so im here is a 3D matrix containing the images in the 3rd dimension. In order to access the idx image:
im(:,:,idx)

Split up a binary image using their white boundaries in MATLAB

I'm trying to read the values in this image into variables using OCR in MATLAB. I'm having trouble doing so, so I tried to split up this image into smaller parts using the white boundary lines then trying to read it, but I dont know how to do this. Any help would be appreciated, thanks.
If the blocks are always delimited by a completely vertical line, you can find where they are by comparing the original image (here transformed from RGB to grayscale to be a single plane) to a matrix that is made of repeats of the first row of the original image only. Since the lines are vertical the intensity of the pixels in the first line will be the same throughout. This generates a binary mask that can be used in conjunction with a quick thresholding to reject those lines that are all black pixels in every row. Then invert this mask and use regionprops to locate the bounding box of each region. Then you can pull these out and do what you like.
If the lines dividing the blocks of text are not always vertical or constant intensity throughout then there's a bit more work that needs to be done to locate the dividing lines, but nothing that's impossible. Some example data would be good to have in that case, though.
img = imread('http://puu.sh/cU3Nj/b020b60f0b.png');
imshow(img);
imgGray = rgb2gray(img);
imgMatch = imgGray == repmat(imgGray(1,:), size(imgGray, 1), 1);
whiteLines = imgMatch & (imgGray > 0);
boxes = regionprops(~whiteLines, 'BoundingBox');
for k = 1:6
subplot(3,2,k)
boxHere = round(boxes(k).BoundingBox);
imshow(img(boxHere(2):(boxHere(2)+boxHere(4)-1), boxHere(1):(boxHere(1)+boxHere(3)-1), :));
end
You can sum along the columns of a binary image corresponding to that input image and find peaks from the sum values. This is precisely achieved in the code here -
img = imread('http://puu.sh/cU3Nj/b020b60f0b.png');
BW = im2bw(img,0.1); %// convert to a binary image with a low threshold
peak_sum_max = 30; %// max of sum of cols to act as threshold to decide as peak
peaks_min_width = 10; %// min distance between peaks i.e. min width of each part
idx = find( sum(BW,1)>=peak_sum_max );
split_idx = [1 idx( [true diff(idx)>peaks_min_width ] )];
split_imgs = arrayfun(#(x) img(:,split_idx(x):split_idx(x+1)),...
1:numel(split_idx)-1,'Uni',0);
%// Display split images
for iter = 1:numel(split_imgs)
figure,imshow(split_imgs{iter})
end
Please note that the final output split_imgs is a cell array with each cell holding image data for each split image.
If you would like to have the split images directly without the need for messing with cell arrays, after you have split_idx, you can do this -
%// Get and display split images
for iter = 1:numel(split_idx)-1
split_img = img(:,split_idx(iter):split_idx(iter+1));
figure,imshow(split_img)
end
There is now a built-in ocr function in the Computer Vision System Toolbox.

Change movie dimensions in matlab

I'm trying to display live video from an external camera using the function "movie" after performing a 2x binning. My original video size is 768x576. However, when I bin my pixels, I get a 384x288 image that, when it's displayed, will look half the size of my original video. Is there any way I can increase the displayed size of the movie such that it looks the same size as the original? In other words, my pixel would look twice the size.
I have tried using set(gca,'Position'...) but it doesn't change the size of my movie.
Any suggestion?
I'll use the example movie as found on the documentation.
Suppose you have a bunch of frames:
figure('Renderer','zbuffer')
Z = peaks;
surf(Z);
axis tight
set(gca,'NextPlot','replaceChildren');
% Preallocate the struct array for the struct returned by getframe
F(20) = struct('cdata',[],'colormap',[]);
% Record the movie
for j = 1:20
surf(.01+sin(2*pi*j/20)*Z,Z)
F(j) = getframe;
end
At the end of help movie, it says:
MOVIE(H,M,N,FPS,LOC) specifies the location to play the movie
at, relative to the lower-left corner of object H and in
pixels, regardless of the value of the object's Units property.
LOC = [X Y unused unused]. LOC is a 4-element position
vector, of which only the X and Y coordinates are used (the
movie plays back using the width and height in which it was
recorded).
Thus, there is no way to display the movie at a bigger size than at which is was recorded. You'll have to blow up the pixels to make it display at larger size:
% blow up the pixels
newCdata = cellfun(#(x) x(...
repmat(1:size(x,1),N,1), ... % like kron, but then
repmat(1:size(x,2), N,1), :), ... % a bit faster, and suited
{F.cdata}, 'UniformOutput', false); % for 3D arrays
% assign all new data back to the movie
[F.cdata] = newCdata{:};
% and play the resized movie
movie(F,10)
Note that this won't win any prizes for readability, so if you're going to use this, please include a comment describing what it does.

How to get matrices representing frames of videos in MATLAB?

I have an avi-video-file. I would like to represent a frame from this video as 3 matrices (because colors are parameterized by 3 number ([red,green,blue] or [hue,saturation,value] or something else).
At the moment I have this code:
videoObject = mmreader(fname);
imageData = read(videoObject, [1 5])
So, as far as I understand I extract the first 5 frames from the video. But I do not understand in what format the imageData is given. For example, how can I get the green component of the color of the pixel from the third frame located at the row number 17 and column number 32?
Can anybody, please, help me with that?
As far as I understand it can be done in the following way. A particular frame can be reached in this way:
% Take frame number 7:
imageData = read(videoObject, 7);
Now if we want to know the read, green, blue component of the pixel in the column 1 and row 2 we need to do that:
impixel(imageData,1,2)
It will return 3 numbers (RGB component of the color of the pixel).
The format for imageData returned from the function read is a 4-D array where your dimensions are (in order) frame height, frame width, image depth (3 for RGB images), and number of frames. So, to get the green component of the pixel in row 17 and column 32 of the third frame, you would simply do this:
greenValue = imageData(17,32,2,3);
One side note: mmreader will be removed in a future MATLAB release in favor of VideoReader.
vidObj1 = mmreader('testballroom_0.avi'); %# Create a video file object
nFrames = vidObj1.NumberOfFrames; %# Get the number of frames
vidHeight1 = vidObj1.Height; %# Get the image height
vidWidth1 = vidObj1.Width; %# Get the image width
%# Preallocate the structure array of movie frames:
mov1(1:nFrames) = struct('cdata',zeros(vidHeight1,vidWidth1,3,'uint8'),...
'colormap',[]); %# Note that colormap is empty!
You can access the frames from mov1 :)