How to apply logical indexing on multi-dimension matrix in matlab - matlab

My question is simple. I have an rgb image and a logical matrix. I want to set the pixel which is true in the corresponding element of logical matrix to (150,160,170).
For example:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0
r= 1 1 1 1 1 g= 1 1 1 1 1 b=1 1 1 1 1 logical_mat =1 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0
I want it results in
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
r= 150 1 1 1 1 g= 160 1 1 1 1 b=170 1 1 1 1
150 150 1 1 1 160 160 1 1 1 170 170 1 1 1
150 150 150 1 1 160 160 160 1 1 170 170 170 1 1
I have tried logical index, if set pixel into same color is easy
lm = repmat(logical_mat,[1 1 3]);
rgb(lm) = 150;
But I dont know how to set the value channel by channel.
Thanks in advance.

You're already creating the right logical matrix:
lm = repmat(logical_mat,[1 1 3]);
You need to create a 3-channel color matrix the same size.
cm = repmat(cat(3,150,160,170), size(lm,1), size(lm,2))
Then, index into the color matrix with lm:
rgb(lm) = cm(lm);

Related

What matlab command, or combination of commands (using 25 characters or less), could be used to create the following matrix?

What matlab command, or combination of commands (using 25 characters or less), could be used to create the following matrix?
1 0 0 0 0 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 1 0 0 1 1 1 0 0
1 1 1 1 0 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 1 0 0 1 1 1 0 0
1 1 1 1 0 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 1 0 0 1 1 1 0 0
1 1 1 1 0 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
Hint: Look for a lower triangluar matrix that is repeated many times. First try to produce that lower triangular matrix with as few characters as possible.
You can use the following code:
A = ones(5); % create 5x5 matrix with all elements 1
B = tril(A); % return the lower triangle matrix of A
C = repmat(B, 3, 2); % repeat the matrix B, 3 times in a row and 2 times in a cloumn as you want.
In more details:
A = ones(5);
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
B = tril(A);
1 0 0 0 0
1 1 0 0 0
1 1 1 0 0
1 1 1 1 0
1 1 1 1 1
C = repmat(B, 3, 2);
1 0 0 0 0 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 1 0 0 1 1 1 0 0
1 1 1 1 0 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 1 0 0 1 1 1 0 0
1 1 1 1 0 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 1 0 0 1 1 1 0 0
1 1 1 1 0 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
A solution using rempat and implicit expansion:
repmat(1:5<(2:6)',3,2)

MATLAB: Identify maxima and minima and split data accordingly

I have the following arrays:
x = [1:33];
y = [0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 3 2 1 0 1 2 1 0 1 2 3 4 3 2 1 0];
I need to separate y into different sections. I need to obtain the ascending parts, the descending parts, and the combined ascending and descending parts.
For example:
Ascending parts = [1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 0 0 1
1 1 1 0 0 0 0];
Descending parts = [0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1
1 1 1 1 0 0 1 1 0 0 0 0 1 1 1 1];
Combined parts = [1 1 1 1 1 1 1 1 1
1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 4 4 4 4 4 4 4 4];
I can, of course, do this manually for these arrays, but I need to do this for arrays with hundreds of thousands of points and I wish to do it automatically. I have been playing around with the findpeaks functions but this isn't straightforward as it sometimes picks up peaks during the descending/ascending parts, rather than at the end points.
Any tips on how I can do this?
version MATLAB 2017/b
For a problem like this, you should consider using Matlab's diff.
For y = [0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 3 2 1 0 1 2 1 0 1 2 3 4 3 2 1 0];
a=diff(y)
1 1 1 1 1 -1 -1 -1 -1 -1 1 1 1 1 1 -1 -1 -1 -1 -1 1 1 -1 -1 1 1 1 1 -1 -1 -1 -1
b=a, c =a;
b(b<0)=0;
c(c>0)=0;
Will give you:
b = 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0
c = 0 0 0 0 0 -1 -1 -1 -1 -1 0 0 0 0 0 -1 -1 -1 -1 -1 0 0 -1 -1 0 0 0 0 -1 -1 -1 -1
For the second part, you can do the following:
z=diff(y, 2);
zd=[0 find(z~=0);0 z(find(z~=0))]
0 5 10 15 20 22 24 28 32
0 -2 2 -2 2 -2 2 -2 2
Assuming that this is how your function looks like in general, the above pattern shows convex and concave regions in the sequence. With this assumption, the following should work in your case:
za=[0 zd(1,zd(2,:)>0)];
zad=diff(za);
cell2mat(arrayfun(#(x,y) repelem(x,y), 1:length(zad),zad,'UniformOutput',false))
ans: 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 4 4 4 4 4 4 4 4
which I believe is close to what you want. Hope this helps.

label over specific cells (index) in imagesc

I have created this map of Jamaica using matrix A. I want to insert text labels on this image at specific indexes for cities. For Example kingston on this map is at point 15, 38, where 15 is the row and 38 the column, this point I would label "kingston". My matrix is below and the image of it generated from imagesc is below as well. I was playing around with get(gca, 'position') but that was not successful.
% Cities
kingston = [15 38];
montegoBay = [4 15];
portRoyal = [18 31];
stThomas = [10 55];
mandeville = [13 21];
ochoRios = [2 29];
A = [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 3 3 0 0 0 0 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 3 0 0 0 0 3 0 3 3 3 0 0 0 0 3 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 3 3 3 0 3 0 3 3 3 3 0 3 0 3 0 3 3 3 0 3 3 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 3 3 3 0 0 0 3 3 3 3 3 3 0 3 0 3 0 0 0 0 0 0 3 0 0 0 3 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 0 0 3 3 0 0 0 3 3 3 3 3 0 3 3 3 3 0 0 0 0 0 0 0 0 0 3 0 0 0 3 3 3 0 3 3 3 3 0 0 3 0 0 1 1 1 1 1 1 1 1 1 1;
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 3 3 3 0 0 3 3 0 3 0 0 0 0 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1;
1 0 3 0 3 3 0 0 0 3 3 3 0 3 0 3 3 3 3 3 0 3 3 3 0 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 3 3 3 0 0 0 0 0 0 0 0 0 0 1;
1 0 0 0 0 0 3 0 0 0 0 0 0 0 0 3 3 3 0 0 0 0 0 0 0 0 3 3 3 3 3 0 3 0 3 3 0 0 3 3 3 0 0 3 0 0 3 0 3 3 0 3 0 3 0 1;
1 1 1 0 0 0 0 0 0 3 3 3 3 0 0 3 3 3 3 3 3 3 3 0 3 3 3 0 0 0 3 3 3 3 0 3 3 0 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1;
1 1 1 1 1 1 1 1 0 0 0 0 0 0 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 1 0 0 0 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 3 3 0 3 0 0 3 3 3 3 3 3 0 3 0 0 0 0 0 3 3 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 3 3 3 3 0 0 0 0 0 3 3 3 3 3 3 0 3 0 3 0 3 3 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 3 3 3 0 0 0 0 0 0 0 3 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 0 3 0 1 1 1 1 1 3 0 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 0 3 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1];
Cmap = [1 1 1; 0 0 1; 0 1 0];
colormap(Cmap);
imagesc(A);
axis off
You should use the function text like this:
text(38,15,'kingston')
i.e. in opposite order, because your axis is in i-j direction, and not x-y (try typing axis xy to see what I mean).
(I have changed the font size to 15: text(38,15,'kingston','FontSize',15))
If you want to go a step further, define your cities as a cell array:
Cities = {'kingston','montegoBay','portRoyal','stThomas','mandeville','ochoRios'};
and their location in a matrix:
location = [15 38;
4 15;
18 31;
10 55;
13 21;
2 29];
And then all you need is one text command:
text(location(:,2),location(:,1),Cities,'FontSize',12)
to get the final result:
You can use text function to do that as:
text(x,y,'MyText')
See the documentation for more info:
https://www.mathworks.com/help/matlab/ref/text.html
Hope it helps.

Generating a matrix containing 3 numbers

I am trying to create an 8x8 matrix containing 0s, 1s and 2s. Each row and each column should contain two 0s, three 1s and three 2s.
Previously I have used the below to generate an example containing only 1s and 0s.
output = zeros(8, 8);
for i=1:8
tmp = (1:8) + (i);
tmp = rem(tmp, 4);
output(i,:) = tmp;
output(i,:) = tmp > 0;
end
output =
1 1 0 1 1 1 0 1
1 0 1 1 1 0 1 1
0 1 1 1 0 1 1 1
1 1 1 0 1 1 1 0
1 1 0 1 1 1 0 1
1 0 1 1 1 0 1 1
0 1 1 1 0 1 1 1
1 1 1 0 1 1 1 0
However I would now like something similar to the following:
output =
1 1 0 1 2 2 0 2
1 0 1 2 2 0 2 1
0 1 2 2 0 2 1 1
1 2 2 0 2 1 1 0
2 2 0 2 1 1 0 1
2 0 2 1 1 0 1 2
0 2 1 1 0 1 2 2
2 1 1 0 1 2 2 0
Thanks for your help.
What you have in your example is a Hankel matrix so you could use the hankel function
c = [1 1 0 1 2 2 0 2];
k = [2 1 1 0 1 2 2 0];
A = hankel(c,k)
where c is the first column of the output matrix and k is the last row.
Making your output matrix a Hankel matrix is a good idea (based on your requirements) as it will enforce the row and column frequency counts for each value. You would not necessarily get this just by creating rows that are random permutations of a base row (using randperm for example) as duplicate rows would be possible which would break your column requirements.
As an example, if you want random c with fixed numbers of specific elements, you can randomly permute a base vector containing the required values and frequencies - as per your requirement this would be
c = [0 0 1 1 1 2 2 2];
index = randperm(numel(c));
c = c(index);
c =
0 2 0 2 2 1 1 1
To get the square Hankel structure then choose k to be the next cyclic permutation of c
k = circshift(c',1)'
k =
1 0 2 0 2 2 1 1
and just call hankel with these as mentioned above
A = hankel(c,k)
A =
0 2 0 2 2 1 1 1
2 0 2 2 1 1 1 0
0 2 2 1 1 1 0 2
2 2 1 1 1 0 2 0
2 1 1 1 0 2 0 2
1 1 1 0 2 0 2 2
1 1 0 2 0 2 2 1
1 0 2 0 2 2 1 1
The above output is based on what I got on my machine based on the output from randperm.
Any output matrix generated using the above will meet your requirements specified in the question.

Using 25 characters or less to create a specific matrix in MATLAB

What matlab command, or combination of commands (using 25 characters or less), could be used to create the following matrix?
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
I got as far as this;
repmat(tril(ones(3,3)),5)
But repmat creates a 5 by 5 matrix. I however, need a 4,5 matrix.
Thank you for taking the time to help!
Add one more argument to repmat and remove one from ones (as Divakar noted):
repmat(tril(ones(3)),4,5)
As you can see, you can specify how many replications you want for both the rows and the columns. A single value argument to either function will use that value for both rows and columns.
I'll throw the kron solution out there. Just because.
kron(ones(4,5),tril(ones(3)))
More than 25 characters, but hey:
bsxfun(#le,mod(0:3*5-1,3),mod(0:3*4-1,3).')