LINES(M) unique colors Matlab - matlab

I'm using the LINES(M) Matlab function which returns an M-by-3 matrix containing a colormap. The problem is that sometimes it return the same colour twice. As an example I used LINES(8) in the results as shown below the first and last row are the same, so I'm asking how can the returned matrix has unique set of colours, if anyone could advise?
0 0 1
0 0.500000000000000 0
1 0 0
0 0.750000000000000 0.750000000000000
0.750000000000000 0 0.750000000000000
0.750000000000000 0.750000000000000 0
0.250000000000000 0.250000000000000 0.250000000000000
0 0 1

The lines colormap has a maximum of 7 unique colors after which they start to repeat.
>> lines(8)
ans =
0 0 1
0 0.5 0
1 0 0
0 0.75 0.75
0.75 0 0.75
0.75 0.75 0
0.25 0.25 0.25
0 0 1 % <---- starts to repeat
You can always select one of the other colormaps which use interpolation to build as many colors as you want. See doc colormap for a list of supported ones.
Similarly you can build you own colormap using the same linear interpolation technique between a specified number of stop-points.
For example, the jet colormap is constructed by passing through a series of 9 endpoints as shown here, using linear interpolation in between. The hsv colormap is built in a similar manner, only it interpolates across the hue space rather than in RGB. Here is yet another example showing how to build a custom divergent colormap with red-white-blue endpoints.

The lines color map has only 7 unique colors (as you have already spotted).
If you need more than 7 unique colors, you'll have to create a map by yourself.
One option is using rand:
>> rCmap = rand( n, 3 ); % create a random map with n colors - usually unique.

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]);

Fitting a distribution for array with zeros

I have data from stimulation of subjects with different intensities (say we have 54 different intensities), and what follows is the percentage of them recognizing the respective stimulation:
x = [0 0 0 0.50 0 0 0 0 0 0 0.5 0 0 0 0 0 0 0 0.125000000000000 0 0.333333333333333 0 0 0.111111111111111 0 0.428571428571429 0 0.285714285714286 0.166666666666667 0 0.1 0 0.400000000000000 0.5 0.4 0.25 0.6 0.727272727272727 0.714285714285714 0.25 0.666666666666667 0.777777777777778 1 0.75 0 1 0.9375 1 1 1 1 1 0.92 0.92]
Say the first index is the weakest stimulation, and the last index the strongest, as visible the stronger the stimulation the more likely the subject recognizes it.
I want to fit now a distribution to these values, to get something called a psychophysical curve (looks like this).
What I have tried is:
pd = fitdist(x,distribution);
but this throws an error, I assume because of the 0's in the x array. What could I do alternatively?
As suggested in
Fit a sigmoid to my data using MATLAB
"I think you can use "Curve fitting" App in Matlab. you can find it in APPS, in "Math, statistics and optimization" section."
What you have to do is define two vector of the same length:
one with the stimuli
one with the respone
After, looking at your file, you can try ,using the "Curve Fitting" app in matlab, to fit a sigmoid.
After pressing the generate code button, matlab will create a fuction that will give the same result.

How to find centroid of an object in divided image [duplicate]

I have spent all day reading up on the above MATLAB functions. I can't seem to find any good explanations online, even on the MathWorks website!
I would be very grateful if anyone could explain bwlabel, regionprops and centroid. How do they work if applied to a grayscale image?
Specifically, they are being used in this code below. How do the above functions apply to the code below?
fun=#minutie; L = nlfilter(K,[3 3],fun);
%% Termination LTerm=(L==1);
figure; imshow(LTerm)
LTermLab=bwlabel(LTerm);
propTerm=regionprops(LTermLab,'Centroid');
CentroidTerm=round(cat(1,LTerm(:).Centroid));
figure; imshow(~K)
set(gcf,'position',[1 1 600 600]); hold on
plot(CentroidTerm(:,1),CentroidTerm(:,2),'ro')
That's quite a mouthful to explain!... nevertheless, I'd love to explain it to you. However, I'm a bit surprised that you couldn't understand the documentation from MathWorks. It's actually quite good at explaining a lot (if not all...) of their functions.
BTW, bwlabel and regionprops are not defined for grayscale images. You can only apply these to binary images.
Update: bwlabel still has the restriction of accepting a binary image but regionprops no longer has this restriction. It can also take in a label matrix that is usually output from bwlabel as well as binary images.
Assuming binary images is what you want, my explanations for each function is as follows.
bwlabel
bwlabel takes in a binary image. This binary image should contain a bunch of objects that are separated from each other. Pixels that belong to an object are denoted with 1 / true while those pixels that are the background are 0 / false. For example, suppose we have a binary image that looks like this:
0 0 0 0 0 1 1 1 0 0
0 1 0 1 0 0 1 1 0 0
0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 1 1
0 0 1 1 1 1 0 0 1 1
You can see in this image that there are four objects in this image. The definition of an object are those pixels that are 1 that are connected in a chain by looking at local neighbourhoods. We usually look at 8-pixel neighbourhoods where you look at the North, Northeast, East, Southeast, South, Southwest, West, Northwest directions. Another way of saying this is that the objects are 8-connected. For simplicity, sometimes people look at 4-pixel neighbourhoods, where you just look at the North, East, South and West directions. This woudl mean that the objects are 4-connected.
The output of bwlabel will give you an integer map where each object is assigned a unique ID. As such, the output of bwlabel would look something like this:
0 0 0 0 0 3 3 3 0 0
0 1 0 1 0 0 3 3 0 0
0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 4
0 0 0 0 0 0 0 0 4 4
0 0 2 2 2 2 0 0 4 4
Because MATLAB processes things in column major, that's why the labelling is how you see above. As such, bwlabel gives you the membership of each pixel. This tells you where each pixel belongs to if it falls on an object. 0 in this map corresponds to the background. To call bwlabel, you can do:
L = bwlabel(img);
img would be the binary image that you supply to the function and L is the integer map I just talked about. Additionally, you can provide 2 outputs to bwlabel, and the second parameter tells you how many objects exist in the image. As such:
[L, num] = bwlabel(img);
With our above example, num would be 4. As another method of invocation, you can specify the connected pixel neighbourhoods you would examine, and so you can do this:
[L, num] = bwlabel(img, N);
N would be the pixel neighbourhood you want to examine (i.e. 4 or 8).
regionprops
regionprops is a very useful function that I use daily. regionprops measures a variety of image quantities and features in a black and white image. Specifically, given a black and white image it automatically determines the properties of each contiguous white region that is 8-connected. One of these particular properties is the centroid. This is also the centre of mass. You can think of this as the "middle" of the object. This would be the (x,y) locations of where the middle of each object is located. As such, the Centroid for regionprops works such that for each object that is seen in your image, this would calculate the centre of mass for the object and the output of regionprops would return a structure where each element of this structure would tell you what the centroid is for each of the objects in your black and white image. Centroid is just one of the properties. There are other useful features as well, but I'm assuming you don't want to do this. To call regionprops, you would do this:
s = regionprops(img, 'Centroid');
The above code will calculate the centroids of each of your objects in the image. You can specify additional flags to regionprops to specify each feature that you want. I do highly encourage that you take a look at all of the possible features that regionprops can calculate, as there are many that are useful in a variety of different applications and situations.
Also, by omitting any flags as input into the function, you would calculate all of the features in your image by default. Therefore, if we were to declare the image that we have seen above in MATLAB, this is what would happen after I run regionprops. After, let's calculate what the centroids are:
img = logical(...
[0 0 0 0 0 1 1 1 0 0;
0 1 0 1 0 0 1 1 0 0;
0 1 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 1;
0 0 0 0 0 0 0 0 1 1;
0 0 1 1 1 1 0 0 1 1]);
s = regionprops(img, 'Centroid');
... and finally when we display the centroids:
>> disp(cat(1,s.Centroid))
3.0000 2.6000
4.5000 6.0000
7.2000 1.4000
9.6000 5.2000
As such, the first centroid is located at (x,y) = (3, 2.6), the next centroid is located at (x,y) = (4.5, 6) and so on. Take special note that the x co-ordinate is the column while the y co-ordinate is the row.
Hope this is clear!

Matlab cdfplof do not show complete graph when multiple cdfs are plotted in one graph with x-axis as log scale

I am trying to use cdfplot() to plot multiple sets of data in one graph. When I use the normal x-axis, everything is fine. However, when I try to change the x-axis to log scale, the cdf plot of some sets of data do not display complete.
I have two sets of data: setFive and setSeven. I want to plot cdf of them in the same graph, with x-axis being log scale.
Here are the two graphs, one is in normal x-axis, the other is in log scale x-axis. The cdf of "five" in log scale x-axis does not go to 0.
The two sets of data are:
setSeven=[ 0.1478
0.2493
0.0650
0.1808
0.3633
0.1684
0.3116
0.1398
0
0
0.3069
0.3252
0.1762
0.4192
0
0.1163
0
0
0.2338
0
0.1388
0
0.2420
0.1115
0
0
0
0.1530
0.1675
0.3333
0
0
0.2351
0.1555
0
0
0.1691
0.2042
0.3143
0
0
0.2206
0
0.2288
0.1271
0
0.1852
0
0
0
0.1226
0
0
0.1571
0.1807
0
0
0
0.3231
0.1358
0.1681
0
0.1924
0.1494
0.1474
0.1030
0.2008
0.1455
0
0.2351
0.2537
0
0.1353
0
0.1320
0.1675
0.1844
0
0
0.2691
0.3640
0
0
0
0
0
0.2395
0
0
0
0.3156
0.2007
0.4463
0
0
0.2526
0.2375
0.3521
0.2279
0];
setFive=[0.1476
0.3300
0.0940
0.2704
0.3659
0.2214
0.3658
0.1402
0.2295
0.2105
0.3324
0.4011
0.2823
0.5740
0.2916
0.1940
0.2559
0
0.2423
0.1734
0.1992
0
0.2822
0.4122
0.2312
0
0.2598
0.3808
0.5833
0.6131
0
0.2831
0.6418
0.2269
0.2532
0.1944
0.3515
0.2734
0.3908
0.3223
0
0.3303
0
0.2759
0.2144
0
0
0
0.1747
0.2721
0.2509
0.2542
0
0.1381
0.2562
0.1918
0.2243
0.2260
0.3823
0.2404
0.3963
0.2917
0.2390
0.2818
0.2863
0.2366
0.2289
0
0.1183
0.2660
0.2535
0.1917
0.1976
0
0
0
0
0.4433
0
0.3395
0.4199
0.3674
0
0
0.2814
0
0.3816
0.4754
0.3198
0.4995
0.5585
0.2965
0.5316
0.4914
0.6343
0.4036
0.3632
0.4205
0.3089
0.4521];
Here are the codes:
e=cdfplot(setFive);
set(e,'LineStyle','-','color','k');
hold on;
g=cdfplot(setSeven);
set(g,'LineStyle','--','color','k');
hold on;
set(gca,'Xscale','log');
axis([0 1 0 1]);
get(gca,'xlim')
The problem is due to the processing the function cdfplot makes on the input, coupled with the logarithmic representation.
Consider the setSeven input data set (the same applies to setFive): the first 5 points generated by cdfplot are:
x7= -Inf 0 0 0.0650 0.0650
y7= 0 0 0.4300 0.4300 0.4400
You canget these points using the get function wiht the handles returned by cdfplot:
x5=get(e,'xdata');
y5=get(e,'ydata');
x7=get(g,'xdata');
y7=get(g,'ydata');
where:
x5: x data from setFive data set
y5: y data from setFive data set
x7: x data from setSeven data set
x7: y data from setSeven data set
In the first of your graph, you see the line starting from x=0, y=0 then climbing to x=0, y=0.43.
In this graph actually the first point x=-inf, y=0 is missing since the plot function simply ignores values such as -inf, inf, NaN.
Something similar happens when you set the xaxis scale as logarithmic:
In this case, the first 3 point are ignored, since
log10([-Inf 0 0 0.0650 0.0650]) is [ Inf + 1.3644i -Inf -Inf -1.1871 -1.1871]
so, the first two point displayable on the graph are the fourth and the fifth which correspond to:
x=0.0650, y=0.4300
x=0.0650, y=0.4400
the first three point are then ignored.
As said at the beginning, this also happens for the setFive data set.
In this case you have:
x5= -Inf 0 0 0.0940 0.0940
y5= 0 0 0.1900 0.1900 0.2000
So in the first graph the first point is not diplayed and since
log10([ -Inf 0 0 0.0940 0.0940]) is Inf + 1.3644i -Inf -Inf -1.0269 -1.0269
the first three point will not be displayed in the second graph (log scale).
In conlcusion, you are right, some points are not diplayed in both the graphs but this is correct given the set of data to be displayed and the function you are using.
You can find below the two graphs zoomed to highlight the first point plotted (setFive in red, setSeven in black).
Zoom of the graph with xaxis linear scale
Zoom of the graph with xaxis logarithmic scale
Hope this helps.
Well it does exactly what it should do.
The cdf tries to generate a function that mimics the population distribution from the sample you gave it.
As a tule of thumb I prefer using the plot function, as it gives you more power and you are in complete control of the data.
So if you consider the below code and the figure it creates, it just means that in log space (where log(0) = -inf) you cannot plot any value of zero.
Therefore, only values that differ from zeros are viable, and the rest are omitted from the plot.
now if you find out these in the two data sets, using the following line
[min(cx5(cx5>0)),min(cx7(cx7>0))]
you will see that set five minimal value is much larger than set seven.
Now think on what is the log spacing when max is one, it emphasizes differences that are closer to zero on the expense of differences that are closer to one.
But as far as cdf's go these results are impressive.
Enjoy.
[cy5,cx5] = ecdf(setFive);
[cy7,cx7] = ecdf(setSeven);
subplot(221)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
axis([0 1 0 1])
subplot(222)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
set(gca,'Yscale','log');
axis([0 1 0 1])
subplot(223)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
set(gca,'Xscale','log');
axis([0 1 0 1])
subplot(224)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
set(gca,'Xscale','log','Yscale','log');
axis([0 1 0 1])

Matlab: Using imagesc in grayscale without black

Beginning with a simple 2D matrix m of either 0 or 1 as an example:
m = [ 0 0 0 1 1
0 1 1 1 0
1 1 0 0 1
0 0 0 1 0 ]
How would I get this image to be displayed in a figure as only white and one gray using imagesc()? Currently, my code would is something like this:
imagesc(m)
colormap(gray)
colorbar
I've experimented with various ways to adjust the colormap and set limits on which values are used with CLim, but I have not found a way to limit the actual colors themselves so that instead of having white and black for values of 0 and 1, we have a white and (light) gray value for 1 and 0, respectively. Any quick and easy ways to do this?
Note: I should also mention that I want these so I can overlay a a contour plot of the same dimensions (but different values) and by using black, so I'm not sure if that would factor into any answers, but I am also open to suggestions with that in mind.
imagesc(m)
cmap = [.7 .7 .7 %// light gray
1 1 1] %// white
colormap(cmap)
colorbar('Ytick',[.25 .75],'Yticklabel',[0 1]) %// only two values in colorbar