MATLAB: adding columns to an empty matrix only when condition is true - matlab

I have a image (orig) and a corresponding binary mask (maskD) composed of vertical streaks/columns of values zero or one. I am trying to make a third matrix (streakTemp) composed of only those columns in the image which have a 1 value in the mask. I'm using the code below and for some reason its giving me as an output both the columns I'm looking for and then zero values where the mask value is 0...so my output has the same x length as my input image...it should be shorter with the mask values of zero excluded. Not sure what I'm doing wrong..any thoughts? Thanks!
streakTemp=[];
for i=1:x
if maskD(1,i)==1
streakTemp(:,i)=orig(:,i);
end
end
imtool(streakTemp);

This variant of your code should work:
streakTemp=[];
j=1;
for i=1:x
if maskD(1,i)==1
streakTemp(:,j)=orig(:,i);
j=j+1;
end
end
The problem you have is that the i index always corresponds to the original matrix column, thus it won's skip the column even if the mask condition is not met.

I think this is what you need:
orig = reshape(1 : 20, 4, 5)
maskD = [1 0 0 1 1; 1 0 0 1 1; 1 0 0 1 1; 1 0 0 1 1]
mask1D = maskD(1, :)
x = 5;
streakTemp=[];
for i=1:x
if maskD(1,i)==1
streakTemp(:,i)=orig(:,i);
end
end
streakTemp
streakTemp2 = orig(:, logical(mask1D))
It outputs:
orig =
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
maskD =
1 0 0 1 1
1 0 0 1 1
1 0 0 1 1
1 0 0 1 1
mask1D =
1 0 0 1 1
streakTemp =
1 0 0 13 17
2 0 0 14 18
3 0 0 15 19
4 0 0 16 20
streakTemp2 =
1 13 17
2 14 18
3 15 19
4 16 20
Here is more on logical indexing.
Note that your maskD does not have to be a matrix at all; you only need to store the first line, which is why I use mask1D.

You shouldn't be using loops here. Straight up logical indexing is totally fine for your purposes:
streakTemp = orig(:, maskD(1,:) == 1);
Remember that maskD is a mask that's the same size as your original image, so we only need to access the first row to do the check. Simply put, this takes a look at all columns where maskD is equal to 1 then uses the corresponding locations to subsample from your orig matrix to create a new matrix that removes all columns that are not desired.

Related

Create a matrix from a vector such that its height and width are powers of multiples in matlab

I have tried multiple solutions in matlab to convert a vector for example
A = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
into
B= [ 1 2 3 4 ]
5 6 7 8
9 10 11 12
13 14 15 16
17 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Here the desired matrix is 8x4 or rather the height or width is any multiple of 4. This would mean the nearest greater multiple of 4 if we keep any one dimension(height or width) fixed for fitting all elements and padding the extra elements with zeroes. I have tried reshape like so
reshape([c(:) ; zeros(rem(nc - rem(numel(c),nc),nc),1)],nc,[])
Here c is the original vector or matrix, nc is the number of columns.
It simply changes the number of rows and cols but does not take into account the possible powers required by the condition for height and width. I don't have the Communications Toolbox which has the vec2mat function.
Another possible alternative thought is to initialize a matrix with all zeroes and then assign. But at this point I'm stuck. So please help me matlab experts.
i think this what you mean:
n = 4;
A = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
B = zeros(n,ceil(numel(A)/n^2)*n);
B(1:numel(A)) = A;
B = B'
B = [ 1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0]

finding indeces of similar group elements

I have a vector test2 that includes NaN 0 and 1 in random order (we cannot make any assumption).
test2 = [NaN 1 1 1 0 0 0 NaN NaN NaN 0 0 0 1 1 1 0 1 1 1 ];
I would like to group the elements containing consecutive 1 and to have in the separte vectors start and finish the first and last index of the groups.
In this case start and finish should be:
start = [2 14 18];
finish = [4 16 20];
I tried to adapt the code provided here coming up with this solution that is not working...could you help me with the right solution and tell me why the one I tried doesn't work?
a = (test2 ==1);
d = diff(a);
start = find([a(1) d]==1); % Start index of each group
finish = find([d - a(end)]==-1); % Last index of each group
start =
2 14 18
finish =
2 3 5 6 7 8 9 10 11 12 14 15 18 19
I am using MATLAB R2013b running on Windows.
I tried also using MATLAB R2013a running on ubuntu.
a = (test2 ==1)
d=diff([0 a 0])
start=find(d==1)
finish=find(d==-1)-1
Padding a zero at the beginning and end is the easiest possibility. Then the special cases where a group starts at index 1 or ends at last index don't cause problems.
Full output:
>> test2 = [NaN 1 1 1 0 0 0 NaN NaN NaN 0 0 0 1 1 1 0 1 1 1 ]
test2 =
Columns 1 through 16
NaN 1 1 1 0 0 0 NaN NaN NaN 0 0 0 1 1 1
Columns 17 through 20
0 1 1 1
>> a = (test2 ==1)
a =
Columns 1 through 16
0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1
Columns 17 through 20
0 1 1 1
>> d=diff([0 a 0])
d =
Columns 1 through 16
0 1 0 0 -1 0 0 0 0 0 0 0 0 1 0 0
Columns 17 through 21
-1 1 0 0 -1
>> start=find(d==1)
start =
2 14 18
>> finish=find(d==-1)-1
finish =
4 16 20
>>
The problem is the line finish = find([d - a(end)]==-1);, in particular that a(end) == 1. There are two steps to correcting this. First, change the problem line to finish = find(d==-1); This tells MATLAB, "Look for the elements where the difference between adjacent elements is -1". In other words, the vector shifts from 1 to 0 or NaN. If you run the code, you'll get
start = 2 14 18
finish = 4 16
Now, you'll notice the last element isn't detected (i.e. we should get finish(3) == 20. This is because the length of d is one less than the length of test2; the function diff cannot calculate the difference between the last element and the non-existant last+1 element!
To remedy this, we should modify a:
a = [(test2 == 1) 0];
And you will get the right output for start and finish.

How to find the indices of nonzero rows in a matrix?

How to find the indices of nonzero rows in a matrix?
Example:
A = [
14 0 6 9 8 17
85 14 1 3 0 99
0 0 0 0 0 0
29 4 5 8 7 46
0 0 0 0 0 0
17 0 5 0 0 49
]
the desired result :
V =[1 2 4 6]
You can use
ix = any(x,2);
any check whether there is any element that is not a zero. The second argument stands for "per-row" computation.
If you want to get the numeric index, you can use find function:
numIx = find(ix);
Another method:
ix = sum(abs(x),2)~=0;
Use
[i,~] = ind2sub(size(A),find(A));
v = unique(i);
Result for the matrix given above:
v = unique(i')
v =
1 2 4 6
Here's one that ab(uses) the fast matrix multiplication in MATLAB -
idx = find(abs(A)*ones(size(A,2),1))

Split an array in MATLAB

I have an array of integer numbers, and I want to split this array where 0 comes and a function that give me points of split.
Example: Array : 0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0
The function must return these numbers:
[ 3 10 ;14 20 ;22 25 ]
These numbers are index of start and end of nonzero numbers.
Here's a simple vectorized solution using the functions DIFF and FIND:
>> array = [0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0]; %# Sample array
>> edgeArray = diff([0; (array(:) ~= 0); 0]);
>> indices = [find(edgeArray > 0)-1 find(edgeArray < 0)]
indices =
3 10
14 20
22 25
The above code works by first creating a column array with ones indicating non-zero elements, padding this array with zeroes (in case any of the non-zero spans extend to the array edges), and taking the element-wise differences. This gives a vector edgeArray with 1 indicating the start of a non-zero span and -1 indicating the end of a non-zero span. Then the function FIND is used to get the indices of the starts and ends.
One side note/nitpick: these aren't the indices of the starts and ends of the non-zero spans like you say. They are technically the indices just before the starts and just after the ends of the non-zero spans. You may actually want the following instead:
>> indices = [find(edgeArray > 0) find(edgeArray < 0)-1]
indices =
4 9
15 19
23 24
Try this
a = [0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0];
%#Places where value was zero and then became non-zero
logicalOn = a(1:end-1)==0 & a(2:end)~=0;
%#Places where value was non-zero and then became zero
logicalOff = a(1:end-1)~=0 & a(2:end)==0;
%#Build a matrix to store the results
M = zeros(sum(logicalOn),2);
%#Indices where value was zero and then became non-zero
[~,indOn] = find(logicalOn);
%#Indices where value was non-zero and then became zero
[~,indOff] = find(logicalOff);
%#We're looking for the zero AFTER the transition happened
indOff = indOff + 1;
%#Fill the matrix with results
M(:,1) = indOn(:);
M(:,2) = indOff(:);
%#Display result
disp(M);
On the theme, but with a slight variation:
>>> a= [0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0];
>>> adjust= [0 1]';
>>> tmp= reshape(find([0 diff(a== 0)])', 2, [])
tmp =
4 15 23
10 20 25
>>> indices= (tmp- repmat(adjust, 1, size(tmp, 2)))'
indices =
4 9
15 19
23 24
As gnovice already pointed out on the positional semantics related to indices, I'll just add that, with this solution, various schemes can be handled very straightforward manner, when calculating indices. Thus, for your request:
>>> adjust= [1 0]';
>>> tmp= reshape(find([0 diff(a== 0)])', 2, []);
>>> indices= (tmp- repmat(adjust, 1, size(tmp, 2)))'
indices =
3 10
14 20
22 25

How to represent my Matlab matrix values in the following lattice-tree form?

I have my values of the lattice in the matrix as shown in fig 1:
Fig 1: Format of values as currently displayed in Matlab for my code
Now I would like to represent these values in form of lattice tree as shown in the figure 2 (Note the values in figure 2 are not same as in figure 1, and fig 2 is just for demonstration purpose). How could I modify my code in Matlab in order to have result that looks like the tree format shown in figure 2?:
Fig 2: Format of values as I want to be displayed in my Matlab result
Following is my code:
function [price,BLOV_lattice]=BLOV_general(S0,K,sigma,r,T,nColumn)
%% Constant parameters
del_T=T./nColumn; % where n is the number of columns
u=exp(sigma.*sqrt(del_T));
d=1./u;
p=(exp(r.*del_T)-d)./(u-d);
a=exp(-r.*del_T);
%% Initializing the lattice
Stree=zeros(nColumn+1,nColumn+1);
BLOV_lattice=zeros(nColumn+1,nColumn+1);
%% Developing the lattice
for i=0:nColumn
for j=0:i
Stree(j+1,i+1)=S0.*(u.^j)*(d.^(i-j));
end
end
for i=0:nColumn
BLOV_lattice(i+1,nColumn+1)=max(Stree(i+1,nColumn+1)-K,0);
end
for i=nColumn:-1:1
for j=0:i-1
BLOV_lattice(j+1,i)=a.*(((1-p).*BLOV_lattice(j+1,i+1))+(p.*BLOV_lattice(j+2,i+1)));
end
end
price=BLOV_lattice(1,1);
If your goal is to reformat an upper-triangular matrix (as shown in figure 1) into a matrix with the non-zero values arranged in a tree-like structure (as shown in figure 2), then you can accomplish this using the function SPDIAGS. Here's an example using a 5-by-5 matrix:
>> A = triu(reshape(1:25,5,5)) %# A sample upper-triangular matrix
A =
1 6 11 16 21
0 7 12 17 22
0 0 13 18 23
0 0 0 19 24
0 0 0 0 25
>> N = size(A,1); %# The size of the rows and columns in A
>> B = full(spdiags(spdiags(A),(1-N):2:(N-1),zeros(2*N-1,N)))
B =
0 0 0 0 21
0 0 0 16 0
0 0 11 0 22
0 6 0 17 0
1 0 12 0 23
0 7 0 18 0
0 0 13 0 24
0 0 0 19 0
0 0 0 0 25
I see a solution using only one for loop..
function B = newShape(A)
n = size(A,1);
B = zeros(2*n-1,n);
idx0 = n:(2*n):(2*n^2 - n);
B(idx0(1):(2*n-2):(2*n^2-n-1)) = A(1,:);
for i=n:(2*n-2)
B( idx0(i - n + 2):(2*n-2):(2*n^2-n) ) = A(i-(n-1)+1,i-(n-1)+1:end);
end
end