Creating a labelmatrix from a non-binary matrix for regionprops - matlab

I have an RGB image that I've imported into MATLAB using imread(), and I have code that has converted each cells value from RGB values into a single value (e.g. going from [1;2;1] to [34]). I'm using this to record unique labels for each cell, which correspond to labels of object's I've segmented previously. A small section of the matrix would like this:
0 0 0 52 52 52 0 0 0
0 0 52 52 31 31 31 0 0
0 52 52 0 0 31 31 31 31
0 0 0 0 0 31 31 0 0
I'm currently trying to run regionprops on the matrix with single values, thinking it would automatically interpret the matrix as a labelmatrix. This doesn't seem to be the case though as the 'label' property is not present in the output. I have areas in my matrix where objects are touching each other, and thus converting the single matrix to binary and running regionprops on that will lead to unwanted merging of objects.
Is there a way to get regionprops to recongize my matrix as a labelmatrix as-is? Or at least convert my matrix into a labelmatrix?

Related

Creating gray-level co-occurrence matrix from 16-bit image

I have a data set of images that are 16-bit and I want to create GLCM matrix from them to extract GLCM features.
However, the resulting matrix shows one value (as shown in the picture below), I wonder why.
I tried using the same image but converted to 8-bit, the resulted GLCM show several values.
Note: I used the following Matlab function:
glcm_matrix = graycomatrix(image.tif);
Here is a cropped sample from the 16-bit image:
Note: The image used in the computations can be downloaded from here. The original image is very low contrast and looks totally dark. The image shown above has its contrast stretched and is intended only for visualization purposes.
EDIT:
I used
glcm_matrix = graycomatrix(image.tif, 'GrayLimits', []);
and it gives me the following results:
It was a binning/scaling problem.
Let's take a peek inside:
edit graycomatrix
In this case we're interested in the two options, 'NumLevels' and 'GrayLimits'
% 'NumLevels' An integer specifying the number of gray levels to use
% when scaling the grayscale values in I. For example,
% if 'NumLevels' is 8, GRAYCOMATRIX scales the values in
% I so they are integers between 1 and 8. The number of
% gray levels determines the size of the gray-level
% co-occurrence matrix (GLCM).
%
% 'NumLevels' must be an integer. 'NumLevels' must be 2
% if I is logical.
%
% Default: 8 for numeric
% 2 for logical
%
% 'GrayLimits' A two-element vector, [LOW HIGH], that specifies how
% the values in I are scaled into gray levels. If N is
% the number of gray levels (see parameter 'NumLevels')
% to use for scaling, the range [LOW HIGH] is divided
% into N equal width bins and values in a bin get mapped
% to a single gray level. Grayscale values less than or
% equal to LOW are scaled to 1. Grayscale values greater
% than or equal to HIGH are scaled to NumLevels. If
% 'GrayLimits' is set to [], GRAYCOMATRIX uses the
% minimum and maximum grayscale values in I as limits,
% [min(I(:)) max(I(:))].
So in other words the function was binning your data into 8x8 bins and assuming that the scaling range was the full uint16 range (0-65535). However that sample image I you gave has a minimum of 305 and a maximum of 769, making it fall into the first bin (0-8192 or so). When I call A = graycomatrix(I) it gives me the following matrix :
A =
6600 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 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
However when A = graycomatrix(I,'GrayLimits', []) is called the scaling range is taken as min(I) - max(I), and the function works as expected :
A =
4 2 1 0 0 0 0 0
1 1 2 2 0 0 0 0
2 2 4 7 1 0 0 0
0 1 7 142 72 1 0 0
0 0 0 65 1711 252 0 0
0 0 0 0 230 3055 178 0
0 0 0 0 0 178 654 8
0 0 0 0 0 0 8 9
In your original example the single value is in the middle of the 8x8 matrix most likely because your original images are int16 and not uint16, so the graycomatrix is symmetric to take into account the possibility of negative values.
You can also of course scale the original images to fit their datatypes. For example percentile scaling might be a good idea if you expect outliers etc.
I'd just like to build on #Tapio's excellent answer.
The GLCM yielded by graycomatrix when you use the name/value pair GrayLimits', [] in the function call looks good. However, this approach might not be valid for your application. If you compute the GLCMs for a set of images in this way, the same elements of two different GLCMs corresponding to two different images are likely to have a different meaning. Indeed, as the intensity is being rescaled differently for each image, the components of the GLCM are actually encoding different co-occurrences from one image to another.
To avoid this you could first calculate the minimum and maximum intensities over the whole image dataset (for example minImgs and maxImgs) and then use those values to rescale the intensity of all the images that make up the dataset in the exact same way:
glcm_matrix = graycomatrix(image_tif, 'GrayLimits', [minImgs maxImgs]);

Create adjacency matrix from nearest neighbour search. (convert adjacency list to adjacency matrix) - Matlab

I have a matrix 2000x5, in the first column the point number, and in columns 2-5 the 4 neighbours (0s if there isnt a neighbour). Is there an efficient way to create an adjacency matrix out of this ?
1 129 0 65 0
2 130 0 66 85
3 131 169 67 0
4 132 170 68 87
5 133 0 69 81
6 134 0 70 82
7 135 173 71 83
8 136 174 72 84
9 137 161 73 0
10 138 162 74 93
11 139 163 75 0
12 140 164 76 95
13 141 165 77 89
14 142 166 78 90
15 143 167 79 91
16 144 168 80 92
17 145 0 81 65
18 146 0 82 66
....
I found the following thread, where it is explained for just one neighbour, but I am not sure how to use it for multiple neighbours.
matlab adjacency list to adjacency matrix
I would very much appreciate any help.
A quick and simple technique:
adjMat = zeros(size(A,1));
for ind = 1:size(A,1)
% Flag 1 on each row 'ind' at the indices mentioned in col 2-5
adjMat(ind, nonzeros(A(ind,2:end))) = 1;
end
Since you have mentioned using the nearest neighbour search, it is likely that the adjacency list should be completely filled to result in a undirected graph, in the sense that if row 1 has 20 as a neighbour, row 20 very likely has 1 as a neighbour.
However technically speaking, this will produce an adjacency matrix exactly equivalent to the adjacency list, assuming nothing by itself.
Example:
For an adjacency list
A = [1 2 3; 2 0 1; 3 1 4; 4 5 3; 5 4 0]
A =
1 2 3
2 0 1
3 1 4
4 5 3
5 4 0
The result is:
adjMat =
0 1 1 0 0
1 0 0 0 0
1 0 0 1 0
0 0 1 0 1
0 0 0 1 0
P.S. To force undirected-ness, you can simply add another statement in the for loop body:
adjMat(nonzeros(A(ind,2:end)),ind) = 1;
This will ensure that the adjacency matrix will be symmetric, which is a characteristic of undirected graphs.
Firstly, I'm going to assume that the adjacency list is undirected. In any case, it's not that far of a stretch to go to multiple neighbours. What you need to do first is detect the total number of non-zero elements per row from columns 2 to 5. Once you do this, for the rows of the adjacency matrix, you would copy the point number for as many times as there are non-zero elements per that row. The function repelem is perfectly suitable to do that for you. The column indices would simply be the second to fifth columns removing all of the zero elements. How you can do this is first transpose the matrix resulting in indexing the second to fifth columns, then using a logical indexing matrix to remove out the zero entries. Doing this will unroll your vector in a column-major fashion, which is why transposing is required before doing this operation. Once you do this, you can create row and column access indices so that these can be input into sparse much like that post you linked.
Supposing that your matrix was stored in A, you would do something like this. This also assumes that each of the weights connecting the nodes are 1:
% Find total number of non-zero elements per row, skipping first column
non_zero = sum(A(:,2:end) ~= 0, 2);
% Create row indices
rows = repelem(A(:,1), non_zero);
% Create column indices
cols = A(:,2:end).';
cols = cols(cols ~= 0);
% Create adjacency matrix
adj = sparse([rows; cols],[cols; rows], 1);
The above representation is in sparse. If you want the full numeric version, cast the output using full:
adj = full(adj);
If your graph is directed
If you have a directed graph instead of an undirected graph, the above call to sparse duplicates edges so that you are creating links to and from each of the neighbours. If your graph is actually directed, then you simply have to only use the row and column indices once instead of twice as seen in the above code:
% Create adjacency matrix
adj = sparse(rows, cols , 1);
Test Case
Here's a small test case to show you that this works. Supposing my adjacency list looked like the following:
>> A = [1 0 2 3; 2 4 0 0; 3 0 0 4]
A =
1 0 2 3
2 4 0 0
3 0 0 4
The adjacency matrix is now:
>> full(adj)
ans =
0 1 1 0
1 0 0 1
1 0 0 1
0 1 1 0
Taking a look at the list above and how the matrix is populated, we can verify that this is correct.
Note about repelem
repelem assumes you have MATLAB R2015a or later. If you don't have this, you can consult this answer by user Divakar on a custom implementation of repelem here: Repeat copies of array elements: Run-length decoding in MATLAB

Copying values from one vector to another vector

I have a vector which is 5000 x 1 & contain doubles, called NewVector. I have another two vectors, one of which is also a 5000 x 1 called OldVector. I then have a vector called CompanyIndex which is a double type as well which contains all the row numbers of OldVector where I would like the data to be copied over to the NewVector. This vector (CompnayIndex) sizes will change every time the code updates.
An example of what I'm looking to do.
Old Vector New Vector CompanyIndex Result I'm looking for - New Vector
3 0 2 0
6 0 3 6
12 0 5 12
9 0 0
36 0 36

Comparing two matrix and took the value if match the criteria

I have some question. I have 2 matrix, it's have same size.
For example, first matrix :
1
1
0
0
1
0
Second matrix
34
56
12
12
33
14
Then, I want to compare this two matrix and groups it by the criteria on first matrix
so I will have this two groups matrix :
Matrix when the first matrix is have value 1
34
56
33
and
Matrix when the first matrix is have value 0
12
12
14
You could try this:
a = [1 1 0 0 1 0]';
b = [34 56 12 12 33 14]';
b(a==1)
b(a==0)

Matlab, Image compression

i am unsure about what this is asking me to do in matlab? what does it mean to encode? what format should the answer be? can anyone help me to work it out please?
Encode the 8x8 image patch and print out the results
I have got an 8X8 image
symbols=[0 20 50 99];
p=[32 8 16 8];
p = p/sum(p);
[dict, avglen] = huffmandict(symbols, p);
A = ...
[99 99 99 99 99 99 99 99 ...
20 20 20 20 20 20 20 20 ...
0 0 0 0 0 0 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 0 0 0 0 0 0];
comp=huffmanenco(A,dict);
ratio=(8*8*8)/length(comp)
Do you understand the principle of Huffman coding?
To put it simply, it is an algorithm used to compress data (like images in your case). This means that the input of the algorithm is an image and the output is a numeric code that is smaller in size than the input: hence the compression.
The principle of Huffman coding is (roughly) to replace symbols in the original data (in your case the value of each pixel of the image) by a numeric code that is attributed according to the probability of the symbol. The most probable (i.e. the most common) symbol will be replaced by shorter codes in order to realize a compression of the data.
To solve your problem, Matlab has two functions in the Communications Toolbox: huffmandict and huffmanenco.
huffmandict: this function build a dictionary that is used to translate symbols from the original data to their numeric Huffman codewords. To build this dictionary, huffmandict needs the list of symbols used in the data and their probability of appearance which is the number of time they are used divided by the total number of symbols in your data.
huffmanenco: this function is used to translate your original data by using the dictionary built by huffmandict. Each symbol in the original data is translated to a numeric Huffman code. To measure the gain in size of this compression method, you can compute the compression ration, which is the ratio between the number of bits used to describe your original data and the number of bits of the Huffman corresponding code. In your case, infering from your computation of the compression ratio, you have an 8 by 8 image using 8 bits integer to describe each pixel, and the Huffman corresponding code uses length(comp) bits.
With all this in mind, you could read your code in this way:
% Original image
A = ...
[99 99 99 99 99 99 99 99 ...
20 20 20 20 20 20 20 20 ...
0 0 0 0 0 0 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 50 50 50 50 0 0 ...
0 0 0 0 0 0 0 0];
% First step: extract the symbols used in the original image
% and their probability (number of occurences / number of total symbols)
symbols=[0 20 50 99];
p=[32 8 16 8];
p=p/sum(p);
% To do this you could also use the following which automatically extracts
% the symbols and their probability
[symbols,p]=hist(A,unique(A));
p=p/sum(p);
% Second step: build the Huffman dictionary
[dict,avglen]=huffmandict(symbols,p);
% Third step: encode your original image with the dictionary you just built
comp=huffmanenco(A,dict);
% Finally you can compute the compression ratio
ratio=(8*8*8)/length(comp)