Matlab overlay imagesc on binary image - matlab

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)

Related

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

how to fill gradient color from light yellow to dark yellow?

With matlab, I don't know how patch can make gradient color vertically in this picture. Here I just want a simple color gradient. I have used bwboundaries to catch the edge function and fill pure color just like this:
for i=1:4
input=imread(['heartspline2_4_',num2str(i)],'bmp');
figure,imshow(input);
BW=im2bw(input,graythresh(input));
[B,L]=bwboundaries(BW,'noholes');
for k=1:length(B)
boundary=B{k};
plot(boundary(:,2),boundary(:,1),'k','LineWidth',2);
fvc=[1 1 0;1 0 0;0 0 1];
hold on;
axis off;
if (k==1)
patch(boundary(:,2),boundary(:,1),'w');
else
p=patch(boundary(:,2),boundary(:,1),'y');
end
end
saveas(gca,['y_','heartspline2_4_',num2str(i)],'bmp')
close(gcf)
end
Following Shai's code in his answer in your other question:
%% Load image %%
close all; clear all; clc;
img = imread('https://i.stack.imgur.com/yO8Nd.jpg'); %// read image
bw = img(:,:,1) > 128; %// convert to binary mask
lb = bwlabel(bw,4); %// extract distinct regions
%%
%% Create as many colors as needed
% example: 2
cmap=rand(2,3); % make this yellow if needed
% lets convert to HSV, we can tune the intesity of the image better here
cmap=rgb2hsv(cmap);
% for each color, lets crate a set of colors.
for ii=1:size(cmap,1);
colors{ii}= [cmap(ii,1)*ones(1,size(img,2)); cmap(ii,2)*ones(1,size(img,2)); linspace(0.3,1,size(img,2))].';
% Modify the limits of linspace
% to achieve control over the limits
end
% Now we have the colors, lets create an image of vertical colors and mask
% it
cimage=zeros(size(img,1),size(img,2),3); % empthy color image
finalimage=cimage;
for ii=1:size(colors,2)
colors{ii}=hsv2rgb(colors{ii});
cimage=permute(reshape(repmat(colors{ii},[size(img,1),1,1]),[size(img,2),size(img,1),3]),[2,1,3]); % there is probably a simpler way
finalimage=finalimage+cimage.*repmat((lb==ii),[1 1 3]);
end
figure; imshow(finalimage, [], 'border', 'tight');
If you understand the code properly, you will be able to do it for vertical gradient. I accidentally did horizontal, but should be alright. The code is commented, but do not hesitate to ask. The steps are the following
Create random colors, as many as desired. In this case 2
convert to HSV
Create a range of V values, that represent "light"
Repeat that list of colors for every row on the image
mask it with the labels to just add it to the areas of that label

How to draw box plot of the objects from regionprops?

I would like to plot the mean and percentile as shown in figure.I tried some code to plot box plot but I'm getting something different
I = propsSynthesizeImage;
imshow(I)
title('Synthetic Image')
% Create a Binary Image
% Segment the grayscale image by creating a binary image containing the objects in the image.
BW = I > 0;
imshow(BW)
title('Binary Image')
s = regionprops(BW, I, {'Centroid','PixelValues','BoundingBox'});
imshow(I);
numObj = numel(s);
title('Standard Deviation of Regions');
hold on
for k = 1 : numObj
s(k).StandardDeviation = std(double(s(k).PixelValues));
text(s(k).Centroid(1),s(k).Centroid(2), ...
sprintf('%2.1f', s(k).StandardDeviation), ...
'EdgeColor','b','Color','r');
end
figure
boxplot(1:numObj,[s.StandardDeviation])
xlabel('Region Label Number');
ylabel('Standard Deviation');
hold off
The boxplot visualizes a distribution. Currently, you're plotting scalars.
To plot the distribution (and have Matlab find median, quantiles, etc), plot
boxplot(1:numObj,{s.PixelValues})
Note that boxplot will not show standard deviations (instead, it shows the inter-quartile range), and that it may give misleading results if the underlying pixel values have a multi-modal distribution.

Surface plot with highligheted cut

I would like to plot a 3D surface using the Matlab surf function. The whole surface should be in gray scale, then I need to highlight a specific cut of the surface using a different color.
I thought this code would've worked but it doesn't.
Mat = randi(100); % Matrix to be plotted in gray scale
ind_highlight = 10; % Row of the matrix to be highlighted
Mat2 = Mat;
Mat2([1:ind_highlight-1, ind_highlight+1:end] ,:) = NaN;
figure
surf(X,Y,Mat)
colormap gray
hold on
% Highlight the ind_highlight row
surf(X,Y,Mat2)
colormap hsv
Any help would be highly appreciated!
It seems there is no way to use different colormap to obtain the desired effect since the colormap "belongs" to the figure.
I've found a possible solution which does not use colormap.
It is based on the specifying the color matrix in the call to surf, one for the whole matrix, one for the section to be highlighted, then superimposing the second one to the first one.
Unfortunately, I've not been able to set the first ad gray.
I've used the peaks matrix instead of your "randi" in order to have a more smooth surface to work with and inserted the script in a for loop to highlight different section of the matrix
% Mat = randi(100,100,100); % Matrix to be plotted in gray scale
% Alternative definition of the Matrix to be displayed
n_pt=50;
Mat=peaks(n_pt);
% Generate meshgrid
x=1:n_pt;
y=1:n_pt;
[X,Y]=meshgrid(x,y);
ind_highlight_2 = 5; % Number of rows of the matrix to be highlighted
% Generate two set of color matrix
% The first on for the whole surf
% The second one for the section to be highlighted
a=randi(2,n_pt,n_pt);
b=randi(10,n_pt,n_pt);
for i=1:n_pt-ind_highlight_2
ind_highlight_1 = i; % Starting row of the matrix to be highlighted
Mat2 = Mat;
% Modified set of data (in the original just one row was left
% Mat2([1:ind_highlight-1, ind_highlight+1:end] ,:) = NaN
Mat2(ind_highlight_1:ind_highlight_1+ind_highlight_2,:) = NaN;
COL=a;
COL(ind_highlight_1:ind_highlight_1+ind_highlight_2,:)=b(ind_highlight_1:ind_highlight_1+ind_highlight_2,:);
% Plot the surf specifying the color
s_h=surf(X,Y,Mat,COL);
shading interp
% view([0 90])
% f_name=['jpg_name_' num2str(i)]
% print('-djpeg75',f_name)
pause(.1);
end
Hope this helps.

How to get image matrix from axes content

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.