Image classification - coloring features with a colormap? - matlab

I have an image with some features/regions in it (balls in the above example). I want to color each ball with a different color based on its properties. For example, that might be its diameter in pixels.
While I'm done on the feature recognition side, I'm stuck when it comes to showing results. Right now I'm doing:
my_image = imread(...);
//ball recognition and other stuff
for i = 1:number_of_balls
ball_diameter(i) = ... //I calculate the diameter of the i-th ball
ball_indices = ... //I get the linear indices of the i-th ball
//ball coloring
my_image(ball_indices) = 255; //color the red channel
my_image(ball_indices + R*C) = 0; //color the blue channel
my_image(ball_indices + 2*R*C) = 0; //color the green channel
end
figure
imshow(my_image)
colormap jet(100) //I want 100 different classes
colorbar
caxis([0, 50]) //I assume all balls have a diameter < 50
In the above code I'm tinting all balls red, which is definitely not what I'm looking for. The issue is that, even if I know ball_diameter(i), I do not know which colormap class that ball will get in. In other words, I would need something like:
for i = 1:number_of_balls
// ...
if ball_diameter *belongs to class k*
my_image(ball_indices) = jet(k, 1);
my_image(ball_indices + R*C) = jet(k,2);
my_image(ball_indices + 2*R*C) = jet(k,3);
end
end
How to, and mostly, is there any other more logical way?

You can separate the assignment of pixels to classes from their coloring for display: you can use my_image as a 2D R-by-C labeling matrix: that is each object (ball) is assigned a different index from 1 to 100 (in case you have 100 objects in the image). Now when you want to display the result you can either ask the figure to map indexes to colors for you, using colormap or explicitly create a colored image using ind2rgb.
For example
%// create the index/labeling matrix
my_image = zeros( R, C );
for ii = 1:number_of_balls
my_image( ball_indices ) = ii; %// assign index to pixels and not atual colors
end
%// color using figure
figure;
imagesc( my_image );axis image;
colormap rand(100,3); %// map indexes to colors using random mapping
%//explicitly create a color image using ind2rgb
my_color_image = ind2rgb( my_image, rand(100,3) );
figure;
imshow( my_color_image ); % display the color image
Notes:
1. IMHO it is preferable to use random color map to display categorizations of pixels, as opposed to jet with which you usually end up with very similar colors to adjacent objects, making it very difficult to visually appreciate the result.
2. IMHO it is more convenient to use label matrix, you can also save it to file as an indexed image (png format) thus visualizing, saving and loading your results simply and efficiently.

A simple way is as follows:
Make a 2D image of the same size as your original.
Set the indices of each "ball" to the diameter or other relevant value
Display with imagesc
Use caxis, colormap, colorbar etc. to adjust the categories dynamically.
For example,
a = randi(200,200); % 200 x 200 image containing values 1 to 200 at random
imagesc(a)
colorbar
The above should show a random color field with the default colormap. The colorbar goes from 1 to 200.
colormap(jet(5))
The colorbar still goes from 1 to 200, but with only 5 colors.
caxis([1 100])
The colorbar now shows the five colors scaled from 1 to 100 (with everything above 100 in the top pot).
If you want to convert your 2D image full of different diameters to a set of discrete labels indicating diameter ranges, an easy way is to use histc with the second output bin being the same size as your input image, set to which bin the diameter value fell into. The second input in this case is the edges of the bins, not the centres.
[n bin] = histc(a,0:20:201);

Related

Outline of corresponding pixels

What I am doing is a pixel-based tree detection with the build-in MATLAB funktion imregionalmax. After a few steps, i get a matrix which contains values from 1 to n, based on how many trees were detected. Each tree is represented through a unique number (see image below). Pixels that don't belong to a tree are represented through NaN.
The result should look like this:
The closest I have been getting to the result above is by using the contour function, although it doesn't quite do the job, as it draws the outline through the middle of the pixels rather than on the outside.
Edit: I have a matrix with height values (same size as the above) and the outline is supposed to be only an overlay. Also, i want this outline to really be on the pixels' edges.
So you want to have a positive value whenever there is a change in your ROI matrix.
Seems to me you are looking for gradient
Maybe try this:
[FX,FY]=gradient(ROI_Matrix);
res = FX~=0 | FY~=0; %so if there is a change in the x-direction or in the y-direction the result for that pixel is 1.
image(res)
[edit]
You want to draw lines, not color pixels. So let's draw lines
imagesc(ROI_Matrix);
[FX,FY]=gradient(ROI_Matrix);
FX = FX~=0;FY = FY~=0;
hold on;
%change in x, horizontal line
for i = 1:size(FX,2)
for j = 1:size(FX,1)
if FX(i,j)
plot([i,i],[j,j+1],'k-');
end
end
end
%change in y, verticle line
for i = 1:size(FY,2)
for j = 1:size(FY,1)
if FY(i,j)
plot([i,i+1],[j,j],'k-');
end
end
end
hold off;

Creating a heatmap/colormap in Matlab, by mixing two colors

Hey I have two big matrices 400x400. That I want to create into one heatmap/colormap. Current code:
res = matrix_1*256/2 + matrix_2*256/2;
%res = res -max(max(res));
HeatMap(res)
surf(res,'EdgeColor','none');
view(0,90);
colormap(gray);
colorbar
disp('done');
where the heatmap function everyone can look up. But to give a visualization of the second one it results in:
This however does not let me know which matrix is dominant. But only that both are dominant (white) both are not dominant (dark). I would like to make a plot where I use fused data. E.g. Matrix 1 is nuance of red and Matrix 2 is nuance of green:
rgb = [matrix_1(i,ii), matrix_2(i,ii), 0]
then I want to make a 2D plot using the color that rgb represents. Is this possible ? I have looked at making my own colormap (but you guessed with no good results).
I have found solutions like this (how-to-create-an-interpolated-colormap-or-color-palette-from-two-colors) and create-a-colormap-in-matlab, but I how do I specify a specific colour for every point in a 2D plot?
Like this:
RGB = cat(3, matrix_1, matrix_2, zeros(size(matrix_1)));
imshow(RGB)
Now the chart will be black were neither are dominant, red where matrix_1 is but matrix_2 is not, green where matrix_2 is but matrix_1 is not and yellow where they both dominate.
If you wanted, you could even convert this back to an indexed image and get the colormap that colours it this way using rgb2ind and then create a surface plot using your original res for the heights (note there is no longer a need to scale this) and your new indexed image (ind) to specify the colours which are no longer enitrely goverened by height
res = (matrix_1 + matrix_2)/2;
[ind, map] = rgb2ind(RGB);
surf(res, ind, 'EdgeColor','none');
colormap(map)
colorbar

Produce a 3D stem plot with a custom colormap in MATLAB

I have a matrix (200 x 4) where first 3 values are X, Y and Z data. I want use the fourth column to display each (X,Y,Z) triplet so that it maps to a color.
The fourth column contains values from 0.0 to 1.0 (200 values). I want to map these values with colormap manually and linearly. The smallest value should have blue color and the largest value may have red color.
I know that it is possible with scatter3. However, I want to do using stem3 where I can specify the color manually from colormap.
Is there a way to do this in MATLAB?
That's pretty simple to do. kkuilla posted a very insightful link. To get something started, if you want to have a colour map that varies from blue to red, you know that an image is decomposed into three colours: Red, green and blue.
Therefore, all you would have to do is vary the red and blue channels. Start with a pure blue colour, which is RGB = (0,0,255) where this is mapped to the initial weight of w = 0 and vary this to the end where RGB = (255,0,0) with w = 1. You can very easily do that by linspace. However, colours in a colour map for plotting in MATLAB are normalized so that they're between [0,1], not [0,255]. Also, because a colour map in MATLAB is a matrix of N x 3, where N is the total number of colours you want, all you have to do is:
num_colours = 10;
colourmap = [linspace(0,1,num_colours).' zeros(num_colours,1) linspace(1,0,num_colours).'];
weights = linspace(0,1,num_colours);
num_colours is the total number of colours you would like displayed. I set it to 10 to get you started. weights is something we will need for later, so don't worry about that righ tnow. Essentially, colormap would be the colour map you apply to your data.
However, what is going to be difficult now is that the data that you're plotting has no correlation to the weight of the data itself (or the fourth column of your data). This means that you can't simply use the (X,Y,Z) data to determine what the colour of each plot in your stem is going to look like. Usually for colour maps in MATLAB, the height of the stem is proportional to the colour that is displayed. For the largest Z value in your data, this would naturally be assigned to the colour at the end of your colour map, or red. The smallestZ value in your data would naturally get assigned at the beginning of your colour map, or blue.
If this was the case, you would only need to make one stem call and specify the colour map as the attribute for Color. Because there is no correlation between the height of the Z value and the weight that you're assigning for each data point, you have no choice but to loop through each of your points and determine the closest value between the weight for a point with every weight and ultimately every colour in your colour map, then apply this closest colour to each point in your stem respectively.
We determine the closest point by using the weights vector that was generated above. We can consider each colour as having a mapping from [0,1], and each weight corresponds to the colour in colourmap. Therefore, a weight of 0 is the first colour in the colour map, and that's in the first row. The next weight after this is the second colour, and that's in the second row and so on.... so we simply need to determine where each weight that's in the fourth column of your matrix is closest to for the above weights vector. This will determine which colour we need to select from the colour map to plot the point.
Given that your matrix of 200 x 4 is stored in data, you must specifically do this:
%// Spawn a new figure
figure;
%// Determine the number of points in the dataset
num_points = size(data,1);
%// For each point in the data set
for idx = 1 : num_points
%// Get 4th column element and determine closest colour
w = data(idx,4);
[~,ind] = min(abs(weights-w));
color = colourmap(ind,:);
%// Plot a stem at this point and change the colour of the stem
%// as well as the marker edge colour and face colour
stem3(data(idx,1), data(idx,2), data(idx,3), 'Color', color, ...
'MarkerEdgeColor', color, 'MarkerFaceColor', color);
%// Make sure multiple calls to stem don't clear the plot
hold on;
end
%// Display colour bar to show colours
colormap(colourmap(1:end-1,:));
colorbar('YTickLabel', colourmap);
The last two lines are a bit hackish, but we basically show a colour bar to the right of the plot that tells you how each weight maps to each colour.
Let's test this on some data. I'm going to generate a random 200 x 4 matrix of points and we will use the above code and plot it using stem3:
rng(123123); %// Set seed for reproducibility
data = rand(200,4);
num_colours = 10;
I set the total number of unique colours to 10. Once I have this above data, when I run through the code above, this is the plot I get:
You can use HSV as well. The Z values would correspond to your fourth column. Low Z values are blue and high Z values are red.
I used the site http://colorizer.org/ to work out that blue is H=0.65 and red is H=1. S and V stay the same.
From http://colorizer.org/, I got that a blue colour is H=236, S=100, V=100. Then the H value for blue is H = 235/360 = 0.65 and H=1, S=1, V=1 for red.
num_elem = 200;
c = linspace(0,1,num_elem)'; % // Replace this with the values from your fourth column
% // The equation gives blue (H=0.65) for c=0 and red (H=1) for c = 1
H = 0.65 + ((1-0.65).* c);
S = ones(size(c,1),1);
V = ones(size(c,1),1);
% // You have to convert it to RGB to be compatible with stem3
colourmap = hsv2rgb([H,S,V]);
% // Generate some sample data
theta = linspace(0,2*pi,num_elem)';
X = cos(theta);
Y = sin(theta);
Z = theta;
% // Plot the sample data with the colourmap
figure;
hold on;
for idx=1:num_elem
stem3(X(idx),Y(idx),Z(idx),':*','Color',colourmap(idx,:) ...
,'MarkerEdgeColor',colourmap(idx,:) ...
,'MarkerFaceColor',colourmap(idx,:) ...
,'LineWidth',4 ...
);
end
hold off;
set(gca,'FontSize',36');

Fingerprint Minutiae Marking Matlab [duplicate]

I have a project on Fingerprint Matching and I got stuck at marking the points of termination and bifurcation on the image. I have already stored pixels' coordinates. How would I go about doing this?
Assuming that your image is stored in a grayscale image called im, and your points of termination and bifurcation are stored in 2D matrices where the first column denotes the row and the second column denotes the column of each point, you can easily do this using sub2ind. sub2ind converts 2D co-ordinates into linear indices so that you can easily vectorize setting pixels in an image, or locations in a matrix quickly. As such, make your grayscale image into a RGB image by stacking the image three times as a 3D matrix. If you recall, grayscale images in the RGB colour model have all of the red, green and blue channels the same. For example, gray would be (R,G,B) = (128,128,128).
Let's call your bifurcation points as bifur and terminations as term and are in that 2D matrix format I specified earlier. As such, do something like this:
%// Get linear indices for bifurcation and termination points
ind_b = sub2ind(size(im), bifur(:,1), bifur(:,2));
ind_t = sub2ind(size(im), term(:,1), term(:,2));
%// Mark them on the image
red = im;
green = im;
blue = im;
red(ind_b) = 255;
green(ind_b) = 0;
blue(ind_b) = 0;
red(ind_t) = 0;
green(ind_t) = 255;
blue(ind_t) = 0;
im_colour = cat(3, red, green, blue);
imshow(im_colour);
Let's walk through this code slowly. I first figure out the linear indices of where the bifurcation and termination points are in the image. What I do next is create red, green and blue channels that are all copies of the original image. After this, I access each colour channel and mark the bifurcation and termination points with different colours. For the bifurcation points, I made them purely red or (R,G,B) = (255,0,0). For the termination points, I made them purely green or (R,G,B) = (0,255,0). Once I set the colours for the points, I create a colour image by stacking the channels together with cat, and specifically choosing the third dimension. I finally show the image in the end.
What you may also have to play with is the size of the markings on the image. As you can see, the pixels that are marked are just the single pixels themselves, and depending on the resolution of your image, you may or may not be able to see them properly in the image. As such, I would recommend you mark the pixels within a grid surrounding the original point. Perhaps you can make this a 5 x 5 grid surrounding the pixel of interest. With this, perhaps make a for loop for each point and mark a 5 x 5 pixel grid that surrounds this point. I'm also going to assume that your markings are sufficiently well inside the image so that we don't risk drawing the grid out of bounds. So the code would be modified like so:
%// Get linear indices for bifurcation and termination points
ind_b = [];
for idx = 1 : size(bifur,1)
[c,r] = meshgrid(bifur(idx,2)-2:bifur(idx,2)+2, bifur(idx,1)-2:bifur(idx,1)+2);
c = c(:);
r = r(:);
ind_b = [ind_b; sub2ind(size(im), r, c);
end
ind_t = [];
for idx = 1 : size(term,1)
[c,r] = meshgrid(term(idx,2)-2:term(idx,2)+2, term(idx,1)-2:term(idx,1)+2);
c = c(:);
r = r(:);
ind_t = [ind_t; sub2ind(size(im), r, c);
end
%// Mark them on the image
red = im;
green = im;
blue = im;
red(ind_b) = 255;
green(ind_b) = 0;
blue(ind_b) = 0;
red(ind_t) = 0;
green(ind_t) = 255;
blue(ind_t) = 0;
im_colour = cat(3, red, green, blue);
imshow(im_colour);
What has changed is the beginning of the code. For each point that we have for the bifurcation and the termination points, I use meshgrid to determine a 5 x 5 grid of points that surround each relevant pixel, then generate the linear indices for each point within the 5 x 5 grid. I then add this into one final array for both so that we can carry out the same marking logic we saw above.
You'll have to play around with the colours if you want them to be other than red and green, but this should be something for you to start with. If you want a list of possible colours with the RGB model, a nice tool is the RGB colour picker where you figure out which colour you want, and it gives you the RGB values to replicate that colour.
Good luck!

matlab: how to plot multidimensional array

Let's say I have 9 MxN black and white images that are in some way related to one another (i.e. time lapse of some event). What is a way that I can display all of these images on one surface plot?
Assume the MxN matrices only contain 0's and 1's. Assume the images simply contain white lines on a black background (i.e. pixel value == 1 if that pixel is part of a line, 0 otherwise). Assume images are ordered in such a way as to suggest movement progression of line(s) in subsequent images. I want to be able to see a "side-view" (or volumetric representation) of these images which will show the surface that a particular line "carves out" in its movement across the images.
Coding is done in MATLAB. I have looked at plot (but it only does 2D plots) and surf, which does 3D plots but doesn't work for my MxNx9 matrix of images. I have also tried to experiment with contourslice, but not sure what parameters to pass it.
Thanks!
Mariya
Are these images black and white with simple features on a "blank" field, or greyscale, with more dense information?
I can see a couple of approaches.
You can use movie() to display a sequence of images as an animation.
For a static view of sparse, simple data, you could plot each image as a separate layer in a single figure, giving each layer a different color for the foreground, and using AlphaData to make the background transparent so all the steps in the sequenc show through. The gradient of colors corresponds to position in the image sequence. Here's an example.
function plotImageSequence
% Made-up test data
nLayers = 9;
x = zeros(100,100,nLayers);
for i = 1:nLayers
x(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
figure;
hold on;
for i = 1:nLayers
layerData = x(:,:,i);
alphaMask = layerData == 1;
layerData(logical(layerData)) = i; % So each layer gets its own color
image('CData',layerData,...
'AlphaData',alphaMask,...
'CDataMapping','scaled');
end
hold off
Directly showing the path of movement a "line" carves out is hard with raster data, because Matlab won't know which "moved" pixels in two subsequent images are associated with each other. Don't suppose you have underlying vector data for the geometric features in the images? Plot3() might allow you to show their movement, with time as the z axis. Or you could use the regular plot() and some manual fiddling to plot the paths of all the control points or vertexes in the geometric features.
EDIT: Here's a variation that uses patch() to draw each pixel as a little polygon floating in space at the Z level of its index in the image sequence. I think this will look more like the "surface" style plots you are asking for. You could fiddle with the FaceAlpha property to make dense plots more legible.
function plotImageSequencePatch
% Made-up test data
nLayers = 6;
sz = [50 50];
img = zeros(sz(1),sz(2),nLayers);
for i = 1:nLayers
img(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
% With each "pixel" as a separate patch
figure;
set(gca, 'XLim', [0 sz(1)]);
set(gca, 'YLim', [0 sz(2)]);
hold on;
for i = 1:nLayers
layerData = img(:,:,i);
[x,y] = find(layerData); % X,Y of all pixels
% Reshape in to patch outline
x = x';
y = y';
patch_x = [x; x+1; x+1; x];
patch_y = [y; y; y+1; y+1];
patch_z = repmat(i, size(patch_x));
patch(patch_x, patch_y, patch_z, i);
end
hold off