Matlab finding the center of cluster of a few pixels and counting the clusters - arrays

So I have this matrix A, which is made of 1 and zeros, I have about 10 to 14 white spots of many pixels, but I want only 1 white pixel/centers coordinate for every cluster of white, how do I calculate how many cluster there are and their centers.
Try to imagine the matrix A as the night sky with white starts in black sky and how to I count the stars and the stars centers, plus the star are made of cluster of white pixels.
also the clusters are not all exactly the same size.

Here is some code using bwlabel and/or regioprops, which are used to identify connected components in a matrix and a buch of other properties, respectively. I think it suits your problem quite well; however you might want to adapt my code a bit as its more of a starting point.
clear
clc
%// Create dummy matrix.
BW = logical ([ 1 1 1 0 1 1 1 0
1 1 1 0 1 1 1 0
1 1 1 0 1 1 1 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0
1 1 1 1 0 1 1 0
1 1 1 1 0 1 1 0
1 1 1 1 0 0 0 0]);
%// Identify clusters.
L = bwlabel(BW,4)
Matrix L looks like this:
L =
1 1 1 0 3 3 3 0
1 1 1 0 3 3 3 0
1 1 1 0 3 3 3 0
0 0 0 0 0 0 0 0
0 0 0 0 0 4 4 0
2 2 2 2 0 4 4 0
2 2 2 2 0 4 4 0
2 2 2 2 0 0 0 0
Here you have many ways to locate the center of the clusters. The first one uses the output of bwlabel to find each cluster and calculate the coordinates in a loop. It works and its didactic but it's a bit long and not so efficient. The 2nd method, as mentioned by #nkjt, uses regionprops which does exactly what you want using the 'Centroid' property. So here are the 2 methods:
Method 1: a bit complicated
So bwlabel identified 4 clusters, which makes sense. Now we need to identify the center of each of those clusters. My method could probably be simplified; but I'm a bit out of time so fell free to modify it as you see fit.
%// Get number of clusters
NumClusters = numel(unique(L)) -1;
Centers = zeros(NumClusters,2);
CenterLinIdices = zeros(NumClusters,1);
for k = 1:NumClusters
%// Find indices for elements forming each cluster.
[r, c] = find(L==k);
%// Sort the elements to know hot many rows and columns the cluster is spanning.
[~,y] = sort(r);
c = c(y);
r = r(y);
NumRow = numel(unique(r));
NumCol = numel(unique(c));
%// Calculate the approximate center of the cluster.
CenterCoord = [r(1)+floor(NumRow/2) c(1)+floor(NumCol/2)];
%// Actually this array is not used here but you might want to keep it for future reference.
Centers(k,:) = [CenterCoord(1) CenterCoord(2)];
%// Convert the subscripts indices to linear indices for easy reference.
CenterLinIdices(k) = sub2ind(size(BW),CenterCoord(1),CenterCoord(2));
end
%// Create output matrix full of 0s, except at the center of the clusters.
BW2 = false(size(BW));
BW2(CenterLinIdices) = 1
BW2 =
0 0 0 0 0 0 0 0
0 1 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 0 0 0 1 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
Method 2 Using regionprops and the 'Centroid' property.
Once you have matrix L, apply regionprops and concatenate the output to get an array containing the coordinates directly. Much simpler!
%// Create dummy matrix.
BW = logical ([ 1 1 1 0 1 1 1 0
1 1 1 0 1 1 1 0
1 1 1 0 1 1 1 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0
1 1 1 1 0 1 1 0
1 1 1 1 0 1 1 0
1 1 1 1 0 0 0 0]);
%// Identify clusters.
L = bwlabel(BW,4)
s = regionprops(L,'Centroid');
CentroidCoord = vertcat(s.Centroid)
which gives this:
CentroidCoord =
2.0000 2.0000
2.5000 7.0000
6.0000 2.0000
6.5000 6.0000
Which is much simpler and gives the same output once you use floor.
Hope that helps!

Related

How to isolate specific boolean island given a coordinate on it?

Given a 2d array with Boolean islands where 1 is land and 0 is water. Lets say I want only the island to which I point with a coordinate. How would I transfer it to a new array where everything beyond the borders of that island is water.
Here is a simple example.
I am given this 2d array
1 0 0 1 1 0
0 1 0 0 0 1
1 1 1 0 0 0
0 1 0 1 0 1
1 1 1 1 1 0
and the coordinate [1][2] (that would be the 2nd column 3rd row)
Then the final result in the new array should be something like
0 0 0 0 0 0
0 1 0 0 0 0
1 1 1 0 0 0
0 1 0 1 0 0
1 1 1 1 1 0
The pixels can only be connected either up, down, left or right to each other (no diagonals)

The fastest way to set up sparse matrix in matlab

I am working with iterative methods, and thus with large sparse matrices.
For instance, I want to set up a matrix like this:
1 1 0 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 0 0
0 1 1 1 0 0 1 0 0 0
0 0 1 1 1 0 0 1 0 0
1 0 0 1 1 1 0 0 1 0
0 1 0 0 1 1 1 0 0 1
So that only certain diagonals are non-zero. In my programming, I will be working with much larger matrix sizes, but Idea is the same: Only a few diagonals are non-zero, all other entries are zeros.
I know, how to do it in for loop, but it seems to be not effective, if the matrix size is large. Also I work with symmetric matrices.
I would appreciate, if you provide me a code for my sample matrix along with description.
You want spdiags:
m = 6; %// number of rows
n = 10; %// number of columns
diags = [-4 -1 0 1 4]; %// diagonals to be filled
A = spdiags(ones(min(m,n), numel(diags)), diags, m, n);
This gives:
>> full(A)
ans =
1 1 0 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 0 0
0 1 1 1 0 0 1 0 0 0
0 0 1 1 1 0 0 1 0 0
1 0 0 1 1 1 0 0 1 0
0 1 0 0 1 1 1 0 0 1

How does this Matlab/Octave code create a Boolean matrix from a vector?

The first line of code creates some vector with "discrete labels", and the second line of code creates a sparse matrix with ones at the index that the label represents. "eye" creates an identity matrix, but then even if the vector "a" is much longer, this effect of creating a sparse matrix still works!?
Could you please help me understand what is going on?
octave:4> a = [1 3 5 7 9 2 4 6 8 10]
a =
1 3 5 7 9 2 4 6 8 10
octave:5> eye(10)(a,:)
ans =
Permutation Matrix
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 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0
0 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 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 1
The notation eye(10)(a,:) in Octave means: build the size-10 identity matrix (eye(10)) and then pick its rows in the order given by a (note that a is used as the first index, which corresponds to rows, and : as second index, which means "take all columns"). So, for example, the 4th row of the result is row 7 of the identity matrix, because the 4th entry of a contains 7.
From this explanation it's clear that a can be as long as you want, provided that all its values are integers in the range 1...10 (these are the rows available in eye(10)).
Note that in Matlab this "chained" indexing is not allowed. You would have to first assign eye(10) to a variable, and then index into that variable:
m = eye(10);
m(a,:)
Lastly, a minor "technical" note: the obtained matrix is not of type logical (Matlab's Boolean data type), nor is it sparse. Rather, it's a full matrix of type double.

rotate vector of arbitrary length circularly about an array about some point x,y in matlab

I have an array:
1 1 1 0 0
1 2 2 0 0
1 2 3 0 0
0 0 0 0 0
0 0 0 0 0
I want to make it
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1
It is like rotating 1/4 piece of pie 270 degrees to fill out the remaining parts of the pie to make a full circle. Essentially mirroring the entire corner in all directions. I don't want to use any in built matlab features if possible - just some vector tricks if possible. Thanks.
EDIT:
This is embedded within an matrix of zeros of arbitrary size. I want it to work in both the above example and say this example:
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0 0 0 0 0
0 0 1 2 2 0 0 0 0 0 0 0 0 0
0 0 1 2 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 0 0 0 0 0 0 0 0 0 0 0 0
Ideally, I want to have a vector say [1,2,3.. N] which can be rotated circularly about the highest value in the array (N) centered about some point xc,yc in the grid. Or if this isn't possible, take an base array [1 1 1, 1 2 2, 1 2 3] and rotate it such that 3 is in the centre and you fill a circle as in the 2nd matrix above.
EDIT:
I found rot90(M,k) rotates matrix M k times but this produces:
Mrot = M + rot90(M,1) + rot90(M,2) + rot90(M,3)
Mrot =
1 1 2 1 1
1 2 4 2 1
2 4 12 4 2
1 2 4 2 1
1 1 2 1 1
This stacks it in the x,y directions which isn't correct.
Assuming the corner you want to replicate is symmetric about the diagonal (as in your example), then you can do this in one indexing step. Given a matrix M containing your sample 5-by-5 matrix, here's how to do it:
>> index = [1 2 3 2 1];
>> M = M(index, index)
M =
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1

Gaussian elimation - Linear equation matrices, algorithm

Let's assume that we have a simple matrix 3rows x 7cols.
The matrix includes only zeros (0) and (1) like:
1 0 1 1 1 0 0
0 0 1 1 0 0 0
0 0 1 0 1 1 0
Senario:
If we know the sum of non-zeros in each row,
(in first row is 4, in second row is 2, in third row is 3.) (blue line)
additional, if we know the sum of each col (1 , 0, 3, 2, 2, 1, 0) (green line)
also if we know the sum of each diagonal from the top-left to bottom-right (1,0,1,2,3,0,1,1,0)(red lines) anti-clockwise
and finally we know the sum of each diagonal from the bottom-left to top-right (0,0,2,1,3,2,1,0,0) (yellow lines)
My question is:
With these values as input (and the lenght of matrix 3x7),
4, 2, 3
1, 0, 3, 2, 2, 1, 0
1, 0, 1, 2, 3, 0, 1, 1, 0
0, 0, 2, 1, 3, 2, 1, 0, 0
How we can draw the first matrix?
After a lot of thoughts I came to the conclusion that this is a linear equation system with 3x7 unknown values and some equations.
Right?
How can I make an algorithm in C, or whatever, to solve these equations?
Should I use a method like gausian equation?
Any help would be greatly appreciated!
Start with the first column. You know the top and bottom values (from the first values of the red & yellow lists). Subtract the sum of these two from the first in the green list, and now you have the middle value as well.
Now just work to the right.
Subtract the first column's middle value from the next value in the red list, and you have the second column's top value. Subtract that same middle value from the next value in the yellow list, and you have the second column's bottom value. Subtract the sum of these two from the next value in the green list, and now you have the middle value for the second column.
et cetera
If you're going to code this up, you can see that the first two columns are a special case, and that'll make the code ugly. I'd suggest using two "ghost" columns of all zeros to the left so that you can use a single method for determining the top, bottom, and middle values for each column.
This is also easily generalizable. You'll just have to use (#rows)-1 ghost columns.
Enjoy.
You can use singular value decomposition to compute a non zero least squares solution to a system of linear homogeneous (and non homogeneous) equations in matrix form.
For a quick overview see:
http://campar.in.tum.de/twiki/pub/Chair/TeachingWs05ComputerVision/3DCV_svd_000.pdf
You should first write out your systems as a matrix equation in the form Ax = b, where x is the 21 unknowns as a column vector, and A is the 28 x 21 matrix that forms the linear system when multiplied out. You essentially need to a compute the matrix A of linear equations, compute the singular value decomposition of A and plug the results into the equation as shown in equation 9.17
There are plenty of libraries that will compute the SVD for you in C, so you only need to formulate the matrix and perform the computations in 9.17. The most difficult part is probably understanding how it all works, with a library SVD function there is relatively little code needed.
To get you started on how to form the equation of linear systems, consider a simple 3 x 3 case.
Suppose that our system is a matrix of the form
1 0 1
0 1 0
1 0 1
We would have the following inputs to the linear system:
2 1 2 (sum of rows - row)
2 1 2 (sum of colums - col)
1 0 3 0 1 (sum of first diagonal sets - t2b)
1 0 3 0 1 (sum of second diagonal sets - b2t)
so now we create a matrix for the linear system
A a1 a2 a3 b1 b2 b3 c1 c2 c3 unknowns (x) = result (b)
sum of row 1 [ 1 1 1 0 0 0 0 0 0 ] [a1] [2]
sum of row 2 [ 0 0 0 1 1 1 0 0 0 ] [a2] [1]
sum of row 3 [ 0 0 0 0 0 0 1 1 1 ] [a3] [2]
sum of col 1 [ 1 0 0 1 0 0 1 0 0 ] [b1] [2]
sum of col 2 [ 0 1 0 0 1 0 0 1 0 ] [b2] [1]
sum of col 3 [ 0 0 1 0 0 1 0 0 1 ] [b3] [2]
sum of t2b 1 [ 1 0 0 0 0 0 0 0 0 ] [c1] [1]
sum of t2b 2 [ 0 1 0 1 0 0 0 0 0 ] [c2] [0]
sum or t2b 3 [ 0 0 1 0 1 0 1 0 0 ] [c3] [3]
sum of t2b 4 [ 0 0 0 0 0 1 0 1 0 ] [0]
sum of t2b 5 [ 0 0 0 0 0 0 0 0 1 ] [1]
sum of b2t 1 [ 0 0 0 0 0 0 1 0 0 ] [1]
sum of b2t 2 [ 0 0 0 1 0 0 0 1 0 ] [0]
sum of b2t 3 [ 1 0 0 0 1 0 0 0 1 ] [3]
sum of b2t 4 [ 0 1 0 0 0 1 0 0 0 ] [0]
sum of b2t 5 [ 0 0 1 0 0 0 0 0 0 ] [1]
When you multiply out Ax, you see that you get the linear system of equations. For example if you multiply out the first row by the unkown column, you get
a1 + a2 + a3 = 2
All you have to do is put a 1 in any of the colums that appear in the equation and 0 elsewhere.
Now all you have to do is compute the SVD of A and plug the result into equation 9.17 to compute the unknowns.
I recommend SVD because it can be computed efficiently. If you would prefer, you can augment the matrix A with the result vector b (A|b) and put A in reduced row echelon form to obtain the result.
For an array of 10x15 ones and zeros, you would be trying to find 150 unknowns and have 10+15+2*(10+15-1) = 73 equations if you ignore that the values are limited to being either one or zero. Obviously you can't create a linear system on that basis which has a unique solution.
So is that constraint enough to give a unique solution?
For a 4x4 matrix with the following sums there are two solutions:
- 1 1 1 1
| 1 1 1 1
\ 0 1 1 0 1 1 0
/ 0 1 1 0 1 1 0
0 0 1 0
1 0 0 0
0 0 0 1
0 1 0 0
0 1 0 0
0 0 0 1
1 0 0 0
0 0 1 0
So I wouldn't expect there to be a unique solution for larger matrices - the same symmetry would exist in many places:
- 1 1 0 0 1 1
| 1 1 0 0 1 1
\ 0 1 0 0 1 0 1 0 0 1 0
/ 0 1 0 0 1 0 1 0 0 1 0
0 0 0 0 1 0
1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
0 1 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 0 0 0
1 0 0 0 0 0
0 0 0 0 1 0
How about this as another variation
Count the amount of unknown squares each sum passes through
While there are unsolved cells
Solve all the cells which are passed through by a sum with only one unknown square
Cells are solved by simply subtracting off all the known cells from the sum
Update the amount of unknown squares each sum passes through
No boundary cases but very similar to the previous answer. This would first solve all the corners, then those adjacent to the corners, then those one step more interior from that, and so on...
Edit: Also zero out any paths that have a sum of zero, that should solve any that are solvable (I think)

Resources