change name of a variable inside a loop [duplicate] - matlab

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to concatenate a number to a variable name in MATLAB?
It must be easy but I just cannot find it in help!
I am operating with a vector x for 10 loops (for example) and at the end I want to concatenate all the results in a matrix 10by10. In order to do that I have to name them x1,x2,x3 etc. how can I do this?
Edit: A portion of my code thus far (copied from comments):
x = [0,0,0,1,0,0,1,0];
for k = 1:50
if x(1,8) ==1 && x(1,1)==1 && x(1,2)==1
x(1,1)=0;
elseif x(1,8) ==1 && x(1,1)==1 && x(1,2)==0
x(1,1)=0;
elseif x(1,8) ==1 && x(1,1)==0 && x(1,2)==1
x(1,1)=0;
elseif x(1,8) ==1 && x(1,1)==0 && x(1,2)==0
x(1,1)=1;
elseif x(1,8) ==0 && x(1,1)==1 && x(1,2)==1
x(1,1)=1;
elseif x(1,8) ==0 && x(1,1)==1 && x(1,2)==0
x(1,1)=1;
elseif x(1,8) ==0 && x(1,1)==0 && x(1,2)==1
x(1,1)=1;
end
...etc...
disp(x)

You should preallocate a matrix before your loop, and in the loop you just insert the vectors directly in the columns (or rows). Like:
A= zeros(10, 10);
for k in 1: 10
A(:, k)= %# result of your processing
end

Related

How to fill only the internal section of a shell with MATLAB

I'm writing a script to process .png images similar to how 3D printing slicers work.
I need to fill the inside of the objects 'shell' but not gaps in the shell itself.
First I tried using MATLAB imfill function which gets me 90% of the way but runs into trouble if there's a internal wall or gap, in that case it fills the shell and the gap as well. (image 2).
I then tried a set of if statements that fill based on encountering walls moving along the image, filling after every other wall encountered. This works except for when it encounters a wall that doesn't have a void after it like a long side wall, (image 3).
My desired result is in image 4. That was done with a manual imfill but the image sets I want to process are in the thousands so an automated method is nearly essential.
%method 1
solid = imfill(im);
%method 2
% im aware this code is bad and full of redundant checks and conditions
% it was written as a fast check to see if what i believed the failure would
% be was correct which it sadly was. I'm not as interested in the content
% (I can fix that myself) as I am the general outcome.
slick = imread('image.png');
solid_im = zeros(size(slick));
for kx=1:x
last=0;
is_filling = 0;
for ky =1:y
if slick(kx,ky) == 1 && last == 0 && is_filling == 0
solid_im(kx,ky) = 1;
last = 1;
is_filling = 1;
elseif slick(kx,ky) == 1 && last == 1 && is_filling == 0
solid_im(kx,ky) = 1;
elseif slick(kx,ky) == 0 && last == 1 && is_filling == 0
solid_im(kx,ky) = 0;
last = 0;
elseif slick(kx,ky) == 0 && last == 0 && is_filling ==0
solid_im(kx,ky) = 0;
elseif slick(kx,ky) == 1 && last == 0 && is_filling == 1
solid_im(kx,ky)= 1;
last = 1;
is_filling = 0;
elseif slick(kx,ky) == 1 && last == 1 && is_filling == 1
solid_im(kx,ky) = 1;
elseif slick(kx,ky) == 0 && last == 1 && is_filling == 1
solid_im(kx,ky) = 1;
last = 0;
elseif slick(kx,ky) == 0 && last == 0 && is_filling == 1
solid_im(kx,ky) = 1;
end
end
end
Image with only shell walls:
Completely filled with imfill:
Image filled by algorithm with bad lines:
Correctly filled image:
Looks like a an old answer of mine solves the problem:
Refer to: How can I fill between edges of these characters in matlab?
Here is the code:
I = imread('https://i.stack.imgur.com/6Rdl1.png');
I = imbinarize(rgb2gray(I));
J1 = imfill(I, 'holes');
J2 = imfill(I, [1, 1]);
J3 = imfill(~J2, [1, 1]);
J4 = imfill(~J3, 'holes');
J5 = J1 & (~J4);
figure;imshow(J5)
Result:
I can't guarantee the solution is going to work for thousands of images.

Matlab Code should stop duplicates, but duplicates still occur

I am trying to write a program that will find the outline of a figure by finding if points around an original point is within a boundary of the original point. I have tried to write a section that will prevent points to look at points already included in the outline (using variables a,b,c,d). The current code I have is
while 1
[m M] = size(already_boxed);
x=0;
for n = 1:m
a=0;
b=0;
c=0;
d=0;
for w = 1:m
if already_boxed(w,:) == [(already_boxed(n,1)+1), already_boxed(n,2)]
a=1;
end
if already_boxed(w,:) == [(already_boxed(n,1)-1), already_boxed(n,2)]
b=1;
end
if already_boxed(w,:) == [already_boxed(n,1), (already_boxed(n,2)+1)]
c=1;
end
if already_boxed(w,:) == [already_boxed(n,1), (already_boxed(n,2)-1)]
d=1;
end
end
if a==0
if subimages((already_boxed(n,1)+1), already_boxed(n,2))<subimages(already_boxed(n,1),already_boxed(n,2))*0.9 && subimages((already_boxed(n,1)+1), already_boxed(n,2))>subimages(already_boxed(n,1),already_boxed(n,2))*1.1
already_boxed = [already_boxed; (already_boxed(n,1)+1), already_boxed(n,2)];
x=1;
end
end
if b ==0
if subimages((already_boxed(n,1)-1), already_boxed(n,2))<subimages(already_boxed(n,1),already_boxed(n,2))*0.9 && subimages((already_boxed(n,1)-1), already_boxed(n,2))>subimages(already_boxed(n,1),already_boxed(n,2))*1.1
already_boxed = [already_boxed; (already_boxed(n,1)-1), already_boxed(n,2)];
x=1;
end
end
if c==0
if subimages(already_boxed(n,1), (already_boxed(n,2)+1))<subimages(already_boxed(n,1),already_boxed(n,2))*0.9 && subimages(already_boxed(n,1), (already_boxed(n,2)+1))>subimages(already_boxed(n,1),already_boxed(n,2))*1.1
already_boxed = [already_boxed; already_boxed(n,1), (already_boxed(n,2)+1)];
x=1;
end
end
if d ==0
if subimages(already_boxed(n,1), (already_boxed(n,2)-1))<subimages(already_boxed(n,1),already_boxed(n,2))*0.9 && subimages(already_boxed(n,1), (already_boxed(n,2)-1))>subimages(already_boxed(n,1),already_boxed(n,2))*1.1
already_boxed = [already_boxed; already_boxed(n,1), (already_boxed(n,2)-1)];
x=1;
end
end
end
if x == 0
break
end
end
Right now, the code will go on forever since it keeps on checking points that are in the online. For example, the variable 'already_boxed' will contain the doubles:
119,288
120,288
118,288
119,289
119,287
119,288
I don't know why 119,288 shows up twice, and I only want it to show up once. How can I fix this?

Loop does not return correct values for piecewise function

I have tried to write a code, part of a bigger program, that would return value of z at every point of s. However, when I run the code I only get z=0, or if last else is ignored code returns zero vector.
Does someone have a clue where I made mistake? I have used method 1 from this source. Any help will be greatly appreciated, I have trying to get this work for months now.
% clc;close all; %// not generally appreciated
%initial values
b=1.25;
h=0.313;
%define the s coordinate
s= 0:0.001:2*(b+h);
%create zero matrix for speed
z=zeros(size(s));
%calculate z at every point of s coordinate
for i =length(s)
if 0 <= s(i) && s(i) <=b %0<=s<=b
z=0.5*h;
elseif b <= s(i) && s(i) <=(b+h) %b<=s<=(b+h)
z=0.5*h+((-0.5*h)/(b+h-b))*(s-b);
elseif b <= s(i) && s(i) <=(b+h) %(h+b)<=s<=(b+h)
z=-0.5*h;
elseif b <= s(i) && s(i) <=(b+h) %(h+2b)<=s<=(2b+2h)
z=-0.5*h+((-0.5*h)/(b+h-b))*(s-b);
else z=0;
end
end
For further reference, this solved my problem. Thank you #Dan!
%// initial values
b=1.25;
h=0.313;
%// define the s coordinate
s= 0:0.001:2*(b+h);
%// Create z
z = zeros(size(s));
idx1 = 0 <= s & s <=b;
idx2 = b <= s & s <=(b+h);
idx3 = (b+h) <= s & s <= (2*b+h);
idx4 = (2*b+h) <= s & s <=(2*b+2*h);
z(idx1) = 0.5*h;
z(idx2) = 0.5*h+((-0.5*h-0.5*h)/(b+h-b))*(s(idx2)-b);
z(idx3) = -0.5*h;
z(idx4) =-0.5*h+((0.5*h+0.5*h)/((2*b+2*h-b)-(h+b+b)))*(s(idx4)-b)
There are many issues with your code. You need to assign to an index of z otherwise you're just overwirting a scalar every time (i.e. z(i)=...). You need to loop over a vector so fori=1:length(s) and your last three loop conditions are identical!
%// initial values
b=1.25;
h=0.313;
%// define the s coordinate
s= 0:0.001:2*(b+h);
%// create zero matrix for speed
z=zeros(size(s));
%// calculate z at every point of s coordinate
for i = 1:length(s)
if 0 <= s(i) && s(i) <=b %// 0<=s<=b
z=0.5*h;
elseif b <= s(i) && s(i) <=(b+h) %// b<=s<=(b+h)
z(i)=0.5*h+((-0.5*h)/(b+h-b))*(s-b);
elseif (b+h) <= s(i) && s(i) <= (2*b+h) %// (h+b)<=s<=(2b+h)
z(i)=-0.5*h;
elseif (2*b+h) <= s(i) && s(i) <=(2*b+2*h) %// (h+2b)<=s<=(2b+2h)
z(i)=-0.5*h+((-0.5*h)/(b+h-b))*(s-b);
else z(i)=0;
end
end
With all the said, in MATLAB you don't even need a loop at all to do this and it is usually preferable not to use one:
%// initial values
b=1.25;
h=0.313;
%// define the s coordinate
s= 0:0.001:2*(b+h);
%// Create z
z = zeros(size(s));
idx1 = 0 <= s && s <=b;
idx2 = b <= s && s <=(b+h);
idx3 = (b+h) <= s && s <= (2*b+h);
idx4 = (2*b+h) <= s && s <=(2*b+2*h);
z(idx1) = 0.5*h;
z(idx2) = 0.5*h+((-0.5*h)/(b+h-b))*(s(idx2)-b);
z(idx3) = -0.5*h;
z(idx4) = -0.5*h+((-0.5*h)/(b+h-b))*(s(idx4)-b);
b=1.25;
h=0.313;
%define the s coordinate
s= 0:0.001:2*(b+h);
%create zero matrix for speed
z=zeros(size(s));
%calculate z at every point of s coordinate
for ii =1:length(s)
if 0 <= s(ii) && s(ii) <=b %0<=s<=b
z(ii)=0.5*h;
elseif b <= s(ii) && s(ii) <=(b+h) %b<=s<=(b+h)
z(ii)=0.5*h+((-0.5*h)/(b+h-b))*(s(ii)-b);
elseif b <= s(ii) && s(ii) <=(b+h) %(h+b)<=s<=(b+h)
z(ii)=-0.5*h;
elseif b <= s(ii) && s(ii) <=(b+h) %(h+2b)<=s<=(2b+2h)
z(ii)=-0.5*h+((-0.5*h)/(b+h-b))*(s(ii)-b);
else z(ii)=0;
end
end
Let your for loop run over more than 1 iteration, hence the for ii = 1:length(s).
Use allocation per element, thus z(ii) = some function
Don't use i as a variable.

Write a simulation of a funny game with a dice in MATLAB

I am trying to write a code that simulates the following game:
Roll two dice and let x be the sum of them. If x=7 or x=11 then you win. Otherwise roll both dice again until you get x (in which case you win) or 7 or 11 (in which case you loose).
Imagine you have a two dice, then if in the first roll you get as the sum of both 7 or 11, you win, if not, then the sum could be other number, let's say 9, then you have to continue rollin both dice until you get again 9, if in that process you get 7 or 11 agiain you loose :)
Then I wrote the following code:
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
while x~=7 & x~=11
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
if x==x
disp('You win')
elseif x==7 | x==11
disp('You loose')
end
end
But it displays indefinitely the sentence "you win" and can't stop it, I know that this is because the condition "x==x" always evaluates true, but how can I fix that to have the simulation?
Thanks a lot in advance
Do you want to do re-rolls until you win? In that case you want to do the re-roll in your while-loop. Checking the same number over and over again is not going to be useful.
x=0;
wins=[7 11];
while min(x~=wins)
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2
if max(x==wins)
disp('You win')
else
disp('You loose')
end
end
This should work:
x=0;
while x~=7 | x~=11
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
if x==7 | x==11
disp(x)
disp('You win')
break
else
disp(x)
disp('You loose')
a = input('You want roll again (y/n)? ','s')
if strcmpi(a,'y')
else
break
end
end
end
added more of a game vibe to it, also added comments so you understand what I am doing
win1 = 7; %these values give you a win
win2 = 11;
lose1 = 0; %can't lose on first roll. this will be set later
lose2 = 0;
streak = 0;
%while game is still going on..
while true
newgame = input('Would you like to start a new game? Type YES or NO --> ','s'); %user inputs string
if strcmpi(newgame,'YES') %did user type YES?
game = true; % set games state to true to begin the game loop
firstroll=true; %first roll coming up
elseif strcmpi(newgame,'NO')
break; % end program by exiting outer loop
else %user didn't enter correctly so re-ask
continue;
end
while game
input('Press enter to roll dice'); %roll the dice
d1 = floor(6*rand)+1;
d2 = floor(6*rand)+1;
disp('You rolled:'); %display the dice
disp(d1);
disp(d2);
x=d1+d2;
if x==win1 || x==win2 % check for a win
streak=streak+1; %%add a win to your total
disp('WINNER!')
elseif x==lose1 || x==lose2
disp('YOU LOST!')
disp('streak:') %show how many games you won
disp(streak)
game = false; % end game state because you lost
%reset winning and losing numbers
win1=7;
win2=11;
lose1=0;
lose2=0;
streak = 0; %reset streak
elseif firstroll %ok, didn't win on the FIRST ROLL so lets set the NEW winning value and reroll
win1 = x; % we win if we roll the same value again
win2 = x;
lose1 = 7; % we lose if we roll a 7 or 11
lose2 = 11;
firstroll = false; % set firstroll false so it doesn't keep resetting the winning and losing values
continue;
end
end
end
disp('Thanks for playing!')
Because you change the rule after the first round, you specify the rule of the first round with an if statement and the rest of the game in the else statement. Moreover, you need to specify the value X in your code. Here I use 5 as an example. If there is no result after the first round, you role the dice again with the code d1=floor(6*rand)+1; d2=floor(6*rand)+1; x=d1+d2;, then determine whether you win or lose. If there is still no result, you will use a while loop to keep this going until there is a win or lose situation.
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
first_sum = x % use another variable first_sum to hold the status of first roll
if x==7 || x==11
disp('You win')
else
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
if x== 7 || x==11
disp('You lose')
elseif x == first_sum
disp('You win')
else
while x ~= first_sum && x~=11 && x~=7
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
if x== 7 || x==11
disp('You lose')
elseif x == first_sum
disp('You win')
end
end
end
end
Or you can write this in a more succinct way. Since the else statement contains a structure like a do while loop(meaning do at least once and keep doing it if a certain condition is met), you can also code it like this :
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
first_sum = x
if x==7 || x==11
disp('You win')
else
flag = true
while flag % The while loop will keep going until flag is set to false.
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
if x== 7 || x==11
disp('You lose')
flag = false % If a result is reached, stop the while loop
elseif x == first_sum
disp('You win')
flag = false
end
end
end
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
x=d1+d2;
kk=1;
while x~=7 && x~=11
d1=floor(6*rand)+1;
d2=floor(6*rand)+1;
if kk ==1
tmp = d1+d2;
end
x=d1+d2;
if x==7 || x==11 && kk == 1
disp('You win')
elseif x==7 || x==11 && kk > 1
disp('You loose')
elseif x==tmp && kk>1
disp('You win')
else
disp('You loose')
end
kk = kk+1;
end
What is happening is that I introduced kk, which can be considered and iteration counter. Add that as an extra condition upon the winning condition. if statements then contain all the conditions you set, note that if kk==1 I save the sum in tmp, against which I check the second win condition.
Test run:
You loose
You loose
You loose
You win

How to chose random lines that hit a rectangular in MatLab

I am creating random starting and ending points. I want to plot those who cross/intersect with a rectangular which is placed at the origin. I found out that my code misses some lines, as shown in the figure. After that, I want to count were the tracks hit the rectangle. For expample the track came from top side and exited from right side etc.
My code is
function [hot, cold, h] = MuonTracks(tracks)%#eml
% NOTE: no variables larger than 1x1 are initialized
width = 1e-4;
height = 2e-4;
% constant used for Laplacian noise distribution
bL = 15 / sqrt(2);
% Loop through all tracks
X = [];
bhit= [];
hot = 0;
ii = 0;
TopBottom= 0;
LeftRight= 0;
TopRight= 0;
TopLeft= 0;
LeftBottom= 0;
RightBottom= 0;
ihit= 0;
while ii <= tracks
ii = ii + 1;
% Note that I've inlined (== copy-pasted) the original laprnd()
% function call. This was necessary to work around limitations
% in loops in Matlab, and prevent the nececessity of those HUGE
% variables.
%
% Of course, you can still easily generalize all of this:
% the new data
u = rand-0.5;
Ystart = 15;
Xstart = 80*rand-40;
Xend = Xstart - bL*sign(u)*log(1-2*abs(u));
%Xend=laprnd(tracks,1,Xstart,15);
b = (Ystart*Xend)/(Xend-Xstart);
% the test
if ((b < height && b > 0)) ||...
(Xend < width/2 && Xend > -width/2)
hot = hot+1;
% growing an array is perfectly fine when the chances of it
% happening are so slim
X = [X [Xstart; Xend]]; %#ok
bhit=b;
end
end
% This is trivial to do here, and prevents an 'else'
cold = tracks - hot;
% Now plot the chosen ones
h = figure;
hold all
%Y = bsxfun(#times, 15, ones(size(X)));
if (size(X)==0)
%Disp('No hits were found');
msgbox('No tracks were found','Result','warn');
elseif (size(X)>1)
Y = bsxfun(#times, [15; 0], ones(size(X)));
plot(X, Y, 'r');
msgbox( [num2str(hot) ' tracks were found'],'Result','help',num2str(hot));
else
Y = bsxfun(#times, [15; 0], ones(size(X)));
plot(X, Y, 'r');
msgbox( [num2str(hot) ' track was found'],'Result','help',num2str(hot));
end
%X;
%Y;
%size(X,2)
while ihit<size(X,2)
ihit=ihit+1
%X(2,ihit)
if ((X(2,ihit)==-width && (bhit<=0 && bhit<=height))&&(bhit==0 && (X(2,ihit)>=-width && X(2,ihit)>=width)))
LeftBottom=LeftBottom+1;
elseif ((bhit==height && (X(2,ihit)>=-width && X(2,ihit)>=width)) && (X(2,ihit)==width && (bhit<=0 && bhit<=height)))
TopRight=TopRight+1;
elseif ((bhit==height && (X(2,ihit)>=-width && X(2,ihit)>=width)) && (bhit==0 && (X(2,ihit)>=-width && X(2,ihit)>=width)))
TopBottom=TopBottom+1;
elseif ((X(2,ihit)==-width && (bhit<=0 && bhit<=height)) && (X(2,ihit)==width && (bhit<=0 && bhit<=height)))
LeftRight=LeftRight+1;
elseif ((X(2,ihit)==-width && (bhit<=0 && bhit<=height)) && (bhit==height && (X(2,ihit)>=-width && X(2,ihit)>=width)))
TopLeft=TopLeft+1;
elseif ((X(2,ihit)==width && (bhit<=0 && bhit<=height)) && (bhit==0 && (X(2,ihit)>=-width && X(2,ihit)>=width)))
RightBottom=RightBottom+1;
else
display('sth is wrong');
end
X(2,ihit)
end
%X(1,:);
%Y(1,:);
LeftBottom
TopRight
TopBottom
LeftRight
TopLeft
RightBottom
%display('sdfghjk');
end
Any ideas would be more than welcome!
Here you have a function that is capable of intersecting whole groups of segments and returning the intersection points. I hope it helps.