How can I draw a triangle in an image in MATLAB? - image

I need to draw a triangle in an image I have loaded. The triangle should look like this:
1 0 0 0 0 0
1 1 0 0 0 0
1 1 1 0 0 0
1 1 1 1 0 0
1 1 1 1 1 0
1 1 1 1 1 1
But the main problem I have is that I do not know how I can create a matrix like that. I want to multiply this matrix with an image, and the image matrix consists of 3 parameters (W, H, RGB).

You can create a matrix like the one in your question by using the TRIL and ONES functions:
>> A = tril(ones(6))
A =
1 0 0 0 0 0
1 1 0 0 0 0
1 1 1 0 0 0
1 1 1 1 0 0
1 1 1 1 1 0
1 1 1 1 1 1
EDIT: Based on your comment below, it sounds like you have a 3-D RGB image matrix B and that you want to multiply each color plane of B by the matrix A. This will have the net result of setting the upper triangular part of the image (corresponding to all the zeroes in A) to black. Assuming B is a 6-by-6-by-3 matrix (i.e. the rows and columns of B match those of A), here is one solution that uses indexing (and the function REPMAT) instead of multiplication:
>> B = randi([0 255],[6 6 3],'uint8'); % A random uint8 matrix as an example
>> B(repmat(~A,[1 1 3])) = 0; % Set upper triangular part to 0
>> B(:,:,1) % Take a peek at the first plane
ans =
8 0 0 0 0 0
143 251 0 0 0 0
225 40 123 0 0 0
171 219 30 74 0 0
48 165 150 157 149 0
94 96 57 67 27 5
The call to REPMAT replicates a negated version of A 3 times so that it has the same dimensions as B. The result is used as a logical index into B, setting the non-zero indices to 0. By using indexing instead of multiplication, you can avoid having to worry about converting A and B to the same data type (which would be required to do the multiplication in this case since A is of type double and B is of type uint8).

Related

Finding biggest square sub matrix has values 1 in a Matrix which has values 1 and 0

i have axb matrix has values 1 or 0, I need to find the largest square sub matrix includes only ones. And i need to understdand how to do it. i mean i neeed algorthim. Example:
Matrix is 5x5 [ 1 1 1 1 1
1 1 1 0 0
1 1 1 0 0
1 0 1 1 1
1 1 1 1 1 ] largest is 3x3 , starting position 0,0 and return value 3
another example:
Matrix is 5x5 [ 0 1 1 1 1
0 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 0 1 0 1 ]
largest is 4x4 , starting position 0,1 and return value 4
Since program will be done multiple programing languages i need an algorithm. But you can basicly write a code for "C" to explain...
I do not know if this is the optimal solution but it is a simple idea.
Take you 5x5 matrix and create from it a 4x4 matrix in the following way:
Each 2x2 matrix it turning to a 1x1 matrix which is 1 if all of the original numbers where 1 and else - 0.
Matrix is 5x5 [ 1 1 1 1 1
1 1 1 0 0
1 1 1 0 0
1 0 1 1 1
1 1 1 1 1 ]
Will turn to
Matrix is 4x4 [ 1 1 0 0
1 1 0 0
0 0 0 0
0 0 1 1 ]
Now we repeat the process:
Matrix is 3x3 [ 1 0 0
0 0 0
0 0 0 ]
And again:
Matrix is 2x2 [ 0 0
0 0 ]
Now this is all zeros, we can search for the smallest matrix that still contains 1's. This can tell us where the original 1's matrix was and the size of the matrix relatively to the size of the original matrix can tell us how large it was. In our case it's top left in 3x3 so originally it was a 3x3 matrix at the top left.
The action we are performing is actually a convolution with 2x2 matrix of 1's and than rounding down. A Lot of programing languages have a library with this functionality.
The time complexity for a single convolution is O(n^2), but we are performing this n times so the time complexity is O(n^3).
Another example:
Matrix is 5x5 [ 0 1 1 1 1
0 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 0 1 0 1 ]
Matrix is 4x4 [ 0 1 1 1
0 1 1 1
1 1 1 1
0 0 0 0 ]
Matrix is 3x3 [ 0 1 1
0 1 1
0 0 0 ]
Matrix is 2x2 [ 0 1
0 0 ]
Matrix is 1x1 [ 0 ]
So the top right in the 2x2 is the last left which mean the original was top right 4x4.

How to adjust the size of the checkerboard pattern with imshowpair on MATLAB?

I wrote the following code:
imageResult = imshowpair(brain1, brain2,'checkerboard');
But this does not control the checkerboard size.
How can I specify what should the checkerboard square size be?
The imshowpair doc is not clear on that.
If you know a different way , please feel free to suggest it as well!
I don't think that there is an option to do that automatically.
But you can create a checkerboard index manually using the kronecker tensor product.
ind = kron(eye(2,2),ones(5,5))
produce a 2x2 checkerboard with a grid size of 5:
1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
You can now duplicate this pattern N times.
For example we duplicate this pattern 10 times.
ind = kron(ones(10,10),ind)
If your images are 3D images, you can still replicate this matrix 3 times:
ind = repmat(ind,1,1,3);
So you obtain a 2X5X10 x 2X5X10 (500x500) checkerboard matrice
Now you can combine your two images, that need also need to be 500x500:
IMG1 = IMG1(logical(ind)) = 0 % an index need to be of type logical.
IMG2 = IMG1(logical(~ind)) = 0
IMG = IMG1+IMG2
If it's impossible to get a checkerboard matrice of the right size because your images have an odd number of columns or lines your can always take a sample of the original matrice
subind = ind(1:size(IMG1,1),1:size(IMG1,2))
Same thing for 3D index:
subind = ind(1:size(IMG1,1),1:size(IMG1,2),:)
You can use the checkerboard function to generate a checkerboard in the appropriate size. e.g.
I = checkerboard(5);
will make a square checkerboard where each square is 5*5. You can further adjust the input to also make it rectangular, e.g. if you want a 5x8 checkerboard instead of an 8x8 checkerboard
I = checkerboard(5,5,8);
Note: if you want a binary checkerboard just adjust the command with
I = checkerboard(5)>0.5;

How to calculate the max number of evenly spaced points on a grid

I need to create a grid that has x columns, y rows, where each cell in the grid can have a point in it, and each point is at least z horizontal/vertical spaces away from all other points.
1) Is there a simple method to calculate the maximum number of points I can place given the grid size and a spacing of z?
Here's an example 5x5 with z = 2. In this case the max number of points is 13.
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
and here's an example 5x5 where z = 3. In this case the max number of points is 6.
1 0 0 1 0
0 0 0 0 0
0 1 0 0 1
0 0 0 0 0
1 0 0 1 0
I'd like to be able, given x, y, and z, the number of points possible to plot.
2) What's the most efficient way of populating the grid in this manner?

Convert binary values to a decimal matrix

Suppose that I have a matrix a= [1 3; 4 2], I convert this matrix to binary format using this code:
a=magic(2)
y=dec2bin(a,8)
e=str2num(y(:))';
The result is :
y =
00000001
00000100
00000011
00000010
e =
Columns 1 through 17
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 18 through 32
0 0 0 0 1 0 0 0 0 1 1 1 0 1 0
Now when I want to get back my original matrix I inverse the functions :
s=num2str(e(:))';
r=bin2dec(s)
The results I got is:
r =
1082
What can I do to get the orignal matrix? not a number
Thank you in advance
You are doing extra processes which destroyed the original structure:
a=magic(2)
y=dec2bin(a,8)
r=bin2dec(y)
Here r is your answer since y has removed the matrix structure of a. To recreate your matrix, you need to:
originalmatrix = reshape(r,size(a))
originalmatrix =
1 3
4 2
I finally got the right solution for my problem and I want to share it in case anyone need it :
a_back=reshape(bin2dec(num2str(reshape(e, 4, []))), 2, 2)
a =
1 3
4 2

Sorting rows and columns of adjacency matrix to reveal cliques

I'm looking for a reordering technique to group connected components of an adjacency matrix together.
For example, I've made an illustration with two groups, blue and green. Initially the '1's entries are distributed across the rows and columns of the matrix. By reordering the rows and columns, all '1''s can be located in two contiguous sections of the matrix, revealing the blue and green components more clearly.
I can't remember what this reordering technique is called. I've searched for many combinations of adjacency matrix, clique, sorting, and reordering.
The closest hits I've found are
symrcm moves the elements closer to the diagonal, but does not make groups.
Is there a way to reorder the rows and columns of matrix to create a dense corner, in R? which focuses on removing completely empty rows and columns
Please either provide the common name for this technique so that I can google more effectively, or point me in the direction of a Matlab function.
I don't know whether there is a better alternative which should give you direct results, but here is one approach which may serve your purpose.
Your input:
>> A
A =
0 1 1 0 1
1 0 0 1 0
0 1 1 0 1
1 0 0 1 0
0 1 1 0 1
Method 1
Taking first row and first column as Column-Mask(maskCol) and
Row-Mask(maskRow) respectively.
Get the mask of which values contains ones in both first row, and first column
maskRow = A(:,1)==1;
maskCol = A(1,:)~=1;
Rearrange the Rows (according to the Row-mask)
out = [A(maskRow,:);A(~maskRow,:)];
Gives something like this:
out =
1 0 0 1 0
1 0 0 1 0
0 1 1 0 1
0 1 1 0 1
0 1 1 0 1
Rearrange columns (according to the column-mask)
out = [out(:,maskCol),out(:,~maskCol)]
Gives the desired results:
out =
1 1 0 0 0
1 1 0 0 0
0 0 1 1 1
0 0 1 1 1
0 0 1 1 1
Just a check whether the indices are where they are supposed to be or if you want the corresponding re-arranged indices ;)
Before Re-arranging:
idx = reshape(1:25,5,[])
idx =
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
After re-arranging (same process we did before)
outidx = [idx(maskRow,:);idx(~maskRow,:)];
outidx = [outidx(:,maskCol),outidx(:,~maskCol)]
Output:
outidx =
2 17 7 12 22
4 19 9 14 24
1 16 6 11 21
3 18 8 13 23
5 20 10 15 25
Method 2
For Generic case, if you don't know the matrix beforehand, here is the procedure to find the maskRow and maskCol
Logic used:
Take first row. Consider it as column mask (maskCol).
For 2nd row to last row, the following process are repeated.
Compare the current row with maskCol.
If any one value matches with the maskCol, then find the element
wise logical OR and update it as new maskCol
Repeat this process till the last row.
Same process for finding maskRow while the column are used for
iterations instead.
Code:
%// If you have a square matrix, you can combine both these loops into a single loop.
maskCol = A(1,:);
for ii = 2:size(A,1)
if sum(A(ii,:) & maskCol)>0
maskCol = maskCol | A(ii,:);
end
end
maskCol = ~maskCol;
maskRow = A(:,1);
for ii = 2:size(A,2)
if sum(A(:,ii) & maskRow)>0
maskRow = maskRow | A(:,ii);
end
end
Here is an example to try that:
%// Here I removed some 'ones' from first, last rows and columns.
%// Compare it with the original example.
A = [0 0 1 0 1
0 0 0 1 0
0 1 1 0 0
1 0 0 1 0
0 1 0 0 1];
Then, repeat the procedure you followed before:
out = [A(maskRow,:);A(~maskRow,:)]; %// same code used
out = [out(:,maskCol),out(:,~maskCol)]; %// same code used
Here is the result:
>> out
out =
0 1 0 0 0
1 1 0 0 0
0 0 0 1 1
0 0 1 1 0
0 0 1 0 1
Note: This approach may work for most of the cases but still may fail for some rare cases.
Here, is an example:
%// this works well.
A = [0 0 1 0 1 0
1 0 0 1 0 0
0 1 0 0 0 1
1 0 0 1 0 0
0 0 1 0 1 0
0 1 0 0 1 1];
%// This may not
%// Second col, last row changed to zero from one
A = [0 0 1 0 1 0
1 0 0 1 0 0
0 1 0 0 0 1
1 0 0 1 0 0
0 0 1 0 1 0
0 0 0 0 1 1];
Why does it fail?
As we loop through each row (to find the column mask), for eg, when we move to 3rd row, none of the cols match the first row (current maskCol). So the only information carried by 3rd row (2nd element) is lost.
This may be the rare case because some other row might still contain the same information. See the first example. There also none of the elements of third row matches with 1st row but since the last row has the same information (1 at the 2nd element), it gave correct results. Only in rare cases, similar to this might happen. Still it is good to know this disadvantage.
Method 3
This one is Brute-force Alternative. Could be applied if you think the previous case might fail. Here, we use while loop to run the previous code (finding row and col mask) number of times with updated maskCol, so that it finds the correct mask.
Procedure:
maskCol = A(1,:);
count = 1;
while(count<3)
for ii = 2:size(A,1)
if sum(A(ii,:) & maskCol)>0
maskCol = maskCol | A(ii,:);
end
end
count = count+1;
end
Previous example is taken (where the previous method fails) and is run with and without while-loop
Without Brute force:
>> out
out =
1 0 1 0 0 0
1 0 1 0 0 0
0 0 0 1 1 0
0 1 0 0 0 1
0 0 0 1 1 0
0 0 0 0 1 1
With Brute-Forcing while loop:
>> out
out =
1 1 0 0 0 0
1 1 0 0 0 0
0 0 0 1 1 0
0 0 1 0 0 1
0 0 0 1 1 0
0 0 0 0 1 1
The number of iterations required to get the correct results may vary. But it is safe to have a good number.
Good Luck!

Resources