code to define mask in matlab - matlab

I am working on developing a CBIR system, where I have to segment my RGB image in the following way:
I am implementing the code in matlab, but I am unable to build the proper masks for it.
I used imellipse but that requires the image handle which is achieved using imshow, but I don't want to show my image.
My code is
img=imread('peppers.png');
h_im=imshow(img); %I want to get rid of imshow because I don't want to show the image
[height, width, planes]=size(img);
%(cX,cY) is image center
cX=width/2;
cY=(height)/2;
%Here I define my ROI which is an ellipse that stretches to 75 percent of
%height and width of the image
e=imellipse(gca,[(1/2-3/8)*width, (1/2-3/8)*height,(3/4)*width,(3/4)*height]);
mymask=createMask(e,h_im);
%extending mask to three channels
mymask=repmat(mymask,[1 1 3]);
ROI=img;
ROI(mymask==0)=0;
figure, imshow(ROI);

You can generate the ellipse mask yourself rather than using the imellipse command.
% Create a meshgrid the same size of the image in order to generate the mask
[x y] = meshgrid(1:size(img, 1), 1:size(img, 2));
% Create the eclipse mask using the general form of an eclipse
% This will be centered in the middle of the image
% and have a height and width of 75% of th eimage
A = (0.75/2)*size(img, 2);
B = (0.75/2)*size(img, 1);
mask = A^2*(x - floor(size(img, 1)/2)).^2 + B^2*(y - floor(size(img, 2)/2)).^2<=A^2*B^2;
% Apply the eclipse mask
masked_image = img.*repmat(mask, [1, 1, 3]);

A bit of a hack but you could create a 'hidden' figure. The only difference is that I added: figure('Visible', 'off') at the start of your code.
figure('Visible', 'off');
img=imread('peppers.png');
h_im = imshow(img); %I want to get rid of imshow because I don't want to show the image
[height, width, planes]=size(img);
%(cX,cY) is image center
cX=width/2;
cY=(height)/2;
%Here I define my ROI which is an ellipse that stretches to 75 percent of
%height and width of the image
e=imellipse(gca,[(1/2-3/8)*width, (1/2-3/8)*height,(3/4)*width,(3/4)*height]);
mymask=createMask(e,h_im);
%extending mask to three channels
mymask=repmat(mymask,[1 1 3]);
ROI=img;
ROI(mymask==0)=0;
figure, imshow(ROI);

I think this code is easy to understand and easily adjustable to address an arbitrary part of your image (It has the same output as your code) :
img = imread('peppers.png');
% define the size of your ellipse relatively to the image dimension
factor = 0.75;
hwidth = size(img, 2) / 2.0;
hheight = size(img, 1) / 2.0;
a = hwidth * factor;
b = hheight * factor;
[x, y] = meshgrid(1:hwidth, 1:hheight);
% simple ellipse equation gets us part three of your mask
bottom_right_mask = (((x.^2)/a^2+(y.^2)/b^2)<=1);
% flip to get the remaining ones
top_right_mask = flipud(bottom_right_mask);
bottom_left_mask = fliplr(bottom_right_mask);
top_left_mask = flipud(bottom_left_mask);
mask = [top_left_mask, top_right_mask; ...
bottom_left_mask, bottom_right_mask];
multichannel_mask = repmat(mask,[1 1 3]);
ROI = img;
ROI(multichannel_mask==0) = 0;
figure;
imshow(ROI);

Related

Speeding up Octave / Matlab plot

Gnoivce and Hartmut helped a lot with this code but it takes a while to run.
The CData property in the bar command doesn't seem to be implemented in the Octave 4.0-4.2.1 version which I'm using. The work around for this was to plot all the single bars individually and set an individual color for each individual bar. People helped me out and got me this far but it takes 5 minutes for the plot to show does anyone know a way of speeding this up?
The following code runs:
marbles.jpg image file used below:
clear all,clf reset,tic,clc
rgbImage = imread('/tmp/marbles.jpg');
hsvImage = rgb2hsv(rgbImage); % Convert the image to HSV space
hPlane = 360.*hsvImage(:, :, 1); % Get the hue plane scaled from 0 to 360
binEdges = 0:360; %# Edges of histogram bins
N = histc(hPlane(:),binEdges); %# Bin the pixel hues from above
C = colormap(hsv(360)); %# create an HSV color map with 360 points
stepsize = 1; % stepsize 1 runs for a while...
for n=binEdges(2:stepsize:end) %# Plot the histogram, one bar each
if (n==1), hold on, end
h=bar(n,N(n));
set(h,'FaceColor',C(n,:)); %# set the bar color individually
end
axis([0 360 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('HSV hue (in degrees)'); %# Add an x label
ylabel('Bin counts'); %# Add a y label
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
Plot created after 5 mins:
To see original question original question
I'm guessing the loop is the bottleneck in your code that is taking so long? You could remove the loop and create the plot with one call to bar, then call set to modify the hggroup object and its child patch object:
h = bar(binEdges(1:end-1), N(1:end-1), 'histc'); % hggroup object
set(h, 'FaceColor', 'flat', 'EdgeColor', 'none');
hPatch = get(h, 'Children'); % patch object
set(hPatch, 'CData', 1:360, 'CDataMapping', 'direct');
Repeating your code with this fix renders right away for me in Octave 4.0.3:
As I suggested in a comment, I would use image (takes 0.12s on my system for your image).
EDIT: more comments, fix little bug, allow to create bins with stepsize > 1
img_fn = "17S9PUK.jpg";
if (! exist (img_fn, "file"))
disp ("downloading image from imgur.com...");
fflush (stdout);
urlwrite ("http://i.imgur.com/17S9PUK.jpg", "17S9PUK.jpg");
endif
rgbImage = imread (img_fn);
## for debugging so the matrixes fit on screen
if (0)
pkg load image
rgbImage = imresize (rgbImage, [6 8]);
endif
hsvImage = rgb2hsv(rgbImage);
hPlane = 360 .* hsvImage(:, :, 1);
## create bins, I've choosen 2 step to "smooth" the result
binEdges = 1:2:360;
N = histc (hPlane(:), binEdges)';
cm = permute (hsv (numel (binEdges)), [3 1 2]);
## Create an image with x = hue
img = repmat (cm, max(N), 1);
## Create binary mask which is used to black "img" dependent on N
sp = sparse (N(N > 0), (1:360)(N > 0), true, max(N), numel (binEdges));
mask = full (cumsum (flipud (sp)));
## extend mask in depth to suppress RGB
mask = repmat (mask, [1 1 3]);
## use inverted mask to "black out" pixels < N
img(logical (1 - flipud (mask))) = 0;
## show image
image (binEdges, 1:max(N), img)
set (gca, "ydir", "normal");
xlabel('HSV hue (in degrees)');
ylabel('Bin counts');
## print it for stackoverflow
print ("out.png")
Same as above but with bin width 1 (Elapsed time is 0.167423 seconds.)
binEdges = 1:360;

MATLAB - Splitting an image converts the blocks into grayscale

Using MATLAB, I am trying to convert a randomly sized image into four equal blocks. I am working with "for" loops to create blocks. The problem I am facing is that these blocks are being converted into gray scale whereas I want the blocks to retain their original form i.e. RGB channel. Here is the code I am using:
clear all;
img1 = imread('ABC.png');
[rs, cols, colorchan] = size(img1);
rnew = int32(rs/2);
cnew = int32(cols/2);
for i = 1:4
for j = 1:4
imgij = img1((i-1)*rnew+1:i*rnew, (j-1)*cnew+1:j*cnew);
figure();
imshow(imgij);
%do some other stuff here%
end
end
I am new to MATLAB and that's the best I could do myself. Can somebody please tell me how to retain the original form of every block of the parent image? Any help will be highly appreciated.
You have considered only the width and height of the image. But actually for a colour image, colour is the 3rd dimension in Matlab. Try the following code.
img = imread('onion.png');
figure; imshow(img);
w = size(img,2); % width of the original image
h = size(img,1); % height of the original image
wm = floor(w/2); % middle of the width
hm = floor(h/2); % middle of the height
figure;
imgtl = img(1:hm,1:wm,:); % top left image
subplot(2,2,1); imshow(imgtl);
imgtr = img(1:hm,wm+1:w,:); % top right image
subplot(2,2,2); imshow(imgtr);
imgbl = img(hm+1:h,1:wm,:); % bottom left image
subplot(2,2,3); imshow(imgbl);
imgbr = img(hm+1:h,wm+1:w,:); % bottom right image
subplot(2,2,4); imshow(imgbr);
Original image:
Partitioned image:

Background Image for Plot

Is there an easy way to put a bitmap image in the background of a Matlab plot which does not fill the whole available space und keeps its aspect ratio when the figure is resized?
TIA
I'm not quite sure to understand what you mean by
plot which does not fill the whole available space
however the following solution should help you solve your problem (or at least get you started).
Basically read an image (here grayscale) and display it using the imagesc command along with the grayscale colormap, then issue the hold on command and plot the data. Notice that you need to reverse the direction of the x-axis in order to get the right direction for the plot.
Here is the code:
clear
clc
close all
A = imread('cameraman.tif');
x = 1:10;
y = x;
figure
%// Notice the fliplr(A) to reverse the direction of the x data
imagesc([min(x(:)) max(x(:))], [min(y(:)) max(y(:))],fliplr(A));
colormap gray
%// Here reverse the direction of the x axis, otherwise the plot is
%// reversed
set(gca,'XDir','reverse')
hold on
plot(x,y,'--r')
axis off
And the result:
If your background image is RGB, you can use the image function: (modified from answer here): You need to flip the x data from the image for each channel separately, because fliplr only accepts 2D arguments:
DataXImage = linspace(min(x), max(x), size(A, 2));
DataYImage = linspace(min(y), max(y), size(A, 1));
%// flip dimensions for each channel
B = cat(3,fliplr(A(:,:,1)),fliplr(A(:,:,2)),fliplr(A(:,:,3)));
image(DataXImage, DataYImage, B, 'CDataMapping', 'scaled');
which, using the peppers.png image, gives this:
Is this what you had in mind? If not please tell me!
img = imread('myimage.png');
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
% make data to plot - just a line.
x = min_x:max_x;
y = (6/8)*x;
imagesc([min_x max_x], [min_y max_y], img);
hold on;
plot(x,y);

plot circle with gradient gray scale color in matlab

I want to draw a circle with gradient color in matlab, but I can't. Is there any one that can help me?
the sample image can be found here
Here's one approach -
N = 200; %// this decides the size of image
[X,Y] = meshgrid(-1:1/N:1, -1:1/N:1) ;
nrm = sqrt(X.^2 + Y.^2);
out = uint8(255*(nrm/min(nrm(:,1)))); %// output image
figure, imshow(out) %// show image
Output -
If you would like to pad the output with white boundary as shown in the expect output image, you can do so with padarray -
padsize = 50; %// decides the boundary width
out = padarray(out,[padsize padsize],255);

Apply a gaussian distribution in a specific part of an image

I have for example the following image and a corresponding mask.
I would like to weight the pixels inside the white circle with a Gaussian, g = #(x,y,xc,yc) exp(-( ((x-xc)^2)/0.5 + ((y-yc)^2)/0.5 ));, placed in the centroid (xc,yc) of the mask. x, y are the coordinates of the corresponding pixels. Could you please someone suggest a way to do that without using for loops?
Thanks.
By "weighting" pixels inside the ellipse, I assume you mean multiply elementwise by a 2D gaussian. If so, here's the code:
% Read images
img = imread('img.jpg');
img = im2double(rgb2gray(img));
mask = imread('mask.jpg');
mask = im2double(rgb2gray(mask)) > 0.9; % JPG Compression resulted in some noise
% Gaussian function
g = #(x,y,xc,yc) exp(-(((x-xc).^2)/500+((y-yc).^2)./200)); % Should be modified to allow variances as parameters
% Use rp to get centroid and mask
rp_mask = regionprops(mask,'Centroid','BoundingBox','Image');
% Form coordinates
centroid = round(rp_mask.Centroid);
[coord_x coord_y] = meshgrid(ceil(rp_mask.BoundingBox(1)):ceil(rp_mask.BoundingBox(1))+rp_mask.BoundingBox(3)-1, ...
ceil(rp_mask.BoundingBox(2)):ceil(rp_mask.BoundingBox(2))+rp_mask.BoundingBox(4)-1);
% Get Gaussian Mask
gaussian_mask = g(coord_x,coord_y,centroid(1),centroid(2));
gaussian_mask(~rp_mask.Image) = 1; % Set values outside ROI to 1, this negates weighting outside ROI
% Apply Gaussian - Can use temp variables to make this shorter
img_g = img;
img_g(ceil(rp_mask.BoundingBox(2)):ceil(rp_mask.BoundingBox(2))+rp_mask.BoundingBox(4)-1, ...
ceil(rp_mask.BoundingBox(1)):ceil(rp_mask.BoundingBox(1))+rp_mask.BoundingBox(3)-1) = ...
img(ceil(rp_mask.BoundingBox(2)):ceil(rp_mask.BoundingBox(2))+rp_mask.BoundingBox(4)-1, ...
ceil(rp_mask.BoundingBox(1)):ceil(rp_mask.BoundingBox(1))+rp_mask.BoundingBox(3)-1) .* gaussian;
% Show
figure, imshow(img_g,[]);
The result:
If you instead want to perform some filtering within that roi, there's a function called roifilt2 which will allow you to filter the image within that region as well:
img_filt = roifilt2(fspecial('gaussian',[21 21],10),img,mask);
figure, imshow(img_filt,[]);
The result: