Create a matrix from a vector such that its height and width are powers of multiples in matlab - 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]

Related

Diagonal matrix in matlab

I am having trouble creating this matrix in matlab, basically I need to create a matrix that has -1 going across the center diagonal followed be 4s on the diagonal outside of that (example below). All the other values can be zero.
A5 = [-1 4 0 0 0;
4 -1 4 0 0;
0 4 -1 4 0;
0 0 4 -1 4;
0 0 0 4 -1];
I have tried using a command v = [4]; D = diag(v)
but that only works for the center diagonal.
This can also be done using a toeplitz matrix:
function out = tridiag(a,b,c,N)
% TRIDIAG generates a tri-diagonal matrix of size NxN.
% lower diagonal is a
% main diagonal is b
% upper diagonal is c
out = toeplitz([b,a,zeros(1,N-2)],[b,c,zeros(1,N-2)]);
>> tridiag(4,-1,4,5)
ans =
-1 4 0 0 0
4 -1 4 0 0
0 4 -1 4 0
0 0 4 -1 4
0 0 0 4 -1
Note #1: When your desired output is symmetric, you can omit the 2nd input to toeplitz.
Note #2: As the size of the matrix increases, there comes a point where it makes more sense to store it as sparse, as this saves memory and improves performance (assuming your matrix is indeed sparse, i.e. comprised mostly of zeros, as it happens with a tridiagonal matrix). Some useful functions are spdiags, sptoeplitzFEX and blktridiagFEX.
A little hackish, but here it goes:
N = 7; % matrix size
v = [11 22 33]; % row vector containing the diagonal values
w = [0 v(end:-1:1)];
result = w(max(numel(v)+1-abs(bsxfun(#minus, 1:N, (1:N).')),1))
This gives
result =
11 22 33 0 0 0 0
22 11 22 33 0 0 0
33 22 11 22 33 0 0
0 33 22 11 22 33 0
0 0 33 22 11 22 33
0 0 0 33 22 11 22
0 0 0 0 33 22 11
To understand how it works, see some intermediate steps:
>> abs(bsxfun(#minus, 1:N, (1:N).'))
ans =
0 1 2 3 4 5 6
1 0 1 2 3 4 5
2 1 0 1 2 3 4
3 2 1 0 1 2 3
4 3 2 1 0 1 2
5 4 3 2 1 0 1
6 5 4 3 2 1 0
>> max(numel(v)+1-abs(bsxfun(#minus, 1:N, (1:N).')),1)
ans =
4 3 2 1 1 1 1
3 4 3 2 1 1 1
2 3 4 3 2 1 1
1 2 3 4 3 2 1
1 1 2 3 4 3 2
1 1 1 2 3 4 3
1 1 1 1 2 3 4
Use D = diag(u,k) to shift u in k levels above the main diagonal, and D = diag(u,-k) for the opposite direction. Keep in mind that you need u to be in the right length of the k diagonal you want, so if the final matrix is n*n, the k's diagonal will have only n-abs(k) elements.
For you case:
n = 5; % the size of the matrix
v = ones(n,1)-2; % make the vector for the main diagonal
u = ones(n-1,1)*4; % make the vector for +1 and -1 diagonal
A5 = diag(v)+diag(u,1)+diag(u,-1) % combine everything together
Which gives:
A5 =
-1 4 0 0 0
4 -1 4 0 0
0 4 -1 4 0
0 0 4 -1 4
0 0 0 4 -1

How to normalize matrix setting 0 for minimum values and 1 for maximum values?

I need to transform a neural network output matrix with size 2 X N in zeros and ones, where 0 will represent the minimum value of the column and 1 contrariwise. This will be necessary in order to calculate the confusion matrix.
For example, consider this matrix 2 X 8:
2 33 4 5 6 7 8 9
1 44 5 4 7 5 2 1
I need to get this result:
1 0 0 1 0 1 1 1
0 1 1 0 1 0 0 0
How can I do this in MATLAB without for loops? Thanks in advance.
>> d = [ 2 33 4 5 6 7 8 9;
1 44 5 4 7 5 2 1];
>> bsxfun(#rdivide, bsxfun(#minus, d, min(d)), max(d) - min(d))
ans =
1 0 0 1 0 1 1 1
0 1 1 0 1 0 0 0
The bsxfun function is necessary to broadcast the minus and division operations to matrices of different dimensions (min and max have only 1 row each).
Other solution is the following (works only for 2 rows):
>> [d(1,:) > d(2,:); d(1,:) < d(2,:)]
ans =
1 0 0 1 0 1 1 1
0 1 1 0 1 0 0 0
If it's just 2xN, then this will work:
floor(A./[max(A); max(A)])
In general:
floor(A./repmat(max(A),size(A,1),1))

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

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.

how to find local maxima in image

The question is about feature detection concept.
I'm stuck after I finding the corner of image and I want to know how to finding the feature point within the computed corners.
Suppose I have grayscale image that have data like this
A = [ 1 1 1 1 1 1 1 1;
1 3 3 3 1 1 4 1;
1 3 5 3 1 4 4 4;
1 3 3 3 1 4 4 4;
1 1 1 1 1 4 6 4;
1 1 1 1 1 4 4 4]
if I use
B = imregionalmax(A);
the result would be like this
B = [ 0 0 0 0 0 0 0 0;
0 1 1 1 0 0 1 0;
0 1 1 1 0 1 1 1;
0 1 1 1 0 1 1 1;
0 0 0 0 0 1 1 1;
0 0 0 0 0 1 1 1]
The question is how do I pick the highest peak inside max local region (in sample how did I chose 5 from 3 and 6 from 4)?
My idea was using B to detect each region and use imregionalmax() again but I'm not good at coding and I need some advice or other ideas.
There are a couple of other easy ways to implement a 2D peak finder: ordfilt2 or imdilate.
ordfilt2
The most direct method is to use ordfilt2, which sorts values in local neighborhoods and picks the n-th value. (The MathWorks example demonstrates how to implemented a max filter.) You can also implement a 3x3 peak finder with ordfilt2 by, (1) using a 3x3 domain that does not include the center pixel, (2) selecting the largest (8th) value and (3) comparing to the center value:
>> mask = ones(3); mask(5) = 0 % 3x3 max
mask =
1 1 1
1 0 1
1 1 1
There are 8 values considered in this mask, so the 8-th value is the max. The filter output:
>> B = ordfilt2(A,8,mask)
B =
3 3 3 3 3 4 4 4
3 5 5 5 4 4 4 4
3 5 3 5 4 4 4 4
3 5 5 5 4 6 6 6
3 3 3 3 4 6 4 6
1 1 1 1 4 6 6 6
The trick is compare this to A, the center value of each neighborhood:
>> peaks = A > B
peaks =
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0
imdilate
Image dilation is usually done on binary images, but grayscale image dilation is simply a max filter (see Definitions section of imdilate docs). The same trick used with ordfilt2 applies here: define a neighborhood that does not include the center neighborhood pixel, apply the filter and compare to the unfiltered image:
B = imdilate(A, mask);
peaks = A > B;
NOTE: These methods only find a single pixel peak. If any neighbors have the same value, it will not be a peak.
The function imregionalmax gives you the 8-connected region containing the maximum and its 8 neighbours (i.e. the 3x3-regions you are seeing). You could then use morphological operations with the same 3x3 structural element to thin out those regions to their centers. E.g.
B = imregionalmax(A);
C = imerode(B, ones(3));
or equivalently
B = imregionalmax(A);
D = bwmorph(B, 'erode');
Alternatively you could write your own maximum finding function using block-processing:
fun = #(block) % your code working on 'block' goes here ...
B = blockproc(A, ones(3), fun)
But most likely this will be slower than the built-in functions.
(I don't have the toolbox available right now, so I can't try that out.)
Also have a look here and here.

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