Consider the following MATLAB code:
C = [ 0 0 0 0 0
0 1 2 1 0
0 2 4 2 0
0 1 2 1 0
0 0 0 0 0 ];
pcolor( C );
shading interp;
axis square
Note that C is invariant under 90 degree rotations. Also note this sentence from the help for pcolor:
With shading interp, each cell is colored by bilinear interpolation of the colors at its four vertices, using all elements of C.
However, the plotted image is as follows:
Note that the image is not invariant under 90 degree rotations (consider e.g. the four corners). Now, unless I horribly misunderstand bilinear interpolation, this must be wrong. MATLAB seems to be interpolating on triangles, which is not the same as bilinear interpolation.
Is there any way of working round this MATLAB bug, and getting correct bilinear interpolation? (Other than manually interpolating additional points myself, which still would not cure the issue if one zoomed in far enough.)
I remember having read a few threads concerning this weird behavior in the official Matlab forums, in the past. Unfortunately, I found none right now with a quick search. Anyway... you aren't the first used pointing out that shading interp, used in combination with with pcolor, behaves in a weird manner, creating shapes that don't reflect the underlying data.
The main problem is that shading interp interpolates between data points without caring about how sensible your grid is to smoothing. If you want a result that doesn't look jagged, you have to provide data sampled at a higher resolution:
C = [
0 0 0 0 0
0 1 2 1 0
0 2 4 2 0
0 1 2 1 0
0 0 0 0 0
];
C = interp2(C,5,'cubic');
pcolor(C);
shading interp;
axis square;
This produces an amazing result, and the output doesn't show any artifact or asymmetry:
Related
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]);
I would like to ask that what's the origin pixel in the image coordinate system used in poly2mask function in MATLAB.
It's been asked by others in OpenCV and wonder if it's the same in MATLAB. Let me repeat the person's question:
In general there may be two kinds of such systems, for the first (0,0) is defined as the center of the upper left pixel, which means the upper left corner of the upper left pixel is (-0,5, -0.5) and the center of the image is ((cols - 1) / 2, (rows - 1) / 2).
The other one is that (0,0) is the upper left corner of the upper left pixel, so the center of the upper left pixel is (0.5, 0.5) and the center of the image is (cols / 2, rows / 2).
My question is which system is adopted in poly2mask function in MATLAB?
MATLAB uses 1-based indexing, not 0-based indexing. Consequently, the top-left pixel has the center at (1,1). poly2mask follows the same convention, they're pretty consistent at the MathWorks.
This experiment shows this:
>> poly2mask([0.8,1.2,1.2,0.8],[0.8,0.8,1.2,1.2],3,5)
ans =
3×5 logical array
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
I drew a polygon closely around the (1,1) point, and the mask shows the top-left pixel marked. If you draw a polygon around the (0.5,0.5) point, no pixel is marked:
>> poly2mask([0.8,1.2,1.2,0.8]-0.5,[0.8,0.8,1.2,1.2]-0.5,3,5)
ans =
3×5 logical array
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
The one thing that is easy to make mistakes with is the order of the axes. The first index is y the second is x. But many functions in the Image Processing Toolbox (and elsewhere) take coordinates as (x,y), rather than as (y,x). For example:
>> poly2mask([0.8,1.2,1.2,0.8]+1,[0.8,0.8,1.2,1.2],3,5)
ans =
3×5 logical array
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0
Here, x = 2 and y = 1, and the pixel ans(1,2) is set!
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!
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
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.