Displaying a png image without the background - matlab

http://sweetclipart.com/multisite/sweetclipart/files/sunglasses_black.png
I have read the png image in MATLAB using [X,map,alpha]=imread('...','png').
Now I want to place this png image on another image. But I want the background color of the read png not to be shown. In the link I want the sunglasses alone to be shown without the 'white' background (Background is another image).

The alpha channel is opacity, the opposite of transparency.
MATLAB figures support alpha blending via the AlphaData property:
background = uint8(255*rand(size(alpha)));
imshow(background)
hold on
h = imshow(X);
set(h, 'AlphaData', alpha)
Result:
Given another image Y and your image X with it's alpha data, you can use alpha to generate a blended image. In you case, alpha has only the values 0 and 255, but in general there can be levels of opacity. In this simple case, again with noise background, but in color:
out = uint8(255*rand(size(X))); % Y
hardMask = repmat(alpha==255,1,1,3);
out(hardMask) = X(hardMask);
imwrite(out,'sunglass_alphaC.png')
It's a big image, so I resized the output here:
If your alpha channel actually had more than two levels of transparency, you could blend with the background:
s = double(alpha)/255;
Yout = uint8((bsxfun(#times,1-s,double(Y)) + bsxfun(#times,s,double(X))));
For grayscale, bsxfun can be replaced with just .- (e.g. s.*double(X)).

You can do it like this:
% Image with alpha channel
[glasses, ~, alpha] = imread('http://sweetclipart.com/multisite/sweetclipart/files/sunglasses_black.png');
% OPTIONAL: Let's rescale it (it's very big!)
glasses = imresize(glasses, 0.1);
alpha = imresize(alpha, 0.1);
% An image of a person (let's put the glasses on the person).
person = imread('http://cinemacao.com/wp-content/uploads/2013/12/Scarlett-CAPA-2.jpg');
% Lets make the alpha MxNx3 (so we can combine it with the RGB channels).
alpha = repmat(alpha, [1 1 3]);
% And convert everything from uint8 to double (to avoid precision issues).
glasses = im2double(glasses);
alpha = im2double(alpha);
person = im2double(person);
% Final image
% Let x,y be the top-left coordinates where we'll put the glasses.
x = 440;
y = 450;
% Let's combine the images.
img3 = person;
img3(y:y+size(glasses,1)-1, x:x+size(glasses,2)-1, :) = ...
glasses .* alpha + ...
person(y:y+size(glasses,1)-1, x:x+size(glasses,2)-1, :) .* (1 - alpha);
% An display the result.
imshow(img3);
Result:

I dont know much about Matlab, but seems to be that [X,map,alpha] use "alpha" as the alpha channel; alpha channel means level of transparency. (probably you already know this). Also check if the image itself has the alpha channel set. PNG doesn't recognise "white" as alpha channel by default. In this case, go to your favorite "*shop" software to edit the photo (maybe select with magic tool which will be the background, go to select inverse, copy-paste to a new image previously specifying that the background image will be transparency).

Related

How to "disturb" an image with noise, but keep the orginal undisturbed pixel intact, and write to file in imagesc

For simple explanation of the title, imagine you're using a Photoshop layers, where noise is on the top layer.
% load a test image
I = rgb2gray(imread('peppers.png'));
% recreate image
cmap = colormap(); % grab current colormap
ncolors = size(cmap,1);
% do what imagesc does
Iind = double(I) - double(min(I(:)));
Iind = Iind / max(Iind(:));
% quantize image
Iind = round(Iind * ncolors + 0.5);
Iind(Iind > ncolors) = ncolors;
Iind(Iind < 1) = 1;
% convert to RGB from indexed image using cmap as palette
Irgb = ind2rgb(Iind,cmap);
imwrite(Irgb, 'filename.bmp');
These code will scale the colormap and write to file. However, by adding a artificial noise at a certain pixel location after loaded the image:
I(50,50) = rand(1);
This will generate a completely different colormap visually, and the one with the noise will look a little washed out. Top image is the original and bottom is with noise.
EDIT: The below image is the cropped image on the top left corner. Left is original and right is with noise. On the right you can see the color washed out a little bit, and if you look closely you can see a noise (dark blue color, position (50,50)).
Any idea how to still maintain the original after noise was added? Thanks in advance!
The issue is that you're adding noise (between 0 and 1) to the original image which has min = 8 and max = 255. This is reducing the new min to either 0 or 1 (the input image is of type uint8, and it seems MATLAB rounds the random number) which stretches out the colourmap slightly. There are two options to avoid this.
Add random noise in the range of the original image
I(50,50) = randi([min(I(:)), max(I(:))]);
Add random noise after scaling the original image
Irgb(50,50) = rand(1);

Getting the coordinates of vertices of an A4 sheet with coins on it, for its further projective transformation and coin detection

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).

Finding dark purple pixels in an image

I am doing a research for my higher studies in automation. I have done the automation part of the microscope but I need help in MATLAB. An example of what I would like to segment is shown here:
I need to extract the dark purple pixels from this image and only display that in a figure. It is almost like colour based segmentation but I just want to only take the dark purple pixel from the whole image.
What would I do in this case?
Here's something to get you started. Let's go with the theme of colour segmentation where you only want to extract pixels that are of a deep purple. I would like to point you to the HSV colour space before we get started. The HSV colour space is ideal for representing colours in a way that is most intuitive to humans. We tend to describe colours by their dominant colour, followed by attributes such as how washed out or how pure the colour is, and how bright or dark the colour is. The dominant colour is represented by the Hue, the appearance of how washed out or how pure the colour is is represented by the Saturation and the intensity of the colour is represented by the Value, and hence Hue-Saturation-Value, or the HSV colour space.
We can transform a RGB image so that it becomes HSV by rgb2hsv. This will return a 3D matrix that has the hue, saturation and value as 2D slices in a 3D matrix, much like a RGB image where each slices represents the red, green and blue channels. Let's see what each component looks like once we transform the image into HSV:
im = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
hsv = rgb2hsv(im2double(im));
figure;
for idx = 1 : 3
subplot(1,3,idx);
imshow(hsv(:,:,idx));
end
The first line of code reads in an image from a URL. I'm going to use the one that Hoki referred you to, as it's the most simplest one to deal with. For self-containment, this is what the original image looks like:
Once we do this, we convert the image into the HSV colour space. It is important that you convert the image to double precision and you normalize each component to [0,1], and that is performed by im2double. Next, we spawn a new figure, and place each component in a single row over three columns. The first column represents the hue, next column the saturation and finally the last column being the value. This is the figure that we see:
With the first figure, it looks like the dominant colour is purple, whether it's a light shade or a dark shade of the colour, so the hue won't help us here. If you look at a HSV colour wheel:
(source: hobbitsandhobos.com)
Normalize the wheel so that it falls between [0,1] instead of 0 to 360 degrees. The hue is actually represented as degrees due to the nature of the colour space, but MATLAB normalizes this to [0,1]. You can see that purple falls within a hue of [0.6,0.8], which corresponds to the first figure I showed you that displays the hue for our image. If you examine the pixels around the image, they fluctuate between this range. Therefore, the hue won't help us much here.
What will certainly help us are the saturation and value components. If you take a look, the deep purple pixels have a higher saturation than the rest of the background, which makes sense because the deep purple has a much more pure version of purple than the rest of the background. For the value, you can see that the brightness of the dark purple is darker than the background.
We can use these two points as an exploit to segment out the purple colour in the image. The easiest thing to do would be to threshold the saturation and value planes so that any values that are within a certain range you keep while those that are outside you throw away. Therefore, you can do something like this:
sThresh = hsv(:,:,2) > 0.6 & hsv(:,:,2) < 0.9;
vThresh = hsv(:,:,3) > 0.4 & hsv(:,:,3) < 0.65;
I used impixelinfo and I hovered my mouse over the saturation and value components to examine what the values were for the deep purple regions. It looks like those pixels that are deep purple have a saturation value between 0.6 and 0.9, while the value component has values between 0.4 and 0.65. The above code will create two binary masks where true means that the pixel satisfies our criteria while false means it doesn't. Because I want to combine both things together and not leave any stone unturned, let's logical OR the masks together for the final result:
figure;
result = sThresh | vThresh;
imshow(result);
We will also show the result too. This is what we get:
As you can see, this does a pretty good job, but we have remnants of the red arrow that we don't want in the final result. To do a bit of cleanup, we can use morphology - specifically an opening filter of a small window so that we don't affect the pixels that we want as much. We can use imopen to perform our opening operation for us. A morphological opening removes isolated pixels that appear around your image. You use what is called a structuring element that is used to look at local neighbourhoods of your image. For the basics, any pixel regions that are as small as the shape that is contained within the structuring element get removed. Because we want to preserve the shape of the other objects, we can try using a 5 x 5 disk structuring element to clean these pixels up:
figure;
se = strel('disk', 2, 0);
final = imopen(result, se);
imshow(final);
This is what we get:
Not bad! There are some holes that we need to patch up, so let's fill in those holes with imfill:
figure;
final_noholes = imfill(final, 'holes');
imshow(final_noholes);
This is what we get:
OK! So we have our mask. The last thing we need to do is present the image so that you only show the deep purple colours from the original image, and nothing else. That can easily be achieved with bsxfun:
figure;
out = bsxfun(#times, im, uint8(final_noholes));
imshow(out);
The above operation takes your mask, and multiplies every pixel in your image by this mask. One small thing I'd like to point out is that the mask we found in the previous step needs to be cast to uint8, because bsxfun requires that the multiplication (or whatever operation you perform) need to be the same type. We replicate this mask in 3D so that you mask out the unwanted RGB pixels and only keep the ones you are looking for.
This is what we finally get:
As you can see, it isn't perfect, but it's certainly enough to get you started. Those thresholds are what are important, but with some very simple thresholding, I extracted most of the purple pixels out.
To make it easier for you, here's the code that I wrote above that can easily be copied and pasted into MATLAB for you to run:
clear all; close all; clc;
im = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
hsv = rgb2hsv(im2double(im));
figure;
for idx = 1 : 3
subplot(1,3,idx);
imshow(hsv(:,:,idx));
end
sThresh = hsv(:,:,2) > 0.6 & hsv(:,:,2) < 0.9;
vThresh = hsv(:,:,3) > 0.4 & hsv(:,:,3) < 0.65;
figure;
result = sThresh | vThresh;
imshow(result);
figure;
se = strel('disk', 2, 0);
final = imopen(result, se);
imshow(final);
figure;
final_noholes = imfill(final, 'holes');
imshow(final_noholes);
figure;
out = bsxfun(#times, im, uint8(final_noholes));
imshow(out);
Good luck!
Try this:
function main
clc,clear
A = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
subplot(1,2,1)
imshow(A)
RGB = [230 210 200]; % color you want
e = 40; % color shift
B = pix_in(A,RGB,e);
B = B + 255.*uint8(~B); % choosing white background
subplot(1,2,2)
imshow(B)
end
function B = pix_in(A,RGB,e)
% select specific pixels in image
% A - color image (3D matrix uint8)
% RGB - [R G B] - color to select
% e - color shift/deviation
A = double(A); % for same class operations (RGB - double)
[m, n, ~] = size(A);
RGB = reshape(RGB,1,1,3);
RGB = repmat(RGB,m,n,1); % creating 3D matrix
b = abs(A-RGB) < e; % logical 3D
b = sum(b,3) == 3; % if [R,G,B] of a pixel in range
B = A.*repmat(b,1,1,3); % selecting pixels those in range
B = uint8(B);
end

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..

Colouring specific pixels in an image

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.