Cropping an ellipse from an image - matlab

I want to extract an elliptical region from an image (a portion of a face portion from an image) preferably in MATLAB:
For example, in this image, I want to extract the region within red boundary.
Can anyone help me with this ?

Cropping is easy, all you have to do is apply a proper mask. The trick is to create such a mask.
Assuming A is your image, try this:
%# Create an ellipse shaped mask
c = fix(size(A) / 2); %# Ellipse center point (y, x)
r_sq = [76, 100] .^ 2; %# Ellipse radii squared (y-axis, x-axis)
[X, Y] = meshgrid(1:size(A, 2), 1:size(A, 1));
ellipse_mask = (r_sq(2) * (X - c(2)) .^ 2 + ...
r_sq(1) * (Y - c(1)) .^ 2 <= prod(r_sq));
%# Apply the mask to the image
A_cropped = bsxfun(#times, A, uint8(ellipse_mask));
The cropped image will be stored in A_cropped.
Play with the coordinates of the center and the values of the radii until you get the desired result.
EDIT: I extended the solution for RGB images (if matrix A is 3-D).

This the method I use to crop faces into ellipse shape. It makes the background transparent.
[FileName,PathName] = uigetfile({'*.jpg;*.tif;*.png;*.gif','All Image Files'},'Please Select an Image');
image = imread([PathName FileName]);
imshow(image) %needed to use imellipse
user_defined_ellipse = imellipse(gca, []); % creates user defined ellipse object.
wait(user_defined_ellipse);% You need to click twice to continue.
MASK = double(user_defined_ellipse.createMask());
new_image_name = [PathName 'Cropped_Image_' FileName];
new_image_name = new_image_name(1:strfind(new_image_name,'.')-1); %removing the .jpg, .tiff, etc
new_image_name = [new_image_name '.png']; % making the image .png so it can be transparent
imwrite(image, new_image_name,'png','Alpha',MASK);
msg = msgbox(['The image was written to ' new_image_name],'New Image Path');
waitfor(msg);

Related

Image blurring results in a sharp edge

I'm doing some processing with MATLAB on an RGB image.
I had to obtain a circular blurring like in the image below:
obtained through this code:
A = imread('lena .bmp');
I = rgb2gray(A);
[rNum,cNum,~] = size(I);
%center and radius of the circular mask
x1 = 256.5;
y1 = 256.5;
radius = 100;
%circular mask creation
[x,y] = ndgrid((1:rNum)-y1,(1:cNum)-x1);
mask = (x.^2 + y.^2)<radius^2;
h = ones(30,30)/900; %gaussian filter
J = roifilt2(h,I,mask); %apply the filter at the mask
%filtering plane - by - plane in order to apply the circular blurred mask
%to the RGB image
filtered_im = zeros(size(A));
filtered_im(:,:,1) = roifilt2(h, A(:,:,1), mask);
filtered_im(:,:,2) = roifilt2(h, A(:,:,2), mask);
filtered_im(:,:,3) = roifilt2(h, A(:,:,3), mask);
filtered_im = uint8(filtered_im);
figure
imshow(filtered_im)
title('Circular blurring RGB image');
The effect obtained, anyway, is too artificial because the transition between the blurred circular mask and the rest of the image is too sharp. Is there a possibility to make this transition more faded in order to obtain a more natural effect?
You can use a weighted average of both the original image and the modified one, using as weights a mask based on the distance to the center of the circle.
The original one would have more weight in the external part of the circle, and the modified image in the center. This could create a transition in the blurring.

how to perform image enhancement over a small region of an image?

I would like to enhance a portion of the image. I would like to enhance the regions within rectangular region esp on the green rectangle region
You can use imcrop.
[I2 rect] = imcrop(I)
This will ask you to draw a rectangle and rect will thus contain the coordinates of that rectangle. I2 contains the cropped image and you can then apply any function you would like on that matrix.
Using a function like ginput you can select a point on an image, and with having a width and height values of a rectangle, you can crop a rectangle from your image. Then you can use any function such as imadjust to enhance your cropped part.
a= 100; % height
b= 100; % width
I = imread('myimage.png'); % read the image file
figure;imagesc(I); % plot the image
[x,y] = ginput(1); % select a point
I2 = I(:,:,1); %
Ic = imcrop(I2,[x-a/2 y-b/2 a b]); % crop a rectangle around the selected point
J = imadjust(Ic); % adjust the contrast
If you want to be able to select a rectangle, you can use the following command:
imshow('myimage.png');
rect = getrect;

Can we rotate an image in MATLAB filled with background color of original image?

By default, MATLAB function imrotate rotate image with black color filled in rotated portion. See this, http://in.mathworks.com/help/examples/images_product/RotationFitgeotransExample_02.png
We can have rotated image with white background also.
Question is, Can we rotate an image (with or without using imrotate) filled with background of original image?
Specific to my problem: Colored image with very small angle of rotation (<=5 deg.)
Here's a naive approach, where we simply apply the same rotation to a mask and take only the parts of the rotated image, that correspond to the transformed mask. Then we just superimpose these pixels on the original image.
I ignore possible blending on the boundary.
A = imread('cameraman.tif');
angle = 10;
T = #(I) imrotate(I,angle,'bilinear','crop');
%// Apply transformation
TA = T(A);
mask = T(ones(size(A)))==1;
A(mask) = TA(mask);
%%// Show image
imshow(A);
You can use padarray() function with 'replicate' and 'both' option to interpolate your image. Then you can use imrotate() function.
In the code below, I've used ceil(size(im)/2) as pad size; but you may want bigger pad size to eliminate the black part. Also I've used s and S( writing imR(S(1)-s(1):S(1)+s(1), S(2)-s(2):S(2)+s(2), :)) to crop the image where you can extract bigger part of image just expanding boundary of index I used below for imR.
Try this:
im = imread('cameraman.tif'); %// You can also read a color image
s = ceil(size(im)/2);
imP = padarray(im, s(1:2), 'replicate', 'both');
imR = imrotate(imP, 45);
S = ceil(size(imR)/2);
imF = imR(S(1)-s(1):S(1)+s(1)-1, S(2)-s(2):S(2)+s(2)-1, :); %// Final form
figure,
subplot(1, 2, 1)
imshow(im);
title('Original Image')
subplot(1, 2, 2)
imshow(imF);
title('Rotated Image')
This gives the output below:
Not so good but better than black thing..

How to measure the rotation of a image in MATLAB?

I have two images. One is the original, and the another is rotated.
Now, I need to discover the angle that the image was rotated. Until now, I thought about discovering the centroids of each color (as every image I will use has squares with colors in it) and use it to discover how much the image was rotated, but I failed.
I'm using this to discover the centroids and the color in the higher square in the image:
i = rgb2gray(img);
bw = im2bw(i,0.01);
s = regionprops(bw,'Centroid');
centroids = cat(1, s.Centroid);
colors = impixel(img,centroids(1),centroids(2));
top = max(centroids);
topcolor = impixel(img,top(1),top(2));
You can detect the corners of one of the colored rectangles in both the image and the rotated version, and use these as control points to infer the transformation between the two images (like in image registration) using the CP2TFORM function. We can then compute the angle of rotation from the affine transformation matrix:
Here is an example code:
%# read first image (indexed color image)
[I1 map1] = imread('http://i.stack.imgur.com/LwuW3.png');
%# constructed rotated image
deg = -15;
I2 = imrotate(I1, deg, 'bilinear', 'crop');
%# find blue rectangle
BW1 = (I1==2);
BW2 = imrotate(BW1, deg, 'bilinear', 'crop');
%# detect corners in both
p1 = corner(BW1, 'QualityLevel',0.5);
p2 = corner(BW2, 'QualityLevel',0.5);
%# sort corners coordinates in a consistent way (counter-clockwise)
p1 = sortrows(p1,[2 1]);
p2 = sortrows(p2,[2 1]);
idx = convhull(p1(:,1), p1(:,2)); p1 = p1(idx(1:end-1),:);
idx = convhull(p2(:,1), p2(:,2)); p2 = p2(idx(1:end-1),:);
%# make sure we have the same number of corner points
sz = min(size(p1,1),size(p2,1));
p1 = p1(1:sz,:); p2 = p2(1:sz,:);
%# infer transformation from corner points
t = cp2tform(p2,p1,'nonreflective similarity'); %# 'affine'
%# rotate image to match the other
II2 = imtransform(I2, t, 'XData',[1 size(I1,2)], 'YData',[1 size(I1,1)]);
%# recover affine transformation params (translation, rotation, scale)
ss = t.tdata.Tinv(2,1);
sc = t.tdata.Tinv(1,1);
tx = t.tdata.Tinv(3,1);
ty = t.tdata.Tinv(3,2);
translation = [tx ty];
scale = sqrt(ss*ss + sc*sc);
rotation = atan2(ss,sc)*180/pi;
%# plot the results
subplot(311), imshow(I1,map1), title('I1')
hold on, plot(p1(:,1),p1(:,2),'go')
subplot(312), imshow(I2,map1), title('I2')
hold on, plot(p2(:,1),p2(:,2),'go')
subplot(313), imshow(II2,map1)
title(sprintf('recovered angle = %g',rotation))
If you can identify a color corresponding to only one component it is easier to:
Calculate the centroids for each image
Calculate the mean of the centroids (in x and y) for each image. This is the "center" of each image
Get the red component color centroid (in your example) for each image
Subtract the mean of the centroids for each image from the red component color centroid for each image
Calculate the ArcTan2 for each of the vectors calculated in 4), and subtract the angles. That is your result.
If you have more than one figure of each color, you need to calculate all possible combinations for the rotation and then select the one that is compatible with the other possible rotations.
I could post the code in Mathematica, if you think it is useful.
I would take a variant to the above mentioned approach:
% Crude binarization method to knock out background and retain foreground
% features. Note one looses the cube in the middle
im = im > 1
Then I would get the 2D autocorrelation:
acf = normxcorr2(im, im);
From this result, one can easily detect the peaks, and as rotation carries into the autocorrelation function (ACF) domain, one can ascertain the rotation by matching the peaks between the original ACF and the ACF from the rotated image, for example using the so-called Hungarian algorithm.

Contour detection in MATLAB

I am trying to understand this code:
d=edge(d,'canny',.6);
figure,
imshow(d,[])
ds = bwareaopen(d,40);
figure,
imshow(ds,[])
iout = d1;
BW=ds;
iout(:,:,1) = iout;
iout(:,:,2) = iout(:,:,1);
iout(:,:,3) = iout(:,:,1);
iout(:,:,2) = min(iout(:,:,2) + BW, 1.0);
iout(:,:,3) = min(iout(:,:,3) + BW, 1.0);
I understand that d is the image and canny detector is applied and 40 pixels are neglected. The image is gray scale and contour is added to the image.
Can you please explain the next lines? What principle/algorithm is used here? I am having trouble especially with the contour detection portion of the code.
Assuming that the variable d1 stores what is likely a double precision representation (values between 0 and 1) of the original grayscale intensity image that is operated on, then the last 5 lines will turn that grayscale image into a 3-D RGB image iout that looks the same as the original grayscale image except that the contours will be overlaid on the image in cyan.
Here's an example, using the image 'cameraman.tif' that is included with the MATLAB Image Processing Toolbox:
d1 = double(imread('cameraman.tif'))./255; % Load the image, scale from 0 to 1
subplot(2, 2, 1); imshow(d1); title('d1'); % Plot the original image
d = edge(d1, 'canny', .6); % Perform Canny edge detection
subplot(2, 2, 2); imshow(d); title('d'); % Plot the edges
ds = bwareaopen(d, 40); % Remove small edge objects
subplot(2, 2, 3); imshow(ds); title('ds'); % Plot the remaining edges
iout = d1;
BW = ds;
iout(:, :, 1) = iout; % Initialize red color plane
iout(:, :, 2) = iout(:, :, 1); % Initialize green color plane
iout(:, :, 3) = iout(:, :, 1); % Initialize blue color plane
iout(:, :, 2) = min(iout(:, :, 2) + BW, 1.0); % Add edges to green color plane
iout(:, :, 3) = min(iout(:, :, 3) + BW, 1.0); % Add edges to blue color plane
subplot(2, 2, 4); imshow(iout); title('iout'); % Plot the resulting image
And here is the figure the above code creates:
How it works...
The creation of the image iout has nothing to do with the edge detection algorithm. It's simply an easy way to display the edges found in the previous steps. A 2-D grayscale intensity image can't display color, so if you want to add colored contour lines to the image you have to first convert it to a format that will let you show color: either an indexed image (which is a little harder to deal with, in my experience) or a 3-D RGB image (the third dimension represents the red, green, and blue color components of each pixel).
Replicating the grayscale image 3 times in the third dimension gives us a 3-D RGB image that initially still contains gray colors (equal amounts of red, green, and blue per pixel). However, by modifying certain pixels of each color plane we can add color to the image. By adding the logical edge mask BW (ones where edges are and zeroes elsewhere) to the green and blue color planes, those pixels where the contours were found will appear cyan. The call to the function min ensures that the result of adding the images never causes a pixel color value to exceed the value 1.0, which is the maximum value an element should have for a double-precision 3-D RGB image.
It should also be noted that the code for creating the 3-D RGB image can be simplified to the following:
iout = d1;
iout(:, :, 2) = min(d1+ds, 1.0);
iout(:, :, 3) = min(d1+ds, 1.0);