How to do logical operations between two matrices in matlab - matlab

I have two matrices. One is PR1 an identity matrix and another inverse identity matrix PR2. Reference Matrix A is mentioned that can be 5x5 10x10 etc. According to that I1,I2 is created.Here it is mentioned 5x5 matrix.
The logical operations start with And= PR1 AND PR2 followed by Xor= PR1 XOR PR2.
A matrix:
A =
0 1 1 1 0
1 0 1 1 0
1 1 0 1 1
1 1 1 0 1
0 0 1 1 0
I is identity matrix
PR1 =
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
PR2 =
0 0 0 0 1
0 0 0 1 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 0
And =
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
Xor =
1 0 0 0 1
0 1 0 1 0
0 0 0 0 0
0 1 0 1 0
1 0 0 0 1
Now scan left to right of each row in And and Xor matrices. Place the first 1 as it is in the new row that is in R1 matrix. Trace for second one and do NOR operation between first one 1 row and second 1 row in A matrix in above matrix (1,5) is second 1 place so do NOR operation between 1st and 5th row place the answer in R1matrix. Similarly it has R1.
R1 =
1 0 0 0 1
0 0 0 0 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 1
Now replace R1 to PR2
new
PR2 =
1 0 0 0 1
0 0 0 0 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 1
Again repated same process PR1 AND PR2 followed by PR1 XOR PR2
And =
1 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 1
Xor =
0 0 0 0 1
0 1 0 0 0
0 0 0 0 0
0 1 0 1 0
1 0 0 0 0
Now scan left to right of each row in And and Xor matrices. Place the first 1 as it is in the new row that is in R1 matrix. Trace for second one and do NOR operation between first one 1 row and second 1 row in A matrix in above matrix (1,5) is second 1 place so do NOR operation between 1st and 5th row place the answer in R2matrix.
R2=
1 0 0 0 1
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
1 0 0 0 1
check all column has minimum one 1 and stop

PR1 AND PR2 is the same as: PR1 * PR2
C = xor(A,B)
(source).
Finding the identity matrix there is a build in function. Identity matrix (I believe that is it, I don't know why it is called "eye")
You should really google stuff, like: "xor matlab matrix". There really isn't much thinking involved with getting these. You probably put more effort into writing your question.

That is quite straight forward
PR1 = eye(size(A,1));
PR2 = flip(PR1);
AND = and(PR1,PR2);
XOR = xor(PR1,PR2);
k = find(And~=0,1,'first');
R1 = zeros(size(A,1));
R1(k) = And(k);
idx = find(Xor~=0, 1, 'first');
R1(idx) = Xor(idx);
and if you want to do the NOR operations for row 1 and row 5 then you do
R1(1,:) = !(or(A(1,:),A(5,:)))
R1(2,:) = !(or(A(2,:),A(4,:)))
R1(4,:) = !(or(A(2,:),A(4,:)))
R1(5,:) = !(or(A(1,:),A(5,:)))
PR2 = R1
from here repeat your process as you need.

Related

What is the result of dilation of this image?

I have this following matrix:
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 0 0 0
1 1 0 0 0 0 0
1 0 0 0 0 1 1
1 0 0 0 0 1 1
And I want to dilate it with the following structuring element:
1 0 0
1 1 1
1 1 1
I already did dilation on Matlab but the result does not match with the one I did by hand. So I guess I missing something here. As far as I know if any '1' of the structuring element touches any of the '1' in the matrix, then it means it is a hit and the center of the current window should be set as 1. If I make dilation in such fashion I would get following (without considering edges):
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 1 1 0 0 0 0
1 1 1 0 1 1 0
1 1 1 0 1 1 1
1 0 0 0 0 1 1
But Matlab gives the following result:
0 0 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
1 1 1 0 1 1 0
1 1 1 0 1 1 1
1 1 0 0 1 1 1
Without considering edges it almost looks like my result but pixels styled with bold are '1' in my result but '0' in Matlab's result. What am I doing wrong? Pixel just below those '0's are '1's in the original image and the structuring element has '1' at that space when the center of the window is on those '0's so it is a hit and the center must be set '1' but Matlab doesn't do this. Can anyone explain me why? Am I missing something essential here?
Suppose matrix A is your image and matrix B is structuring element. You should pad the matrix A with zeroes on all sides. So let's say you have matrix C. Then you should perform Logical AND operation of C and B. The result matrix called D will be a dilated matrix. For further information, please see here.
Here is the code of Matlab which dilate image without 'imdilate' function:
clc;clearvars;close all;
%Image Dilation without using 'imdilate' function
% Matrix A is our image
A=[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 0 0 0;
1 1 0 0 0 0 0;
1 0 0 0 0 1 1 ;
1 0 0 0 0 1 1 ];
%Structuring element
B=[1 0 0; 1 1 1; 1 1 1];
%Pad zeros on all the sides
C=padarray(A,[1 1]);
%Intialize a matrix of matrix size A with zeros
D=false(size(A));
for i=1:size(C,1)-2
for j=1:size(C,2)-2
%Perform logical AND operation
D(i,j)=sum(sum(B&C(i:i+2,j:j+2)));
end
end
display(D);
And this is my output, dilated matrix D:

Advanced Search and Remove in special Matrix

I have this matrix
X= [2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
4 0 0 1 0 1 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 250;
4 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
3 1 1 1 0 0 1 0 0 1 0 0 1 0 0 0 0 1 0 1 0 0 400]
I need to do three different sequence things in this matrix:
1- Search in this matrix to the following sequence 1 1 0 0 0 and write those rows that have this characteristic in new matrix (like row 1).
2- Use the matrix that generate in the first step and remove from it to the rows that have the same number in the same digits (like row 1,3,7) but at the same time keep only one row of each one (in the case of row 1,3,7 keep row 1 and remove other rows) .
3- use the matrix that generate in the second step and remove from this matrix any row that have following sequence 1 1 1 (like row 8) and put the other rows in this matrix in new matrix.
%Step-1
% Converting the matrix into a string, appending a semi-colon for similarity and removing the brackets from the string
req=mat2str(X); req(end)=';' ; req=req(2:end);
% Searching the sequence: 1 1 0 0 0
sp1=strfind(req, '1 1 0 0 0');
% Storing those rows of X in req matrix which contain the sequence
req=X(unique(ceil([sp1]/(size(req,2)/size(X,1)))),:);
%Step-2
req= unique(req,'rows');
%Step-3
% Converting the matrix into a string, appending a semi-colon for similarity and removing the brackets from the string
reqtemp=mat2str(req); reqtemp(end)=';' ; reqtemp=reqtemp(2:end);
% Searching the sequence: 1 1 1
sp1=strfind(reqtemp, '1 1 1');
% Removing those rows which contain the sequence
req(unique(ceil([sp1]/(size(reqtemp,2)/size(req,1)))),:)=[];

How do I create random matrix where each column is all zeroes except for one random row?

I want to create a matrix of size m-by-n where all elements in a column are 0 except one element which is 1. That one element must be at a random position.
eg.
[0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 0 1]
To add some variety, here's another approach:
m = 4;
n = 5;
[~, result] = sort(rand(m,n));
result = double(result==1);
This gives, for example,
result =
0 0 0 0 1
0 1 0 0 0
1 0 0 1 0
0 0 1 0 0
You can also use rand and max to do the job:
m=4;
n=5;
R=rand(m,n);
result = bsxfun(#eq, R, max(R,[],1))
On my machine it gave:
1 1 0 0 0
0 0 0 0 0
0 0 1 0 1
0 0 0 1 0
How it works: Generating a random matrix, R, and then setting to 1 the entry corresponding to the maximal element at each column. No need for sorting.
Regarding the original answer of Divakar, since it uses randperm it is restricted to square matrix only, and it will only produce random permutation matrices.
One possible way to correct his solution is to use randi instead of randperm:
result = bsxfun( #eq, (1:m)', randi(m, 1, n ) )
May give this output:
1 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
As for the answer of bla, using accumarry can save the use of zeros and sub2ind:
m=5; n=10;
R=randi(m,n,1);
A = accumarray( {R, (1:n)' }, 1, [m n] )
May give this output:
0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Another idea I have is to create the identity matrix of size m x m, then use randi with a range from 1 up to m to create a vector of n elements long. After, you'd use this vector to access the columns of the identity matrix to complete the random matrix you desire:
m = 5; n = 5; %// Given your example
M = eye(m);
out = M(:,randi(m, n, 1));
Here's one possible run of the above code:
out =
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 1 1 0 1
here's an example using randi:
m=5; n=10;
A=zeros(m,n);
R=randi(m,n,1);
A(sub2ind(size(A),R',1:n))=1
A =
0 0 0 0 0 0 0 1 0 1
0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0
You can use sparse with randi for a one-liner, like so -
full(sparse(randi(m,1,n),1:n,1,m,n))
Sample run -
>> m = 5; n = 6;
>> full(sparse(randi(m,1,n),1:n,1,m,n))
ans =
0 1 0 0 0 1
0 0 1 1 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0

Extract multiple indices from matrix

I want to access multiple indices of a matrix as shown below. So what I want is indices (1,3),(2,6),(3,7) to be set to one. However, as you can see the entire column is set to one. I can see what it is doing but is there a way to do what I want it to (in an elegant way - no loops).
a=zeros(3,10)
a(1:3,[3 6 7])=1
a =
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
I realise that you can do something along the lines of
x_idx=1:3, y_idx=[3 6 7];
idx=x_idx*size(a,2)+y_idx;
a(idx)=1;
but just wondering if there was a better, or proper way of doing this in Matlab
You can use sub2ind, which essentially is doing what you have mentioned in your post, but MATLAB has this built-in:
a = zeros(3,10);
a(sub2ind(size(a), 1:3, [3 6 7])) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
Another way would be to create a logical sparse matrix, then use this to index into a:
a = zeros(3,10);
ind = logical(sparse(1:3, [3 6 7], true, size(a,1), size(a,2)));
a(ind) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0

Matlab: sort an array to ascending order in terms of binary interpretation

The array contains binary numbers per line: one row means one binary number. They are in no order so I am trying to find a command by which I can sort them to ascending order, how to do it?
Input
>> [1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0]
ans =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
Goal: by which command I can get by the input the below output?
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
You can do it by converting to strings (num2str) and then from binary string to number (bin2dec):
[vv ii] = sort(bin2dec(num2str(data)));
data_sorted = data(ii,:);
Based on my suggestion in the comments, "you should be able to do a radix sort using sortrows on columns n down to 1.", the OP got the following code working:
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1];sortrows(A)
ans =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
And has now included Luis' cool idea for indexing.
Beaker answered in the comment "you should be able to do a radix sort using sortrows on columns n down to 1." -- and it works! Then Luis Mendo had a method to store the original positioning so putting the ideas together, vuola!
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1]
[vv ii]=sortrows(A)
A =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
vv =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
ii =
4
2
1
3