N-th largest component of bwconncomp including the background - matlab

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:

Related

UI in Matlab to get inputs to be used in a script

I am trying to create a GUI for my script in Matlab. At the moment I am opening this dialog boxes in my script to get the inputs I need.
prompt = {'Mass [kg]:','Power [kW]:','Drag Coeff:','Lift Coeff:','Area Front [m^2]:'};
dlgtitle = 'Vehicle Parameters';
dims = [1 35];
definput = {'752','650','1','3','1'};
vehicle = inputdlg(prompt,dlgtitle,dims,definput);
prompt = {'Friction Coeff:','Air Density [kg/m^3]:'};
dlgtitle = 'External Parameters';
dims = [1 35];
definput = {'1.4','1.19'};
ambient = inputdlg(prompt,dlgtitle,dims,definput);
prompt = {'Length [m]:','Corner Radius [m]:'};
dlgtitle = 'Track Parameters';
dims = [1 35];
definput = {'1000','150'};
track = inputdlg(prompt,dlgtitle,dims,definput);
Here the code continues
laptime = formula used to get the laptime;
However I would like to create something similar to what this image shows, where I can write the parameters, push the run button to run the script and get the laptime printed. Any suggestions on how I could achieve it?
Thanks a lot in advance!
steeven:
From inspecting your image, you essentially will need:
A figure object.
Ten(10) field objects.
Ten(10) Static text objects.
A pushbutton object
A callback function.
Here's a sample script:
clc
clear
close all %Very important when making GUI's in MATLAB!
%figure object that contains GUI.
f = figure('units','normalized');
%Uicontrols devoted to static text:
m_text = uicontrol('Parent',f,'units','normalized','Style','Text');
P_text = uicontrol('Parent',f,'units','normalized','Style','Text');
FS_text = uicontrol('Parent',f,'units','normalized','Style','Text');
CD_text = uicontrol('Parent',f,'units','normalized','Style','Text');
CL_text = uicontrol('Parent',f,'units','normalized','Style','Text');
CF_text = uicontrol('Parent',f,'units','normalized','Style','Text');
rho_text = uicontrol('Parent',f,'units','normalized','Style','Text');
len_text = uicontrol('Parent',f,'units','normalized','Style','Text');
rad_text = uicontrol('Parent',f,'units','normalized','Style','Text');
%Uicontrols devoted to editable fields:
m_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
P_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
FS_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
CD_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
CL_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
CF_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
rho_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
len_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
rad_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
% MLG Cell array strat.
ui_texts = {m_text,P_text,FS_text,CD_text,CL_text,CF_text,rho_text,...
len_text,rad_text};
strings = {'mass','power','Front Section','Drag Coefficient',...
'Lift Coefficient','Friction Coefficient','Air Density','Length',...
'Radius'};
ui_edits = {m_edit,P_edit,FS_edit,CD_edit,CL_edit,CF_edit,rho_edit,...
len_edit,rad_edit};
defaults = {'10','100','0.5','0.05','1.2','0.0005','1.225','5','3'};
xi = 0.05; %X-coordinate of Bottom-Left corner.
yi = 0.85; %Y-coordinate of Bottom-Left corner.
width = 0.15; %Width of object.
height = 0.075; %Height of object
deltaH = 0.3; %Horizontal Spacing between objects.
deltaV = -0.25; %Vertical Spacing between objects.
offset = 0.15;
rows = 3; %Number of rows.
cols = 3; %Number of columns.
k = 0; % Counter for number of uicontrols that populate grid pattern.
for i = 1:rows
for j = 1:cols
k = k + 1;
if k <= length(ui_texts)
x = xi + deltaH*(j-1);
y = yi + deltaV*(i-1);
xo = x + offset; %horizontally offset the editable field.
set(ui_texts{k},'Position',[x, y, width, height],'String',strings{k})
set(ui_edits{k},'Position',[xo, y, width, height],'String',defaults{k})
end
end
end
%Uicontrol for output object:
out = uicontrol('Parent',f,'Style','text','units','normalized',...
'position',[xo-deltaH,y+deltaV,width,height],'String','Val = ');
%Uicontrol for button execution:
exe = uicontrol('Parent',f,'Style','pushbutton','units','normalized',...
'position',[xo-2*deltaH,y+deltaV,width,height],'String','Calculate',...
'Callback',{#computations,ui_edits,out});
%Function executed by the "exe" uicontrol.
function computations(obj,~,ui_edits,out)
no_inputs = length(ui_edits);
summation = 0;
for i = 1:no_inputs
in = get(ui_edits{i},'String');
val = str2double(in);
summation = summation +val;
end
set(out,'String',['Val = ',num2str(summation)])
end
The above script produces:
Here's the gist:
The figure is a graphical object needed to contain the editable fields and text descriptions.
The fields are objects that enable user input (These are uicontrol objects).
The static texts establish to the user the correspondence between field and input (These are also uicontrol objects).
The button is an object that executes the callback function (also a uicontrol).
The callback function is a user-defined function that collects inputs from uicontrol objects and uses them to run code.
In this example, the "calculate" button simply sums up all the numeric values of the inputs. For your applications, you must modify the programmer-defined function at the end to suit your needs.
This kind of GUI lets users input information as strings. Said information must be converted from the string type to the double type. Other GUI objects allow for direct numerical inputs (such as sliders or buttons with underlying logical structure, ie. "if this button, then this value"). When working with editable fields, the programmer must be conscious that the inputs are strings until run through a function like str2double.
Other nuances with GUI's:
Every object that the programmer intends to be interactive must have an associated programmer-defined function.
In this case, the only interactive object is the button.
Personally, my biggest challenge when making MATLAB GUI's is dealing with the positioning of the UI controls. I have used a few for loops and cell arrays to generate the grid pattern for the texts and buttons. This is quality of life on my part, more elaborate GUI's may require more sophisticated coding.
MATLAB has a feature called "GUIDE" which helps automate the uicontrol generation. This is worth a try if the programatic method I have shared is too tedious.

How to draw Venn Diagram on MATLAB?

I have to plot some Venn diagrams to show intersections between arrays of strings. Let me explain: I have a category of names that includes three others that do not intersect each other. I want to understand which of these three occupies the largest percentage of the macro-category mentioned above. I would like to do it with MATLAB but I see that this development environment is somewhat devoid of such functions. If you have any ideas in mind I would be grateful.
Thanks in advance!
Venn Diagrams by Plotting Circles
Not the most elegant way but one method of plotting a Venn diagram can be plotting circles and filling the individual circles using a text() annotation/label. Unfortunately, here I manually placed where the labels are centred. Automating the label positioning may take several additional steps which I will leave out for simplicity. To find the intersections of the respective datasets I simply used the intersect() function.
A = {'A','B','C','D','E','F','G','H','I','L'};
B = {'A','B','C','D'};
C = {'E','F','G','H','I','L'};
%Finding the intersections of the arrays%
Intersection_AB = intersect(A,B);
fprintf("Intersection AB: ")
disp(Intersection_AB);
fprintf("\n");
Intersection_BC = intersect(B,C);
fprintf("Intersection BC: ")
disp(Intersection_BC);
fprintf("\n");
Intersection_AC = intersect(A,C);
fprintf("Intersection AC: ")
disp(Intersection_AC);
fprintf("\n");
Intersection_ABC = intersect(Intersection_AB,C);
fprintf("Intersection ABC: ")
disp(Intersection_ABC);
fprintf("\n");
clc;
clf;
Plotting_Interval = 0.01;
Angles_In_Radians = (0: Plotting_Interval: 2*pi);
Circle_Plot = #(X_Offset,Y_Offset,Radius) plot(X_Offset + Radius*cos(Angles_In_Radians),Y_Offset + Radius*sin(Angles_In_Radians));
hold on
%Plotting the 3 circles%
X_Offset_A = 0; Y_Offset_A = 2; Radius_A = 3;
Circle_A = Circle_Plot(X_Offset_A,Y_Offset_A,Radius_A);
fill(Circle_A.XData, Circle_A.YData,'r','FaceAlpha',0.2,'LineWidth',1);
X_Offset_B = -2; Y_Offset_B = -2; Radius_B = 3;
Circle_B = Circle_Plot(X_Offset_B,Y_Offset_B,Radius_B);
fill(Circle_B.XData, Circle_B.YData,'g','FaceAlpha',0.2,'LineWidth',1);
X_Offset_C = 2; Y_Offset_C = -2; Radius_C = 3;
Circle_Plot(X_Offset_C,Y_Offset_C,Radius_C);
Circle_C = Circle_Plot(X_Offset_C,Y_Offset_C,Radius_C);
fill(Circle_C.XData, Circle_C.YData,'b','FaceAlpha',0.2,'LineWidth',1);
title("Venn Diagram");
%Writing all the labels%
A_Label = strjoin(string(A));
text(X_Offset_A,Y_Offset_A,A_Label,'color','r');
B_Label = strjoin(string(B));
text(X_Offset_B,Y_Offset_B,B_Label,'color','g');
C_Label = strjoin(string(C));
text(X_Offset_C,Y_Offset_C,C_Label,'color','b');
AB_Label = strjoin(string(Intersection_AB));
text(-1.2,0,AB_Label);
BC_Label = strjoin(string(Intersection_BC));
text(0,-2,BC_Label);
AC_Label = strjoin(string(Intersection_AC));
text(1.2,0,AC_Label);
ABC_Label = strjoin(string(Intersection_ABC));
text(0,0,ABC_Label);
%Setting the labels to be relative to the centres%
set(findall(gcf,'type','text'),'HorizontalAlignment','center');
axis equal
axis off
Ran using MATLAB R2019b

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.

MATLAB combine two avi. together

I created two avi. file and they have the same length.
I wanted to combine them on a same background and one on top another one on the bottom.
The code I used for one of the animation is below, the other one is similar.
Is there any way I can do that?
load Results.mat;
I = imread('hex08.jpg');
[rows,columns,numberOfColorChannels] = size(I);
if numberOfColorChannels >1
I = I(:,:,2);
end
background = imresize(background, [rows,columns]);
figure(1);
hold on;
for i=1:500
A=angle(i,:);
J = imrotate(I,A,'crop');
mask = J == 0;
mask = bwareafilt(mask,4);
J(mask) = background(mask);
pause(0.01)
imshow(J);
imwrite(J,[num2str(i),'.png']);
end
imageNames = dir(fullfile('*.png'));
imageNames = {imageNames.name}';
outputVideo = VideoWriter(fullfile('hex08.avi'));
outputVideo.FrameRate = 15;
open(outputVideo)
for ii = 1:length(imageNames)
img = imread(fullfile(imageNames{ii}));
writeVideo(outputVideo,img)
end
close(outputVideo)
Here is one way this can be done:
Just like you read the image into img, you can read a second image (from the second video) into img2. Then, you can create a combined image of the two: imgCombined = [img ; img2]; which will contain the first image on top and the second on bottom (This will work if both images are the same width, otherwise you will need to resize/crop). When you write to the video file, use writeVideo(outputVideo,imgCombined).

Average filter Matlab

I have written the 3x3 average filter. It works fine but it shows the same output image three times instead of one. How to resolve the problem?
The code is
function [filtr_image] = avgFilter(noisy_image)
[x,y] = size(noisy_image);
filtr_image = zeros(x,y);
for i = 2:x-1
for j =2:y-1
sum = 0;
for k = i-1:i+1
for l = j-1:j+1
sum = sum+noisy_image(k,l);
end
end
filtr_image(i,j) = sum/9.0;
filtr_image = uint8(filtr_image);
end
end
end
thanks in advance
What is most likely happening is the fact that you are supplying a colour image when the code is specifically meant for grayscale. The reason why you see "three" is because when you do this to allocate your output filtered image:
[x,y] = size(noisy_image)
If you have a 3D matrix, the number of columns reported by size will be y = size(noisy_image,2)*size(noisy_image,3);. As such, when you are iterating through each pixel in your image, in column major order each plane would be placed side by side each other. What you should do is either convert your image into grayscale from RGB or filter each plane separately.
Also, you have an unnecessary casting performed in the loop. Just do it once outside of the loop.
Option #1 - Filter per plane
function [filtr_image] = avgFilter(noisy_image)
[x,y,z] = size(noisy_image);
filtr_image = zeros(x,y,z,'uint8');
for a = 1 : z
for i = 2:x-1
for j =2:y-1
sum = 0;
for k = i-1:i+1
for l = j-1:j+1
sum = sum+noisy_image(k,l,a);
end
end
filtr_image(i,j,a) = sum/9.0;
end
end
end
end
Then you'd call it by:
filtr_image = avgFilter(noisy_image);
Option #2 - Convert to grayscale
filtr_image = avgFilter(rgb2gray(noisy_image));
Minor Note
You are using sum as a variable. sum is an actual function in MATLAB and you would be overshadowing this function with your variable. This will have unintended consequences if you have other functions that rely on sum later down the line.
I can't see why your code would repeat the image (unless it's a pattern cause by an integer overflow :/ ) but here are some suggestions:
if you want to use loops, at least drop the inner loops:
[x,y] = size(noisy_image);
filtr_image = zeros(x,y);
for i = 2:x-1
for j =2:y-1
% // you could do this in 1 line if you use mean2(...) instead
sub = noisy_image(i-1:i+1, j-1:j+1);
filtr_image = uint8(mean(sub(:)));
end
end
However do you know about convolution? Matlab has a built in function for this:
filter = ones(3)/9;
filtr_image = uint8(conv2(noisy_image, filter, 'same'));