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

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,:)=[....

Related

How to provide input to BagOfFeatures() function in MATLAB in the form of imageSet or imageDataStore?

I want to use bagOfFeatures() function of MATLAB. But it requires input in the form of imageSet or imageDataStore. The code I want to run is given below:
Dataset = 'D:\dsktop\kinect_leap_dataset\acquisitions';
thresh1 = 0;
thresh2 = 20;
k = dir(fullfile(Dataset,'\P*\G*\*_depth.png'));
kf = {k(~[k.isdir]).folder};
kn = {k(~[k.isdir]).name};
for j=1:length(k)
% Applying thresholding to the original image
full_name = horzcat(kf{j},filesep,kn{j});
image = imread(full_name);
image_bin1 = (image < thresh2);
image_bin2 = (thresh1 < image);
image_bin = abs(image_bin2- image_bin1);
sequence{i} = image_bin;
end
% Bag of Features
bag = bagOfFeatures(sequence);
But the "sequence" is a cell class and so bagOfFeatures() is giving me errors. So I tried this:
Dataset = 'D:\dsktop\kinect_leap_dataset\acquisitions';
imgFolder = fullfile(Dataset);
imgSets = imageSet(imgFolder, 'recursive');
imgSets.Description
But now the problem is how to do the processing (thresholding) on images saved in imgSets. Also, after processing how to save all the "image_bin" images in imageSet class so that I can give them as input to the BagOfFeatures() function.
I solved this problem myself. To give input as an imageSet or imageStrore to BagOfFeatures(), we have to store all the "image_bin" images in a folder in PC.
For that, we have to create that folder in the desired location as
mkdir D:\.............\cropped
Then, we have to save the "image_bin" in that folder in a loop as
file_name = sprintf('D:/............/cropped/image_bin_%d.png',j);
imwrite(image_bin, file_name);
Then, the data from above folder is read in MATLAB memory as
imds = imageDatastore('D:/.............../cropped', 'Labels', label);
% label is an array of labels made by the user
[trainingSet, validationSet] = splitEachLabel(imds, 0.3, 'randomize');
% Bag of Features
bag = bagOfFeatures(trainingSet);
And It's done.

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.

Sorting several functions in one function

I have a function where I'm receiving input data and other data from four random sources. This function must be repeated for 12 times and 12 should be set so that. This function should also be repeated 10 times. Is there a more compact way to perform what I'm doing below?
for ii=1:10
Percent=0.7;
num_points1 = size(X_1,1);
split_point1 = round(num_points1*Percent);
sequence1 = randperm(num_points1);
X1_train{ii} = X_1(sequence1(1:split_point1),:);
Y1_train{ii} = Y_1(sequence1(1:split_point1));
X1_test{ii} = X_1(sequence1(split_point1+1:end),:);
Y1_test{ii}= Y_1(sequence1(split_point1+1:end));
num_points2 = size(X_2,1);
split_point2 = round(num_points2*Percent);
sequence2 = randperm(num_points2);
X2_train{ii} = X_2(sequence2(1:split_point2),:);
Y2_train{ii} = Y_2(sequence2(1:split_point2));
X2_test{ii} = X_2(sequence2(split_point2+1:end),:);
Y2_test{ii}= Y_2(sequence2(split_point2+1:end));
.
.
.
.
num_points12 = size(X_12,1);
split_point12 = round(num_points12*Percent);
sequence12 = randperm(num_points12);
X12_train{ii} = X_12(sequence12(1:split_point12),:);
Y12_train{ii} = Y_12(sequence12(1:split_point12));
X12_test{ii} = X_12(sequence12(split_point12+1:end),:);
Y12_test{ii}= Y_12(sequence12(split_point12+1:end));
end
The biggest problem you have currently is that you have 12 separate variables to do 12 related operations. Don't do that. Consolidate all of the variables into one container then iterate over the container.
I have the following suggestions for you:
Combine X_1, X_2, ... X_12 into one container. A cell array or structure may be prudent to use here. I'm going to use cell arrays in this case as your code currently employs them and it's probably the easiest thing for you to transition to.
Create four master cell arrays for the training and test set data and labels and within each cell array are nested cell arrays that contain each trial.
Loop over the cell array created in step #1 and assign the results to each of the four master cell arrays.
Therefore, something like this comes to mind:
X = {X_1, X_2, X_3, X_4, X_5, X_6, X_7, X_8, X_9, X_10, X_11, X_12};
Y = {Y_1, Y_2, Y_3, Y_4, Y_5, Y_6, Y_7, Y_8, Y_9, Y_10, Y_11, Y_12};
N = numel(X);
num_iterations = 10;
X_train = cell(1, num_iterations);
Y_train = cell(1, num_iterations);
X_test = cell(1, num_iterations);
Y_test = cell(1, num_iterations);
Percent = 0.7;
for ii = 1 : num_iterations
for jj = 1 : N
vals = X{jj};
labels = Y{jj};
num_points = size(vals,1);
split_point = round(num_points*Percent);
sequence = randperm(num_points);
X_train{ii}{jj} = vals(sequence(1:split_point),:);
Y_train{ii}{jj} = labels(sequence(1:split_point));
X_test{ii}{jj} = vals(sequence(split_point+1:end),:);
Y_test{ii}{jj} = labels(sequence(split_point+1:end));
end
end
As such, to access the training data for a particular iteration, you would do:
data = X_train{ii};
ii is the iteration you want to access. data would now be a cell array, so if you want to access the training data for a particular group, you would now do:
group = data{jj};
jj is the group you want to access. However, you can combine this into one step by:
group = X_train{ii}{jj};
You'll see this syntax in various parts of the code I wrote above. You'd do the same for the other data in your code (X_test, Y_train, Y_test).
I think you'll agree that this is more compact and to the point.

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

N-th largest component of bwconncomp including the background

My question has two parts. First one is:
How can I include the background as a component in the bwconncomp function, because it's default behavior doesn't include it.
Also, and this is my other question is, how can I select the n-th largest component based on what I get by using bwconncomp.
Currently I was thinking about something like this, but that doesn't work :P
function out = getComponent(im,n)
CC = bwconncomp(im,4);
%image is an binary image here
numPixels = cellfun(#numel,CC.PixelIdxList);
sortedPixels = sort(numPixels,'descend');
w = sortedPixels(n);
[largest, index] = find(numPixels==w);
im(CC.PixelIdxList{index}) = 0;
out = im;
But that doesn't work at all. But im not too sure what the CC.PixelIdxList{index} does, is it just changing elements in the array. I also find it kinda vague what exactly PixelIdxList is.
To find the background, you can use 'not' operation on the image
'PixelIdxList' is not what you need. You need the 'Area' property.
function FindBackgroundAndLargestBlob
x = imread('peppers.png');
I = x(:,:,2);
level = graythresh(I);
bw = im2bw(I,level);
b = bwlabel(bw,8);
rp = regionprops(b,'Area','PixelIdxList');
areas = [rp.Area];
[unused,indexOfMax] = max(areas);
disp(indexOfMax);
end
Update:
You can do it with bwconncomp as well:
function FindBackgroundAndLargestBlob
x = imread('peppers.png');
I = x(:,:,2);
level = graythresh(I);
bw = im2bw(I,level);
c = bwconncomp(bw,4);
numOfPixels = cellfun(#numel,c.PixelIdxList);
[unused,indexOfMax] = max(numOfPixels);
figure;imshow(bw);
bw( c.PixelIdxList{indexOfMax} ) = 0;
figure;imshow(bw);
end
Which will give the following results: