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);
Related
I need to transform my tilted image in a way I can find coins on an A4 paper. So far, I have been getting four coordinates of edges of my paper by manually selecting them with ginput.
targetImageData = imread('coin1.jpg');
imshow(targetImageData);
fprintf('Corner selection must be clockwise or anti-clockwise.\n');
[X,Y] = ginput(4);
Is there a way to automate this process, say, apply some edge detector and then find coordinates of each vertex and then pass them as the coordinates needed for transformation?
Manual selection:
Result:
You can try using detectHarrisFeatures on the S color channel of HSV color space:
I was looking for a color space that gets maximum contrast of the paper.
It looks like the saturation color channel of HSV makes a good contrast between the paper and the background.
Image is resized the image by a factor of 0.25, for removing noise.
detectHarrisFeatures finds the 4 corners of the paper, but it might not be robust enough.
You may need to find more features, and find the 4 correct features, using some logic.
Here is a code sample:
%Read input image
I = imread('im.png');
%Remove the margins, and replace them using padding (just because the image is a MATLAB figure)
I = padarray(I(11:end-10, 18:end-17, :), [10, 17], 'both', 'replicate');
HSV = rgb2hsv(I);
%H = HSV(:, :, 1);%figure;imshow(H);title('H');
S = HSV(:, :, 2);%figure;imshow(S);title('S');
%V = HSV(:, :, 3);%figure;imshow(V);title('V');
%Reduce image size by a factor of 0.25 in each axis
S = imresize(S, 0.25);
%S = imclose(S, ones(3)); %May be requiered
%Detect corners
corners = detectHarrisFeatures(S);
imshow(S); hold on;
plot(corners.selectStrongest(4));
Result:
Different approach you may try:
Take a photo without the coins.
Mark the corners manually, and extract features of the 4 corners.
Use image matching techniques to match the image with the coins with the image without the coins (mach basted on the 4 corners).
I am calling some images inside a for loop and then doing some processing on those images. After that, I am using the step function to display those frames and their masks inside a video player. How can I add a boundary to an object inside the mask image? Also, how can I make the boundary thicker and plot the centroids of each blob in the mask in the mask image? Below is the rough sketch of the code.
videoPlayer = vision.VideoPlayer();
maskPlayer = vision.VideoPlayer();
for ii = 1:nfiles
filenameii = [............]
frame= imread(filenameii);
mask = dOB(frame,BackgroundImg);
% some processing on the images
mask= bwareaopen(mask,27);
boundaries = bwboundaries(mask,'noholes');
B=boundaries{1};
Centroid = regionprops(mask,'centroid');
Centroids = cat(1, Centroid.Centroid);
plot(B(:,2),B(:,1),'g','LineWidth',3);
plot(Centroids(:,1), Centroids(:,2), 'r+', 'MarkerSize', 10); step(videoPlayer,frame);
step(maskPlayer, mask);
P.S: I know how to display it on a figure using hold on but I would like this done directly on the image before displaying it in the video player. Any guidance would be appreciated.
Simply paint the pixels on the mask first before displaying it in the video player. What you have does work, but it will plot the boundary inside the figure for the mask player. Therefore, take your boundaries that you detected from bwboundaries, create linear indices from these coordinates and set the values in your image to white. What may be even simpler is to take your mask that you detected and use bwperim to automatically produce a mask that contains the boundaries of the blobs. I also see that you are filling in the holes of the mask, so you can use imfill directly on the output of your post-processing so that it gives you an image instead of coordinates. You would then use this mask to directly index into your image and set the coordinates of the boundaries of the blob to your desired colour. If you desire to make the perimeter thicker, a simple image dilation with imdilate using the appropriately sized square structuring element will help. Simply define the size of the neighbourhood of this structuring element to be the thickness of the perimeter that you desire. Finally, if you want to insert the centroids into the mask and since you have the MATLAB Computer Vision System Toolbox, use the insertMarker function so that you can use a set of points for each centroid and put them directly in the image. However, you must be sure to change the mask from a logical to a data type more suitable for images. uint8 should work. Therefore, cast the image to this type then multiply all nonzero values by 255 to ensure the white colours are maintained in the mask. With insertMarker, you want to insert red pluses with a size of 10 so we need to make sure we call insertMarker to reflect that. Also, because you want to have a colour image you will have to make your mask artificially colour and to do this painting individually for each plane for the colour that you want. Since you want green, this corresponds to the RGB value of (0,255,0).
Therefore, I have modified your code so that it does this. In addition, I've calculated the centroids of the filled mask instead of the original. We wouldn't want to falsely report the centroids of objects with gaps... unless that's what you're aiming for, but let's assume you're not:
videoPlayer = vision.VideoPlayer();
maskPlayer = vision.VideoPlayer();
% New - Specify colour you want
clr = [0 255 0]; % Default is green
% New - Define thickness of the boundaries in pixels.
thickness = 3;
% New - Create structuring element
se = strel('square', thickness);
for ii = 1:nfiles
filenameii = [............]
frame = imread(filenameii);
mask = dOB(frame, BackgroundImg);
% some processing on the images
mask = bwareaopen(mask,27);
%boundaries = bwboundaries(mask,'noholes');
%B=boundaries{1};
% New code - fill in the holes
mask = imfill(mask, 'holes');
Centroid = regionprops(mask,'centroid');
% New code - Create a boundary mask
mask_p = bwperim(mask, 8);
% New code - Make the boundaries thicker
mask_p = imdilate(mask_p, se);
% New code - create a colour image out of the mask
[red, green, blue] = deal(255*uint8(mask));
% Paint the perimeter of the blobs in the desired colour
red(mask_p) = clr(1); green(mask_p) = clr(2); blue(mask_p) = clr(3);
Centroids = cat(1, Centroid.Centroid);
%plot(B(:,2),B(:,1),'g','LineWidth',3);
%plot(Centroids(:,1), Centroids(:,2), 'r+', 'MarkerSize', 10);
% New - Make mask into RGB image for marker painting and to
% show to the user
mask_p = cat(3, red, green, blue);
% New - Insert the centroids directly in the mask image
mask_p = insertMarker(mask_p, Centroids, '+', 'color', 'r', 'size', 10);
step(videoPlayer, frame);
% New - Show new mask in the player
step(maskPlayer, mask_p);
end
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..
Say I have an image. How can I colour some specific pixels in that image using MATLAB?
Thanks.
RGB Pixels
I'd suggest working with an RGB image, so that you can easily represent color and gray pixels. Here's an example of making two red blocks on an image:
img = imread('moon.tif');
imgRGB = repmat(img,[1 1 3]);
% get a mask of the pixels you want and set an RGB vector to those pixels...
colorMask = false(size(imgRGB,1),size(imgRGB,2));
colorMask(251:300,151:200,:) = true; % two discontiguous blocks
colorMask(50:100,50:100,:) = true;
redPix = permute([255 0 0],[1 3 2]);
imgRGB(repmat(colorMask,[1 1 3])) = repmat(redPix, numel(find(colorMask)),1);
AlphaData image property
Another cool way of doing this is with an image's AlphaData property. See this example on a MathWorks blog. This essentially turns color on or off in certain parts of the image by making the gray image covering the color image transparent. To work with a gray image, do like the following:
img = imread('moon.tif');
influenceImg = abs(randn(size(img)));
influenceImg = influenceImg / (2*max(influenceImg(:)));
imshow(img, 'InitialMag', 'fit'); hold on
green = cat(3, zeros(size(img)), ones(size(img)), zeros(size(img)));
h = imshow(green); hold off
set(h, 'AlphaData', influenceImg)
See the second example at the MathWorks link.
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);