How to get image matrix from axes content - matlab

Is there a way to get the content of a contourf plot as an image matrix? I want rasterize only the content, not the axes, labels and the empty space of the entire figure.
My goal is to overlay a transparent, colored contour plot over a grayscale image and I don't see another way, since MATLAB has only one colormap per figure.

Try getframe and frame2im
Example from the frame2im documentation:
Create and capture an image using getframe and frame2im:
peaks %Make figure
f = getframe; %Capture screen shot
[im,map] = frame2im(f); %Return associated image data
if isempty(map) %Truecolor system
rgb = im;
else %Indexed system
rgb = ind2rgb(im,map); %Convert image data
end

Not a direct answer to the question, but this is how I think you could achieve your goal:
%# load in grayscale image
gray_im = rgb2gray(imread('peppers.png'));
%# converting n x m grey image to n x m x 3 rgb gray image
rgb_gray_im = cat( 3, gray_im, gray_im, gray_im );
%# displaying this image
imshow( rgb_gray_im );
%# plotting contourf on top with arbitrary colourmap
hold on
h = axes('position', [0.5, 0.5, 0.2, 0.2]);
z = peaks;
contourf(h, z, [min(z(:)), -6 : 8]);
Which gives the result:
The figure's colourmap is being used for the contourf plot. The background image is not relying on a colourmap, and is instead being displayed in truecolour - i.e. each pixel is being displayed as an RGB value defined in rgb_gray_im.
There are also other ways of getting around the MATLAB colourmap restrictions: see for example this blog post or these answers.

Related

Matlab overlay imagesc on binary image

I am trying to overlay an imagesc image on top of a binary image. I searched for it online, but no luck. Below is my code:
figure;
imshow(BW4);
hold on
imagesc(image2,'AlphaData',0.5); axis equal; axis tight; axis off;
myColorMap = jet(256);
myColorMap(1,:) = 0;
colormap(myColorMap); colorbar;
hold off
The output what I am getting looks like below image on right, instead of the jet colormap lines on top of white color. Can someone help me to fix this issue? I appreciate your time and effort.
Thanks,
Binary image
Jet image
Result what I am getting which I do not want
So we first read your bw data a and create some jet image b which is some nxm matrix of intensities:
a=rgb2gray(imread('fFIG2.png'));
a=a==max(a(:));
a=a>0; % now it is binary
% make jet data with 0 being it's minimal value
b=(imresize(peaks(100),size(a))).*a ;
b=b.*(b>0);
Now we normalize the data in b between 0 and 1 and make an RGB array out of it. The we'll create a mask and assign white to it...
cmap=[0,0,0;jet(255)]; % set the colormap to be always black and jet
% normalize from nxm matrix to nxmx3 rgb values
c=b;
c=round( ((c-min(c(:)) )/(max(c(:))-min(c(:))))*(length(cmap)-1)+1);
im=reshape(cmap(c(:),:),[size(c),3]);
% get the mask for all pixels that are in a but are zero in b
bw2=repmat( (a>0 & b==0),[1 1 3]);
im(bw2)=1; % assign this pixels with rgb=white
imagesc(im)

How can I convert an RGB histogram into a color spectrum?

How can I convert an RGB histogram of an image to create a histogram showing the combined colors along with correct color wavelength range?
Example code:
pkg load image
f=imread('/tmp/marbles.jpg');
f=uint8(f); %need to convert back to uint8 to show picture
%Split into RGB Channels
f_red = f(:,:,1);
f_green = f(:,:,2);
f_blue = f(:,:,3);
%Get histValues for each channel
[y_f_red, x] = imhist(f_red);
[y_f_green, x] = imhist(f_green);
[y_f_blue, x] = imhist(f_blue);
subplot (2,1,1); imshow(f);
subplot (2,1,2); plot(x, y_f_red, 'r', x, y_f_green, 'g', x, y_f_blue, 'b');
Example image along with separate RGB histogram the code produces:
I'm trying to get the histogram to look like the image below but have the colors go from red to blue:
Another image example:
PS: I'm using Octave 4.0 which is very similar to MATLAB.
There's a huge hurdle to converting between standard color representations (like RGB or HSV) and spectral wavelength: many colors can't be represented by a single wavelength of light. Colors such as magenta, pink, brown, or any grayscale color represent mixtures of different wavelengths. Generating an equivalent spectral wavelength is therefore a much more complicated endeavor (you may find some useful ideas and links here and here).
Creating histograms of the colors themselves may be a better way to go (illustrated in one of my other answers), but if you really want to relate color to wavelength in a simple fashion you can try the following...
A first step will be to convert RGB values to HSV values, then create a histogram of the hue channel. I'll adapt part of my answer from here to do that. The next step will be to map hues to wavelengths of light, using some rather gross approximations adapted from this answer:
rgbImage = imread('test_image.png'); % Load image
hsvImage = rgb2hsv(rgbImage); % Convert the image to HSV space
hPlane = 360.*hsvImage(:, :, 1); % Get the hue plane scaled from 0 to 360
binEdges = 0:270; % Edges of histogram bins
N = histc(hPlane(:), binEdges); % Bin the pixel hues from above
wavelength = 620-(170/270).*(0:269); % Approximate wavelength
hBar = bar(wavelength, N(1:end-1), 'histc'); % Plot the histogram
set(hBar, 'CData', 270:-1:1, ... % Change the color of the bars using
'CDataMapping', 'direct', ... % indexed color mapping (360 colors)
'EdgeColor', 'none'); % and remove edge coloring
colormap(hsv(360)); % Change to an HSV color map with 360 points
axis([450 620 0 max(N)]); % Change the axes limits
set(gca, 'Color', 'k'); % Change the axes background color
set(gcf, 'Pos', [50 400 560 200]); % Change the figure size
xlabel('Wavelength (nm)'); % Add an x label
ylabel('Bin counts'); % Add a y label
NOTE: For the above to work properly in Octave, it may be necessary to change the set(hBar, ... line to the following:
set(hBar, 'FaceColor', 'flat', 'EdgeColor', 'none');
set(get(hBar, 'Children'), 'CData', 270:-1:1, 'CDataMapping', 'direct');
And here's the histogram:
There is, however, one issue with this. If we instead use the code exactly as it is in my other answer to plot the histogram of all the hue values, we would get this:
Note that there is a big cluster of magenta, pink, and reddish pixels that gets excluded when we toss out part of the hue range to convert to wavelengths (they don't correspond to a single wavelength in the light spectrum). Incorporating these into the results would require a more complicated conversion from hue to wavelength.
you can not convert RGB to wavelength unless some physical properties of the image and light is met. Anyway you can fake this by inversing:
RGB values of visible spectrum
if you do not know how look at:
Reverse complex 2D lookup table
But the result will not be the same as physical wavelengths histogram ... For that you would need multi-band image acquisition either by rotating prism optics or by set of bandpass filters ...
PS. HSV is far from accurate ...
Btw. the easiest way to do this is create palette from the spectral colors and convert your input image to it (indexed colors) and then just create histogram sorted by wavelength (and or color index)...
Based on gnovices answer but with an image instead of bar (take 0.12s on my system):
rgbImage = imread ("17S9PUK.jpg");
hsvImage = rgb2hsv(rgbImage);
hPlane = 360 .* hsvImage(:, :, 1);
binEdges = 1:360;
N = histc (hPlane(:), binEdges);
cm = permute (hsv (360), [3 1 2]);
img = repmat (cm, max(N), 1);
row_index = max(N) - N';
sp = sparse (row_index(row_index>0), (1:360)(row_index>0), true);
mask = flipud (cumsum (sp));
img(repmat (logical(1 - full(mask)), [1 1 3])) = 0;
image (img)
set (gca, "ydir", "normal");
xlabel('hue');
ylabel('Bin counts');

Separate colormap for each subplot in Octave

Matlab provides an ability to set individual colormaps for each subplot. The same functionality described by Octave docs
Namely following phrases:
Function File: cmap = colormap (hax, …)
If the first argument hax is an axes handle, then the colormap for the parent figure of hax is queried or set.
But when I try to run following code, I end up having single colormap for all subplots for some reason.
clear -all;
clc;
img = zeros(128, 128);
img(64,64) = 0.2;
rad = radon(img);
x = 1;
y = 4;
s1 = subplot(y,x,1); imagesc(img);
colormap(s1, gray);
s2 = subplot(y,x,2); imagesc(rad);
colormap(s2, hot);
colorbar;
line_img = zeros(128, 128);
line_img(64, 32:64) = 0.5;
line_img(63, 32:64) = 0.4;
line_img(63, 32:64) = 0.2;
line_rad = radon(line_img);
s3 = subplot(y,x,3); imshow(line_img);
colormap(s3, gray);
s4 = subplot(y,x,4); imagesc(line_rad);
colormap(s4, hot);
colorbar;
Any help is appreciated. I expect to have source images in grayscale and radon transform images in "hot". For some reason I'm getting first subplot somewhat like grayscale (it's actually not, since I initialize point with value 0.2 and octave gives me pure white color for it, while I'm expecting reasonably dark gray), and thee remaining images seem to have "hot" colormap being set.
If you read that line from the documentation a little close you will see that is that that if you pass an axes handle that the parent figure's colormap is changed. This is not the same as each axes having a different colormap since they're all in the same figure.
Function File: cmap = colormap (hax, …) If the first argument hax is an axes handle, then the colormap for the parent figure of hax is queried or set.
Currently, Octave does not support this functionality which was only just recently introduced in MATLAB.
The way around this is to convert your images to RGB images prior to displaying with imshow and then the figure's colormap is irrelevant. You can do this by first converting it to an indexed image (using gray2ind) and then to RGB with ind2rgb.
% To display the grayscale image
rgb = ind2rgb(gray2ind(img), gray);
imshow(rgb);
As a side note, the reason that your first grayscale image is showing up as all white is that if the input to imshow is of type double, then all values are expected to be between 0 and 1. If you want to change this behavior you can use the second input of imshow to specify that you'd like to scale the color limits to match your data
imshow(img, [])

Displaying a quiver plot of a gradient image in MATLAB

I have an image. I want to display a quiver plot of the gradient image that I get using gradient function in MATLAB, preferably superimposed on the gradient image.
I = imread('image.png');
[gx,gy] = gradient(double(rgb2gray(I)));
g = abs(gx) + abs(gy);
figure;
imshow(g, []);
hold on;
quiver(abs(gx),abs(gy));
This is what I tried, and all I get is a completely blue display.
I think all you see is the arrows, but they're too close together.
If you plot the two graphs (imshow(g) and quiver) separately, they show up normal. The imshow only shows the pixels without any scaling, if you fix that (make it scale) the quiver arrows also will have more space between them and become visible.
You can do just that by adding the 'InitialMagnification','fit' option to imshow:
imshow(g,'InitialMagnification','fit')
Or you can show less quiver arrows:
figure;
imshow(g, []); % [] to display image properly
hold on;
[Nx, Ny] = size(g);
xidx = 1:10:Nx;
yidx = 1:10:Ny;
[X,Y] = meshgrid(xidx,yidx);
quiver(Y',X',abs(gx(xidx,yidx)),abs(gy(xidx,yidx)));

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