I have the following matrix:
A= [23 34 45 0 0 0; 21 34 0 0 23 11; 34 23 0 0 0 22]
I want to find if a value is present and if it's present, I want to find the following values.
Eg I want to find in A the value 23, if it's present I want like output a matrix only with 23 and its following values
B= [23 34 45 0 0 0; 0 0 0 0 23 11; 0 23 0 0 0 22]
This is an interesting question, and I have a non-loopy answer, it uses the interesting effect of cumsum and find to great efficiency.
G = zeros(size(A));
T = find(A==23);
G(T) = 1;
mask = cumsum(G,2)>0;
result = mask .* A;
>> result =
23 34 45 0 0 0
0 0 0 0 23 11
0 23 0 0 0 22
This is I think, one of the more efficient way of doing this.
========EDIT========
even better, use logical indexing:
B = A.*(cumsum(A==23,2)>0);
Thanks to #obchardon
find() returns the row and the column of the desired value, in your case "23", in matrix A.
using a for loop you can copy the value and its following ones:
A = [23 34 45 0 0 0; ...
21 34 0 0 23 11; ...
34 23 0 0 0 22];
[r, c] = find(A==23);
B = zeros(3,6);
for i=1:length(r)
columns = c(i):length(B);
B(i,columns) = A(r(i),columns);
end;
Related
Suppose I have two matrices:
A= [0 0 0 0 1;
0 0 0 1 0;
1 0 1 0 1;
0 0 0 0 0;
0 0 1 1 1]
B = [20 15 25 30 40;
12 15 25 38 24;
50 23 37 21 19;
7 20 89 31 41;
12 13 45 21 31]
How to make all the entries in a row of B nan the first time 1 appears in A. in this case I want the output to be:
B = [20 15 25 30 Nan;
12 15 25 Nan Nan;
Nan Nan Nan Nan Nan;
7 20 89 31 41;
12 13 Nan Nan Nan]
Thank you in advance
You can use cummax or cumsum and logical indexing to set the values to NaN:
B(logical(cumsum(A,2)))=NaN;
or
B(logical(cummax(A,2)))=NaN;
A simple solution can be using from a loop to consider each row:
for idx = 1 : size(B,1)
foundOne = find(A(idx,:) == 1);
B(idx, foundOne:end) = NaN;
end
You want to place NaN in B where there is 1 in the A. It can be simply achieved with one step.
A= [0 0 0 0 1;
0 0 0 1 0;
1 0 1 0 1;
0 0 0 0 0;
0 0 1 1 1] ;
B = [20 15 25 30 40;
12 15 25 38 24;
50 23 37 21 19;
7 20 89 31 41;
12 13 45 21 31] ;
B(A==1) = NaN ;
I'm new to Matlab programming and I've only had 3 classes so far. I'm having problem with my homework. (Also I am from Iceland so english is not my first language, so please forgive my grammar)
I'm given a matrix, A and I'm supposed to change the value? of a vector to 0 if it is an even number and to 1 if it is an odd number.
This is what I have so far.
A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
B = zeros(size(A));
for k = 1:length(A)
if mod(A(k),2)== 0 %%number is even
B(k) = 0;
else
B(k) = 1; %%number is odd
end
end
B(A,2==0) = 0;
B(A,2~=0) = 1
What I am getting it this:
B =
0 0 0 0 0 0
1 1 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
If anyone could please help me, it would be greatly appreciated :)
You are very close. Don't use length(A) - use numel(A). length(A) returns the number of elements along the largest dimension. As such, because you have 6 columns and 4 rows, this loop will only iterate 6 times. numel returns the total number of elements in the array A, which is what you want as you want to iterate over each value in A.
Therefore:
A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
B = zeros(size(A));
for k = 1:numel(A) %// Change
if mod(A(k),2)== 0 %%number is even
B(k) = 0;
else
B(k) = 1; %%number is odd
end
end
The above loop will go through every single element in the matrix and set the corresponding element to 0 if even and 1 if odd.
However, I encourage you to use vectorized operations on your code. Don't use loops for this. Specifically, you can do this very easily with a single mod call:
B = mod(A,2);
mod(A,2) will compute the modulus of every value in the matrix A with 2 as the operand and output a matrix B of the same size. This will exactly compute the parity of each number.
We get for B:
>> A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
>> B = mod(A,2)
B =
0 0 1 1 0 0
1 1 0 0 0 0
1 1 0 1 1 0
1 1 0 1 0 1
I want to implement the JPEG compression by using MATLAB. Well at the point where the symbols' probabilities (Huffman coding) are calculated i can see some NEGATIVE values. I am sure that this is not correct!!! if someone can give some help or directions i would really appreciate it. Thank all of you in advance. I use MATLAB R2012b. Here is the code:
clc;
clear all;
a = imread('test.png');
b = rgb2gray(a);
b = imresize(b, [256 256]);
b = double(b);
final = zeros(256, 256);
mask = [1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 0
1 1 1 1 1 0 0 0
1 1 1 1 0 0 0 0
1 1 1 0 0 0 0 0
1 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0];
qv1 = [ 16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99];
t = dctmtx(8);
DCT2D = #(block_struct) t*block_struct.data*t';
msk = #(block_struct) mask.*block_struct.data;
for row = 1:8:256
for column = 1:8:256
x = (b(row:row+7, column:column+7));
xf = blockproc(x, [8 8], DCT2D);
xf1 = blockproc(xf, [8 8], msk);
xf1 = round(xf1./qv1).*qv1;
final(row:row+7, column:column+7) = xf1;
end
end
[symbols,p] = hist(final,unique(final));
bar(p, symbols);
p = p/sum(p); %NEGATIVE VALUES????
I think you might have the outputs of hist (symbols and p) swapped. The probability should be calculated from the bin counts, which is the first output of hist.
[nelements,centers] = hist(data,xvalues) returns an additional row vector, centers, indicating the location of each bin center on the x-axis. To plot the histogram, you can use bar(centers,nelements).
In other words, instead of your current line,
[symbols,p] = hist(final,unique(final));
just use,
[p,symbols] = hist(final,unique(final));
Also, final is a matrix rather than a vector, so nelements will be a matrix:
If data is a matrix, then a histogram is created separately for each column. Each histogram plot is displayed on the same figure with a different color.
Still very new to programming...
I have 9x1 Vectors at time t, t+1, t+2 etc.
[10 10 10 10 10 10 10 10 10]'
and matrices. Each matrix is 9x9 and also at time 1, t+1, t+2 etc. =
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1
They are 3d matrices and I want to make them 4d in the future.
I want to multiply vector(:,:,t) with the diagonal of matrix at time t and output vector(:,:,t+1).
So in short...
vector t multiplied by diag matrix t = vector t+1
vector t+1 multiplied by diag matrix t+1 = vector t+2
vector t+2 multiplied by diag matrix t+2 = vector t+3 ... and so on.
the diagonal numbers change in each time step but for simplicity sake, let's keep them all at 1 for the moment.
I've tried using diag but it states I have to use a 2D input so only works when I ignore t.
Cheers for your help guys - it's helping me learn a lot. Any hints or solutions will be much appreciated. I know you guys know the simplest and most efficient solutions.
Since the result of each step depends on the previous iteration, it cannot be vectorized. So I would go with #JohnColby's solution.
For what it's worth, here is an example how you would extract the diagonals of a 3D matrix in a vectorized way:
M = reshape(1:3*4*3,[3 4 3]);
[r,c,p] = size(M);
ind = bsxfun(#plus, (1:r+1:r*c)', (0:p-1).*r*c);
M(ind)
Each column of the result corresponds to the diagonal elements from each slice (doesn't have to be square matrix):
>> M
M(:,:,1) =
1 4 7 10
2 5 8 11
3 6 9 12
M(:,:,2) =
13 16 19 22
14 17 20 23
15 18 21 24
M(:,:,3) =
25 28 31 34
26 29 32 35
27 30 33 36
>> M(ind)
ans =
1 13 25
5 17 29
9 21 33
Here you go:
n = 10;
% Make sample data
t = zeros(9,1,n);
t(:,1,1) = 1;
T = repmat(diag(ones(9,1)), [1 1 n]);
% Loop though to fill in t based on previous t and T
for i = 2:n
t(:,1,i) = t(:,1,i-1) .* diag(T(:,:,i-1));
end
Now all of t should be 1.
I have a matrix in MATLAB. I want to check the 4-connected neighbours (left, right, top, bottom) for every element. If the current element is less than any of the neighbours then we set it to zero otherwise it will keep its value. It can easily be done with loop, but it is very expensive as I have thousands of these matrices.
You might recognize it as nonmaxima suppression after edge detection.
If you have the image processing toolbox, you can do this with a morpological dilation to find local maxima and suppress all other elements.
array = magic(6); %# make some data
msk = [0 1 0;1 0 1;0 1 0]; %# make a 4-neighbour mask
%# dilation will replace the center pixel with the
%# maximum of its neighbors
maxNeighbour = imdilate(array,msk);
%# set pix to zero if less than neighbors
array(array<maxNeighbour) = 0;
array =
35 0 0 26 0 0
0 32 0 0 0 25
31 0 0 0 27 0
0 0 0 0 0 0
30 0 34 0 0 16
0 36 0 0 18 0
edited to use the same data as #gnovice, and to fix the code
One way to do this is with the function NLFILTER from the Image Processing Toolbox, which applies a given function to each M-by-N block of a matrix:
>> A = magic(6) %# A sample matrix
A =
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
>> B = nlfilter(A,[3 3],#(b) b(5)*all(b(5) >= b([2 4 6 8])))
B =
35 0 0 26 0 0
0 32 0 0 0 25
31 0 0 0 27 0
0 0 0 0 0 0
30 0 34 0 0 16
0 36 0 0 18 0
The above code defines an anonymous function which uses linear indexing to get the center element of a 3-by-3 submatrix b(5) and compare it to its 4-connected neighbors b([2 4 6 8]). The value in the center element is multiplied by the logical result returned by the function ALL, which is 1 when the center element is larger than all of its nearest neighbors and 0 otherwise.
If you don't have access to the Image Processing Toolbox, another way to accomplish this is by constructing four matrices representing the top, right, bottom and left first differences for each point and then searching for corresponding elements in all four matrices that are non-negative (i.e. the element exceeds all of its neighbours).
Here's the idea broken down...
Generate some test data:
>> sizeA = 3;
A = randi(255, sizeA)
A =
254 131 94
135 10 124
105 191 84
Pad the borders with zero-elements:
>> A2 = zeros(sizeA+2) * -Inf;
A2(2:end-1,2:end-1) = A
A2 =
0 0 0 0 0
0 254 131 94 0
0 135 10 124 0
0 105 191 84 0
0 0 0 0 0
Construct the four first-difference matrices:
>> leftDiff = A2(2:end-1,2:end-1) - A2(2:end-1,1:end-2)
leftDiff =
254 -123 -37
135 -125 114
105 86 -107
>> topDiff = A2(2:end-1,2:end-1) - A2(1:end-2,2:end-1)
topDiff =
254 131 94
-119 -121 30
-30 181 -40
>> rightDiff = A2(2:end-1,2:end-1) - A2(2:end-1,3:end)
rightDiff =
123 37 94
125 -114 124
-86 107 84
>> bottomDiff = A2(2:end-1,2:end-1) - A2(3:end,2:end-1)
bottomDiff =
119 121 -30
30 -181 40
105 191 84
Find the elements that exceed all of the neighbours:
indexKeep = find(leftDiff >= 0 & topDiff >= 0 & rightDiff >= 0 & bottomDiff >= 0)
Create the resulting matrix:
>> B = zeros(sizeA);
B(indexKeep) = A(indexKeep)
B =
254 0 0
0 0 124
0 191 0
After wrapping this all into a function and testing it on 1000 random 100x100 matrices, the algorithm appears to be quite fast:
>> tic;
for ii = 1:1000
A = randi(255, 100);
B = test(A);
end; toc
Elapsed time is 0.861121 seconds.