Check whether unit cell forms a "whole piece" in MATLAB? - matlab

I wish to check whether a square unit cell, when repeated side by side, forms a valid "whole piece" or not. I am sorry that I may not have described it in an accurate way, but I really do not know how to say this using scientific terms. Let me give you two examples, one for "whole piece" and the other for "not whole piece".
1 represents rubber, and 0 represents air.
"whole piece"
0 0 1 0 0 0
0 0 1 0 0 0
1 1 1 0 1 1
0 0 1 1 1 0
0 0 1 0 0 0
0 0 1 0 0 0
"not whole piece"
0 0 1 0 0 0
0 0 1 0 0 0
1 1 1 0 1 1
0 0 0 1 1 0
0 0 1 0 0 0
0 0 1 0 0 0
As you can see, in the "whole piece" case, one can find a path (diagonal counted) from top to bottom and left to right, whereas in the "not whole piece", the path is broken. So if you lift the periodic structure up, part of it will fall apart.
How can I do it efficiently in MATLAB? Is there an efficient way? Built-in?
Update
Actually, even if bwconncomp() returns 1, the periodic structure may not be connected. Let's consider this example.
A =
0 0 0 1 0 0
0 0 1 1 0 0
1 1 1 0 1 0
0 0 1 1 1 1
0 0 1 0 0 0
0 0 1 0 0 0
>> bwconncomp(A, 4)
>> 1
If I show 4 A blocks, then it is like
A | A
-----
A | A
0 0 0 1 0 0 | 0 0 0 1 0 0
0 0 1 1 0 0 | 0 0 1 1 0 0
1 1 1 0 1 0|1 1 1 0 1 0
0 0 1 1 1 1 | 0 0 1 1 1 1
0 0 1 0 0 0 | 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 1 0 0
0 0 1 1 0 0 | 0 0 1 1 0 0
1 1 1 0 1 0 | 1 1 1 0 1 0
0 0 1 1 1 1 | 0 0 1 1 1 1
0 0 1 0 0 0 | 0 0 1 0 0 0
0 0 1 0 0 0 | 0 0 1 0 0 0
So as you can see, the 1 on the left side collides with the 0 on the right side of another A, causing the thing not a "whole piece". (Placed with no space deliberately to make it patent).

The term is "connected". Equivalently, each piece is called a connected component.
Use bwconncomp (Image Processing Toolbox) to determine the number of connectrd components. Let A denote your matrix. Then
c = bwconncomp(A,4);
returns a structure c whose NumObjects field indicates how many connected components there are in A. The input argument "4" is the number of neighbours you want to consider to defin connectedness: either 4 (don't take diagonals into account; that semes to be what you want) or 8 (include diagonals). So, just check if
c.NumObjects
is 1 ("whole piece") or more than 1 ("not whole piece"). In your examples, the first matrix has 1 connected component and the second has 3.
If you want it in one line:
getfield(bwconncomp(A,4),'NumObjects')==1
(or use Divakar's suggestion).

Related

Matlab Equivalent of sortrows for columns

To sort a matrix according to all columns except the first, I used the following code. I do not want sortrows to consider the first column because that is meant to keep track of the row numbers.
B = [1 1 0 0 0 0 0 0 0 1
2 0 1 0 0 0 0 1 0 0
3 0 0 1 0 1 0 0 1 0
4 0 1 0 0 0 1 1 0 0
5 0 0 1 0 0 0 0 1 0
6 0 0 0 0 0 1 1 0 0
7 1 0 0 1 0 0 0 0 0
8 0 0 1 0 1 0 0 0 0];
D = -sortrows(-B,[2:size(B,2)])
What if you want to sort the matrix according to all rows except the first, so the first element of each column would be ignored when sorting them in descending order? Is there any similar function to sortrows?
To clarify, the desired output is
1 0 0 0 0 0 0 1 0 1
2 1 1 0 0 0 0 0 0 0
3 0 0 1 1 1 0 0 0 0
4 1 1 0 0 0 1 0 0 0
5 0 0 1 1 0 0 0 0 0
6 1 0 0 0 0 1 0 0 0
7 0 0 0 0 0 0 1 1 0
8 0 0 1 0 1 0 0 0 0
You can do this via
transposing the input and output
keeping column 1 separate
you can use negative sort indices to avoid what you've done making the input and output negative
A = [B(:,1) sortrows( B(:,2:end).', -(2:size(B,1)) ).'];
>> A
A =
1 0 0 0 0 0 0 1 0 1
2 1 1 0 0 0 0 0 0 0
3 0 0 1 1 1 0 0 0 0
4 1 1 0 0 0 1 0 0 0
5 0 0 1 1 0 0 0 0 0
6 1 0 0 0 0 1 0 0 0
7 0 0 0 0 0 0 1 1 0
8 0 0 1 0 1 0 0 0 0

Boolean expression minimization

Is there anyway to make this expression with another gates (especially with nand, xor, nor). I almost tried every combination but I couldn't find. Allways one output is wrong.
~A~BC + AB~C
You'll need 5 gates for this, 2 NANDs, 2 ANDs and 1 OR.
Run A and B into the first NAND, and put the output of that into the AND, along with C.
Then, into the second NAND, just put C on it's own. Then, the output of this NAND goes into the second AND, along with A and B.
The output of the 2 AND gates then goes into the OR, which will make the expression you're after.
Truth table
A B C ~A ~B ~C ~A~BC AB~C ~A~BC + AB~C
0 0 0 1 1 1 0 0 0
0 0 1 1 1 0 1 0 1
0 1 0 1 0 1 0 0 0
0 1 1 1 0 0 0 0 0
1 0 0 0 1 1 0 0 0
1 0 1 0 1 0 0 0 0
1 1 0 0 0 1 0 1 1
1 1 1 0 0 0 0 0 0
So you need 2 AND gates and 1 OR gate. Now replace AND gates with NAND gates:
A B C ~A ~B ~C NAND(~A,~B,C) NAND(A,B,~C) ?
0 0 0 1 1 1 1 1 0
0 0 1 1 1 0 0 1 1
0 1 0 1 0 1 1 1 0
0 1 1 1 0 0 1 1 0
1 0 0 0 1 1 1 1 0
1 0 1 0 1 0 1 1 0
1 1 0 0 0 1 1 0 1
1 1 1 0 0 0 1 1 0
Which gate make 1 1 -> 0 and 0 1 -> 1? XOR gate.
Simple answer: ~A~BC + AB~C = NAND(~A,~B,C) ⊕ NAND(A,B,~C)

distribute matrix values of a binary image

I need to take the tril below and distribute the values equally so it ends up like a modified checkerboard.
x=ones(1186,686);
x2=tril(x);
A sample simplified matrix of what I need to have happen is below:
1 1 1 1 1 1
1 1 1 1 1 1
0 1 1 1 1 1
0 0 1 1 1 1
0 0 0 1 1 1
0 0 0 0 1 1
0 0 0 0 0 1
0 0 0 0 0 0
0 0 0 0 0 0
The matrix above needs to be changed into:
1 1 1 1 1 1
1 1 1 1 1 1
1 0 1 1 1 1
1 0 1 0 1 1
1 0 1 0 1 0
1 0 1 0 0 0
1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
I've tried looking for built in MATLAB functions that would evenly distribute the zeros values across the board, but have not found anything that works. In terms of the output, where the ones and zeros appear is somewhat irrelevant. They just need to be distributed as evenly as possible within the matrix. For example the 3rd line of the modified matrix could = 1 1 1 0 1 1 or the like.
Would be be possible to achieve this effect a different way than starting with the tril that I'm not seeing?
For Beaker and anyone that wants to comment on how I could have better asked my original question.
This is the result of what I wanted. It's not exactly what I had described, but it achieves the same function I'm after. It's Completely different direction. I'm doing image analysis of the mixing and segregation of particles. Having contrived images like this allows me to determine if my mixing algorithm is producing the results I'm expecting. I can use the interleaving code you gave to continue making new and interesting patterns (not shown).
img=checkerboard(1,1186,686);
img_bw=im2bw(img);
img_mix=triu(img_bw,-500);
img_neg=imcomplement(img_mix);
imshow(img_neg)
I think this might be what you're after. Note that I borrowed the interleave-by-reshape trick from this blog post. (I also used triu instead of tril since it matched your example.)
x=ones(12,10);
x2=triu(x);
[rows,cols]=size(x2);
a = x2(:,1:cols/2);
b = x2(:,end:-1:(cols/2)+1);
% interlave two same sized matrices by column
a = a.';
b = b.';
col_interleave = reshape([b(:) a(:)]',2*size(a,1), []).'
Output is:
col_interleave =
1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1
1 0 1 0 1 1 1 1 1 1
1 0 1 0 1 0 1 1 1 1
1 0 1 0 1 0 1 0 1 1
1 0 1 0 1 0 1 0 1 0
1 0 1 0 1 0 1 0 0 0
1 0 1 0 1 0 0 0 0 0
1 0 1 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
0 0 0 0 0 0 0 0 0 0

Matlab how to bitwise-AND of a vector and a matrix?

I want to find out the index of the matrix column in which the vector appears. My idea is to do AND of the vector over matrix and only the column that is the same will be 1 in the new vecotr. But I don't know how to do this. Below is example:
H =
0 0 0 0 1 1 1 1 1 1 1 1 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 1 0 0
1 0 1 1 0 1 1 0 0 1 1 0 0 1 0
1 1 0 1 1 0 1 0 1 0 1 0 0 0 1
S =
0 1 0 1
From that I want to get 2 as second column or even better vector
0 1 0 0 0 0 ... 0
Since there is error in second column.
How can I do this in Matlab or even better Octave?
Not really sure how you tried to approach the problem. But with repmat or bsxfun it is as simple as this:
all(bsxfun(#eq,H,S'))
How about
result = sum(H==repmat(S(:),[1 size(H,2)]))==4;
I found out the function
ismember(H', S, "rows")
works exactly as I want. Your answers are all good too, thanks.
That's pretty easy with broadcasting. The following will require Octave 3.6.0 or later but you can use bsxfun if you have a previous version:
octave-cli-3.8.1> h = logical ([
0 0 0 0 1 1 1 1 1 1 1 1 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 1 0 0
1 0 1 1 0 1 1 0 0 1 1 0 0 1 0
1 1 0 1 1 0 1 0 1 0 1 0 0 0 1]);
octave-cli-3.8.1> s = logical ([0 1 0 1]');
octave-cli-3.8.1> all (h == s)
ans =
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
From here, it's all a matter of using find to get the column numbers. It will even work if it matches more than 1 column:
octave-cli-3.8.1> find (all (h == s))
ans = 2

Grouping logical data in Matlab

I have a matrix that contains data of 0 & 1. I want to find groups of ones (not a specific size) in that matrix. Is it possible somehow?
Thanks in advance!
If you mean that you want to find all the "connected components in the matrix, say BW, simply use:
BW = logical([1 1 1 0 0 0 0 0
1 1 1 0 1 1 0 0
1 1 1 0 1 1 0 0
1 1 1 0 0 0 1 0
1 1 1 0 0 0 1 0
1 1 1 0 0 0 1 0
1 1 1 0 0 1 1 0
1 1 1 0 0 0 0 0]);
L = bwlabel(BW,4) %Result
This would yeild:
L =
1 1 1 0 0 0 0 0
1 1 1 0 2 2 0 0
1 1 1 0 2 2 0 0
1 1 1 0 0 0 3 0
1 1 1 0 0 0 3 0
1 1 1 0 0 0 3 0
1 1 1 0 0 3 3 0
1 1 1 0 0 0 0 0
Now if you want to find the size of various groups:
for ii=1:max(L(:))
length_vector(ii)=length(find(L==ii));
end
length_vector
This gives you:
length_vector =
24 4 5