For Loop and indexing - matlab

Following is my code :
function marks(my_numbers)
handle = zeros(5,1)
x = 10 ;
y = 10:20:100 ;
for i = 1
for j = 1:5 ;
handle(j,i) = rectangle('position',[x(i),y(j),20 10],'facecolor','r')
end
end
end
now lets say input argument my_numbers = 2
so i have written the code :
set(handle(j(my_numbers),1),'facecolor','g')
With this command, rectangle with lower left corner at (30,10) should have turned green. But MATLAB gives an error of index exceeds matrix dimensions

This is more an illustrated comment than an answer, but as #hagubear mentioned your i index is pointless so you could remove it altogether.
Using set(handle(my_numbers,1),'facecolor','g') will remove the error, because you were trying to access handles(j(2),1) and that was not possible because j is a scalar.
Anyhow using this line after your plot works fine:
set(handle(my_numbers,1),'facecolor','g')
According to your comment below, here is a way to call the function multiple times and add green rectangles as you go along. There are 2 files for the purpose of demonstration, the function per se and a script to call the function multiple times and generate an animated gif:
1) The function:
function marks(my_numbers)
%// Get green and red rectangles to access their properties.
GreenRect = findobj('Type','rectangle','FaceColor','g');
RedRect = findobj('Type','rectangle');
%// If 1st call to the function, create your plot
if isempty(RedRect)
handle = zeros(5,1);
x = 10 ;
y = 10:20:100 ;
for j = 1:5 ;
handle(j) = rectangle('position',[x,y(j),20 10],'facecolor','r');
end
set(handle(my_numbers,1),'facecolor','g')
%// If not 1st call, fetch existing green rectangles and color them green. Then color the appropriate rectangle given by my_numbers.
else
RedRect = flipud(RedRect); %// Flip them to maintain correct order
if numel(GreenRect) > 0
hold on
for k = numel(GreenRect)
set(GreenRect(k),'facecolor','g')
set(RedRect(my_numbers,1),'facecolor','g')
end
end
end
2) The script:
clear
clc
%// Shuffle order for appearance of green rectangles.
iter = randperm(5);
filename = 'MyGifFile.gif';
for k = iter
marks(k)
pause(1)
frame = getframe(1);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if k == iter(1)
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
Here is the animated gif of the output:

Related

Matlab: Calling a legend in a plot which is created with an ''if'' statement

I am trying to plot some functions and display a legend. My code can be found below:
%% DATCOM spanloading method
tol = Input.tol;
iteration = 0;
difference =0;
AVL_step = 0.25;
Interp_step =0.1;
AVLruns = 3;
Angle = ((1:AVLruns)*AVL_step)+AOA;
while sum(difference < 0) <= fix(tol*Input.Surface.Nspan) && iteration < 100
iteration = iteration +1;
if iteration <= AVLruns
AOA = AOA + AVL_step;
[Yle_wing,Spanloading] = obj.AVLspanloading(Input,CLa,AOA); % Creates spanloading with AVL
Scalefunc = 1/(max(Yle_wing)-min(Yle_wing)); % Scale function
Ynorm= ((Yle_wing - min(Yle_wing)) .* Scalefunc)'; % Normalize semi-span from 0 to 1
if length(YClmax) ~= length(Ynorm) && iteration ==1
Clmax_dist= interp1(YClmax,Clmax_dist,Ynorm,'linear');
end
difference = (Clmax_dist - Spanloading); % Difference between resampled CL3d and Cl2d
cl_matrix(iteration,:) = Spanloading;
else
AOA = AOA + Interp_step;
for QQ = 1:Input.Surface.Nspan
CL3d = interp1(Angle,cl_matrix(:,QQ)',AOA,'linear','extrap');
Spanloading(:,QQ) = CL3d;
end
difference = (Clmax_dist - Spanloading);
end
figure(1)
pl = plot(Yle_wing,Clmax_dist,'r');
legendStrs = {'2D Clmax'};
set(pl,'linewidth',1.5);
hold on
if iteration <= AVLruns
plot(Yle_wing,Spanloading,'g--o')
legendStrs = [legendStrs, {'Spanloading by AVL'}];
else
plot(Yle_wing,Spanloading)
legendStrs = [legendStrs, {'Spanloading by extrapolation'}];
end
xlabel('2y/b')
ylabel('Local Cl')
title('DATCOM SPANLOADING METHOD')
legend('boxon')
legend(legendStrs,'Location','SouthWest');
end
if iteration >= 100
disp('Spanloading did not converge, while loop terminated by reaching maximum iteration count')
end
Here, I create a plot in the same figure using the hold on statement and with an if statement. Running my code will run both conditions of the if statement. Hence, multiple lines will be plotted in this Figure.
Therefore, I want to make a legend for all three plot commands. However, I don't seem to understand how to create the legend for a plot function within an if statement since the following makes my second plot green, and the rest of the plots red.
How would I go about?
Edit: I've incorporated my whole while loop
You can pass a cell array as an input to legend. Maintain a cell array of strings and add relevant strings to it right after your plot statements.
pl = plot(Yle_wing,Clmax_dist,'r');
legendStrs = {'2D Clmax'};
Then later in the if else block
if iteration <= AVLruns
plot(Yle_wing,Spanloading,'g--o')
legendStrs = [legendStrs, {'Spanloading by AVL'}];
set(pl,'linewidth',1.5);
else
plot(Yle_wing,Spanloading)
legendStrs = [legendStrs, {'Spanloading by extrapolation'}];
end
This will keep the number of legend strings equal to the number of lines you have on your plot. Then, at last
legend(legendStrs,'Location','SouthWest');

How to force MATLAB function area to hold on in figure

I'm working on this function which gets axis handler and data, and is supposed to plot it correctly in the axis. The function is called in for loop. It's supposed to draw the multiple data in one figure. My resulted figure is shown below.
There are only two correctly plotted graphs (those with four colors). Others miss areas plotted before the final area (red area is the last plotted area in each graph). But the script is same for every axis. So where can be the mistake? The whole function is written below.
function [] = powerSpectrumSmooth(axis,signal,fs)
N= length(signal);
samplesPer1Hz = N/fs;
delta = int16(3.5*samplesPer1Hz); %last sample of delta frequncies
theta = int16(7.5*samplesPer1Hz); %last sample of theta frequncies
alpha = int16(13*samplesPer1Hz); %last sample of alpha frequncies
beta = int16(30*samplesPer1Hz); %last sample of beta frequncies
x=fft(double(signal));
powerSpectrum = 20*log10(abs(real(x)));
smoothPS=smooth(powerSpectrum,51);
PSmin=min(powerSpectrum(1:beta));
y1=[(smoothPS(1:delta)); zeros(beta-delta,1)+PSmin];
y2=[zeros(delta-1,1)+PSmin; (smoothPS(delta:theta)); zeros(beta-theta,1)+PSmin];
y3=[zeros(theta-1,1)+PSmin; (smoothPS(theta:alpha)); zeros(beta-alpha,1)+PSmin];
y4=[zeros(alpha-1,1)+PSmin; (smoothPS(alpha:beta))];
a1=area(axis,1:beta,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axis,1:beta,y2);
set(a2,'FaceColor','blue')
a3=area(axis,1:beta,y3);
set(a3,'FaceColor','green')
a4=area(axis,1:beta,y4);
set(a4,'FaceColor','red')
ADDED
And here is the function which calls the function above.
function [] = drawPowerSpectrum(axesContainer,dataContainer,fs)
size = length(axesContainer);
for l=1:size
powerSpectrumSmooth(axesContainer{l},dataContainer{l},fs)
set(axesContainer{l},'XTickLabel','')
set(axesContainer{l},'YTickLabel','')
uistack(axesContainer{l}, 'top');
end
ADDED 29th July
Here is a script which reproduces the error, so you can run it in your computer. Before running it again you might need to clear variables.
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
a1=area(axes,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axes,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axes,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axes,1:N,y4);
set(a4,'FaceColor','red')
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
My result of this script is plotted below:
Again only one picture contains all areas.
It looks like that every call to plot(axes,data) deletes whatever was written in axes.
Important note: Do not use a variable name the same as a function. Do not call something sin ,plot or axes!! I changed it to axs.
To solve the problem I just used the classic subplot instead of creating the axes as you did:
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axs=subplot(3,3,l);
a1=area(axs,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axs,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axs,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axs,1:N,y4);
set(a4,'FaceColor','red')
set(axs,'XTickLabel','')
set(axs,'YTickLabel','')
axis tight % this is to beautify it.
end
As far as I know, you can still save the axs variable in an axescontainer and then modify the properties you want (like location).
I found out how to do what I needed.
len = 8;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
Y=[y1',y2',y3',y4'];
a=area(axes,Y);
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
The area is supposed to work with matrices like this. The tricky part is, that the signal in every next column is not plotted absolutely, but relatively to the data in previous column. That means, if at time 1 the data in first column has value 1 and data in second column has value 4, the second column data is ploted at value 5. Source: http://www.mathworks.com/help/matlab/ref/area.html

Code for peak detection

I want to calculate if a real-time signal pass some thresholds in the first step. In the first step, I want to detect if the real signal pass under those thresholds (in order to detect a peak in the signal). My Matlab code:
k=1;
t = 1;
l=1;
for i =1:length(sm) //sm my signal.
if (sm(i) > 0.25)
first(k) = i;
k = k+1;
if (sm(i) > 0.5)
second(t) = i;
t =t +1;
if (sm(i) > 0.75)
third(l) = i;
l = l+1;
end
end
end
end
Example:
![enter image description here][1]
I want to calculate the times that the signal pass over and under the three thresholds 0.25, 0.5, 0.75 and to return those windows. Basically the three main peaks that I have in my example.
Basically what am I trying to do is to use fastsmooth function and findpeaks.
signalSmoothed = fastsmooth(sm,50); plot(signalSmoothed)
[max_pk1 max_pk2] = findpeaks(signalSmoothed);
find(max_pk1 >0.5)
inversex = 1.01*max(signalSmoothed) - signalSmoothed;
[min_pk1 min_pk2] = findpeaks(inversex);
find(min_pk1 >0.5)
Which are the heuristics in order to take only the desired peaks? Moreover the depticted image is an offline example. Generally I want to perform the technique online.
EDIT: I wrongfully defined as peak my desired curve result which is the whole wave not just the max value.
Here is a solution to get the points where the signal sm passes the thresholds 0.25, 0.50 and 0.75. The points can be converted into windows inside the data-range and get stored in W. Finally we can plot them easily in the same figure. Note that we need to do some checks in the local function getwindows to handle special cases, for example when the window starts outside the data-range. The detection of windows inside another window is done in the getwindowsspecial-function.
Here is the code:
function peakwindow
% generate sample data
rng(7);
sm = 2*rand(1,25)-0.5;
sm = interp1(1:length(sm),sm,1:0.01:100*length(sm));
% get points
firstup = find(diff(sm > 0.25)==1);
secondup = find(diff(sm > 0.50)==1);
thirdup = find(diff(sm > 0.75)==1);
firstdown = find(diff(sm < 0.25)==1);
seconddown = find(diff(sm < 0.50)==1);
thirddown = find(diff(sm < 0.75)==1);
% plot the result
figure; hold on;
plot(sm,'k')
plot(firstup,sm(firstup),'*')
plot(firstdown,sm(firstdown),'*')
plot(secondup,sm(secondup),'*')
plot(seconddown,sm(seconddown),'*')
plot(thirdup,sm(thirdup),'*')
plot(thirddown,sm(thirddown),'*')
% get windows
W1 = getwindows(firstup,firstdown);
W2 = getwindows(secondup,seconddown);
W3 = getwindows(thirdup,thirddown);
% get special window
WS = getwindowsspecial(W1,W3);
% plot windows
plotwindow(W1,0.25,'r');
plotwindow(W2,0.50,'r');
plotwindow(W3,0.75,'r');
plotwindow(WS,0,'b-');
function W = getwindows(up,down)
if length(up)>1 && length(down)>1 && up(1)>down(1)
down(1)=[]; % handle case when window begins out of bounds left
end
if length(up)<1 || length(down)<1;
W = []; % handle if no complete window present
else
% concatenate and handle case when a window ends out of bounds right
W = [up(1:length(down));down]';
end
function plotwindow(W,y,lspec)
for i = 1:size(W,1)
plot(W(i,:),[y,y],lspec)
end
% get windows of U where there is a window of H inside
function W = getwindowsspecial(U,H)
W = []; % empty matrix to begin with
for i = 1:size(U,1) % for all windows in U
if any(H(:,1)>=U(i,1) & H(:,1)<=U(i,2))
W = [W;U(i,:)]; % add window
end
end
This is the result:
To see that the handling works properly, we can plot the result when initialized with rng(3):
Note that the window of 0.25 and 0.50 would start out of bounds left and therefore is not present in the plotted windows.

how do i mask labeled object based on some specified threshold value for each objects area,majoraxis and minoraxis?

i am currently using bwconnomp to label each connected object and regionpropsto find area, majoraxis, minoraxis of each labeled object respectively. i am also displaying each labeled object its area,majoraxis and minoraxis. now i want to set some threshold for area,majoraxis and minoraxis and if the value of area,majoraxis and minoraxis is above specified threshold then that object has to be masked.how this can be done??
here is my code
clc
clear all
close all
Index = 1;
scrsz = get(0,'ScreenSize');
%read an image
while Index ~= 0
% Open a dialog and select an image file
[FileName,FilePath,Index] = uigetfile('*.png', 'Open Imagefile ');
if Index == 0
disp('Procedure Done')
break;
end
inimage = imread([num2str(FilePath) FileName]);
D=inimage;
A=inimage;
subplot(2,3,1);
imshow(inimage);
title('original image');
%labeling algorithm
B=im2bw(inimage);
C=imfill(B,'holes');
label=bwlabel(C);
max(max(label))
CC = bwconncomp(B);
data = regionprops(CC,'all');
for j=1:max(max(label))
[row, col] = find(label==j);
len=max(row)-min(row)+2;
breadth=max(col)-min(col)+2;
target=uint8(zeros([len breadth] ));
sy=min(col)-1;
sx=min(row)-1;
for i=1:size(row,1)
x=row(i,1)-sx;
y=col(i,1)-sy;
target(x,y)=A(row(i,1),col(i,1));
end
mytitle=strcat('Object Number:' ,num2str(j),'area:', num2str(data(j).Area),'MajorAxis: ',num2str(data(j).MajorAxisLength),'MinorAxis: ',num2str(data(j).MinorAxisLength));
figure,imshow(target);title(mytitle);
a=size(target);
ax=a(1);
ay=a(2);
pos=[1,1,ay,ax];
rectangle('Position',pos,'EdgeColo','r')
end
next = input('next image? press Enter: ');
if next == 0
channelactivity = 0;
break
else
close all
disp('==================================')
pause(0.2)
continue
end
end
Here is a way to do it. The code is commented so easy to follow; the important line is the following:
AboveAreaIndices = find(vertcat(data.Area) > SomeValue)
In which you store the indices of the objects whose area is larger than SomeValue. In the example I color them red but you can do whatever you want with them or remove them altogether from the data structure.
You can also use logical operators to combine multiple conditions for example using the MinorAxis and MajorAxis properties. Note that I used AllArea as anew variable to store the concatenated areas to make things clearer, but you can keep them as vertcat(data.Area).
AboveIndices = find(vertcat(data.Area) > SomeValue & vertcat(data. MinorAxis) > SomeValue & Bla bla bla...);
Whole code:
clear
clc
close all
%// Read and clean up sample image
A = imread('rice.png');
A = im2bw(A,.5);
A = bwareaopen(A,50);
CC = bwconncomp(A);
%// Same as you.
data = regionprops(CC,'all');
%// Concatenate all the areas into an array.
AllArea = vertcat(data.Area);
%//========================================
%//==== Apply threshold on area here \\====
AboveAreaIndices = find(AllArea > 150);
%// If you wish to remove the entries from the data structure
% data(AllArea>150) = [];
%//========================================
%// Same for centroids...for display purposes
AllCentroids = vertcat(data.Centroid);
%// Display original and thresholded objects. Use the indices calculated
%// above to "mask" large areas if you want
imshow(A);
hold on
scatter(AllCentroids(:,1),AllCentroids(:,2),40,'b','filled')
scatter(AllCentroids(AboveAreaIndices,1),AllCentroids(AboveAreaIndices,2),40,'r','filled')
And sample output:

Rolling window for averaging using MATLAB

I have the following code, pasted below. I would like to change it to only average the 10 most recently filtered images and not the entire group of filtered images. The line I think I need to change is: Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;, but how do I do it?
j=1;
K = 1:3600;
window = zeros(1,10);
Yout = zeros(10,column,row);
figure;
y = 0; %# Preallocate memory for output
%Load one image
for i = 1:length(K)
disp(i)
str = int2str(i);
str1 = strcat(str,'.mat');
load(str1);
D{i}(:,:) = A(:,:);
%Go through the columns and rows
for p = 1:column
for q = 1:row
if(mean2(D{i}(p,q))==0)
x = 0;
else
if(i == 1)
meanvalue = mean2(D{i}(p,q));
end
%Calculate the temporal mean value based on previous ones.
meanvalue = (meanvalue+D{i}(p,q))/2;
x = double(D{i}(p,q)/meanvalue);
end
%Filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
end
end
end
% for k = 2:10
% subplot(5,2,k)
% subimage(Yout(k)*5000, [0 100]);
% colormap jet
% end
% pause(0.01);
end
disp('Done Loading...')
The best way to do this (in my opinion) would be to use a circular-buffer to store your images. In a circular-, or ring-buffer, the oldest data element in the array is overwritten by the newest element pushed in to the array. The basics of making such a structure are described in the short Mathworks video Implementing a simple circular buffer.
For each iteration of you main loop that deals with a single image, just load a new image into the circular-buffer and then use MATLAB's built in mean function to take the average efficiently.
If you need to apply a window function to the data, then make a temporary copy of the frames multiplied by the window function and take the average of the copy at each iteration of the loop.
The line
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
calculates a kind of Moving Average for each of the 10 bands over all your images.
This line calculates a moving average of meanvalue over your images:
meanvalue=(meanvalue+D{i}(p,q))/2;
For both you will want to add a buffer structure that keeps only the last 10 images.
To simplify it, you can also just keep all in memory. Here is an example for Yout:
Change this line: (Add one dimension)
Yout = zeros(3600,10,column,row);
And change this:
for q = 1:row
[...]
%filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(i,k,p,q) = y.^2;
end
YoutAvg = zeros(10,column,row);
start = max(0, i-10+1);
for avgImg = start:i
YoutAvg(k,p,q) = (YoutAvg(k,p,q) + Yout(avgImg,k,p,q))/2;
end
end
Then to display use
subimage(Yout(k)*5000, [0 100]);
You would do sth. similar for meanvalue