Overlapping two images with transparency in MATLAB [duplicate] - matlab

Can someone help me in placing a logo (for example, the MATLAB logo) on an image?
First I read an image in using the imread command, and then on the top left corner, I need to add the MATLAB logo on that image. How would I do it?

Here's a reproducible example for you. #liangbright is on the right track, but I want to produce an example that works. Let's say I want to embed the MATLAB logo in the top left corner of a snapshot showing fictional federal agent, turned rogue: Jack Bauer. Here's an example MATLAB logo from the Wikimedia Commons media archive:
Source: Wikimedia Commons
Here's the picture of Jack Bauer I'm going to embed the MATLAB logo in:
Source: The Mirror
The MATLAB logo is quite large, so we're going to resize it so that it's a small icon. Let's resize this down to 10% of the original size. Once we do this, we simply have to replace those pixels that are in the top left corner with the MATLAB logo. Keep in mind that this MATLAB logo is in PNG format, which means that it will have a transparency / alpha channel. This is great because we will need the alpha channel so that we can place the MATLAB logo while making it look natural. That's the whole point of transparency. You can use imread as you have said, but we need to specify additional output parameters in order to grab the alpha channel. Specifically, we need the third parameter. The second parameter is the colour map, but let's ignore that as we don't need it for what you want to do. Now, the alpha channel is only a single 2D matrix, while the MATLAB logo and Jack Bauer are colour images. As such, we want to mix all of the colours together, and so we need to make the alpha channel a 3D matrix. This can be done by simply replicating the alpha map 3 times, and stacking it into a 3D matrix. We can do this by using repmat.
Once we have this, we can finally mix in the logo with the image. #liangbright has the equation right. If you want to mix two images together, given an alpha channel, you do it this way:
out = alpha*im1 + (1-alpha)*im2;
im1 is the image you want to mix in, while im2 is the image where im1 will be placed on top of this image. In our case, im1 is our MATLAB logo, while im2 is Jack Bauer. Before we can even do this, the alpha channel returned from imread actually (it's usually...) an unsigned 8-bit integer type image which has its alpha values span from [0-255]. As such, we need to transform the alpha map so that it spans between [0-1]. You can use im2double to do this for us.
Finally, we can use imresize to scale the image down so that it is 10% original size. We will also need to know the dimensions of this resized image so that we can properly put this into our bigger image.
One final note: We need to temporally convert the type of each image to double as the alpha maps are now double. We need to make sure that when you are multiplying two matrices together, they must be the same type. Once we finish mixing the stuff together, we then cast this part of the image back to uint8, as that is what the original type of bigger image was.
Without further ado, here's the code you should use. Note that I have saved the images to my computer before running this:
%// Load in MATLAB logo
[logo, map, alpha] = imread('Matlab_Logo.png');
%// Load in Jack Bauer
jack = imread('Kiefer-Sutherland-in-24.jpg');
%// Resize the MATLAB logo
logoResize = imresize(logo, 0.1, 'bilinear');
%// Make sure you do the same for the alpha map
alphaResize = imresize(alpha, 0.1, 'bilinear');
%// Duplicate the alpha map to make this three channels - This is a colour image
alphaResize = repmat(alphaResize, [1 1 3]);
%// Make double to ensure mixing
alphaResize = im2double(alphaResize);
%// Get the size of the resized logo - we need this
%// to properly mix the stuff in
rows = size(logoResize, 1);
cols = size(logoResize, 2);
%// Mix in the logo with the image
jack(1:rows,1:cols,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(1:rows,1:cols,:)));
figure;
imshow(jack);
This is the image I get:
Now, supposing you want to change the location of the logo so that it appears in either the top right, bottom left, or bottom right. As such, you simply need to change the last statement of the code before you show the final image. The last statement basically controls where you want the logo to go in the bigger image.
Specifically, you have to change the indexes of where we want to assign to the output. As such, let's do the other three cases where I'll show you each statement, and then the resulting image after.
Top Right
jack(1:rows,end-cols+1:end,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(1:rows,end-cols+1:end,:)));
Bottom Left
jack(end-rows+1:end,1:cols,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(end-rows+1:end,1:cols,:)));
Bottom Right
jack(end-rows+1:end,end-cols+1:end,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(end-rows+1:end,end-cols+1:end,:)));
Minor Note
The images that you may want to mix into your bigger image may not have an alpha channel. Examples of this are JPEG images. If you don't have access to the alpha channel, then you can do what #liangbright suggests and simply specify a constant for the alpha channel. As such, simply do the following. Most of the code that I showed above would disappear as there is no alpha channel. The code would thus simplify to:
%// Load in MATLAB logo without alpha channel
logo = imread('Matlab_Logo.png');
%// Load in Jack Bauer
jack = imread('Kiefer-Sutherland-in-24.jpg');
%// Resize the MATLAB logo
logoResize = imresize(logo, 0.1, 'bilinear');
%// Get the size of the resized logo - we need this
%// to properly mix the stuff in
rows = size(logoResize, 1);
cols = size(logoResize, 2);
%// Specify alpha here
alpha = 0.9;
%// Mix in the logo with the image
jack(1:rows,1:cols,:) = uint8(alpha.*double(logoResize) + ...
(1-alpha).*double(jack(1:rows,1:cols,:)));
figure;
imshow(jack);
... and this is the image I get:
Take note that putting in the MATLAB logo like this doesn't make the logo look like it's naturally there. This is because we assumed that all of the alpha values for the logo are the same, where the alphas should be zero except along the edges of the logo. Also, the actual logo pixels (not along the edges or the background) should have an alpha value of 1, as you want this to appear on top of the bigger image. With all of this, this roughly defines how the alpha channel should behave and thus make the transition between the logo and the bigger image more natural.
I've also decided not to show you what the logo looks like in the other corner positions with the simplified alpha, as the code is basically the same as the top left case. Just specify alpha to be a constant, then modify the last statement of your code before you show the image to be whichever case you want (top right, bottom left, bottom right).
Hope this helps!

I : the image
M : the logo
I(a:b, c:d) = (1-Alpha)*I(a:b, c:d)+ Alpha*M
(set Alpha = 0.9)
a:b c:d is related to the top left corner
then you show the image I
you can not just plot two images, one by one, because the second will cover the first

Related

Creating intensity band across image border using matlab

I have this image (8 bit, pseudo-colored, gray-scale):
And I want to create an intensity band of a specific measure around it's border.
I tried erosion and other mathematical operations, including filtering to achieve the desired band but the actual image intensity changes as soon as I use erosion to cut part of the border.
My code so far looks like:
clear all
clc
x=imread('8-BIT COPY OF EGFP001.tif');
imshow(x);
y = imerode(x,strel('disk',2));
y1=imerode(y,strel('disk',7));
z=y-y1;
figure
z(z<30)=0
imshow(z)
The main problem I am encountering using this is that it somewhat changes the intensity of the original images as follows:
So my question is, how do I create such a band across image border without changing any other attribute of the original image?
Going with what beaker was talking about and what you would like done, I would personally convert your image into binary where false represents the background and true represents the foreground. When you're done, you then erode this image using a good structuring element that preserves the roundness of the contours of your objects (disk in your example).
The output of this would be the interior of the large object that is in the image. What you can do is use this mask and set these locations in the image to black so that you can preserve the outer band. As such, try doing something like this:
%// Read in image (directly from StackOverflow) and pseudo-colour the image
[im,map] = imread('http://i.stack.imgur.com/OxFwB.png');
out = ind2rgb(im, map);
%// Threshold the grayscale version
im_b = im > 10;
%// Create structuring element that removes border
se = strel('disk',7);
%// Erode thresholded image to get final mask
erode_b = imerode(im_b, se);
%// Duplicate mask in 3D
mask_3D = cat(3, erode_b, erode_b, erode_b);
%// Find indices that are true and black out result
final = out;
final(mask_3D) = 0;
figure;
imshow(final);
Let's go through the code slowly. The first two lines take your PNG image, which contains a grayscale image and a colour map and we read both of these into MATLAB. Next, we use ind2rgb to convert the image into its pseudo-coloured version. Once we do this, we use the grayscale image and threshold the image so that we capture all of the object pixels. I threshold the image with a value of 10 to escape some quantization noise that is seen in the image. This binary image is what we will operate on to determine those pixels we want to set to 0 to get the outer border.
Next, we declare a structuring element that is a disk of a radius of 7, then erode the mask. Once I'm done, I duplicate this mask in 3D so that it has the same number of channels as the pseudo-coloured image, then use the locations of the mask to set the values that are internal to the object to 0. The result would be the original image, but having the outer contours of all of the objects remain.
The result I get is:

How to place a logo in an image using MATLAB

Can someone help me in placing a logo (for example, the MATLAB logo) on an image?
First I read an image in using the imread command, and then on the top left corner, I need to add the MATLAB logo on that image. How would I do it?
Here's a reproducible example for you. #liangbright is on the right track, but I want to produce an example that works. Let's say I want to embed the MATLAB logo in the top left corner of a snapshot showing fictional federal agent, turned rogue: Jack Bauer. Here's an example MATLAB logo from the Wikimedia Commons media archive:
Source: Wikimedia Commons
Here's the picture of Jack Bauer I'm going to embed the MATLAB logo in:
Source: The Mirror
The MATLAB logo is quite large, so we're going to resize it so that it's a small icon. Let's resize this down to 10% of the original size. Once we do this, we simply have to replace those pixels that are in the top left corner with the MATLAB logo. Keep in mind that this MATLAB logo is in PNG format, which means that it will have a transparency / alpha channel. This is great because we will need the alpha channel so that we can place the MATLAB logo while making it look natural. That's the whole point of transparency. You can use imread as you have said, but we need to specify additional output parameters in order to grab the alpha channel. Specifically, we need the third parameter. The second parameter is the colour map, but let's ignore that as we don't need it for what you want to do. Now, the alpha channel is only a single 2D matrix, while the MATLAB logo and Jack Bauer are colour images. As such, we want to mix all of the colours together, and so we need to make the alpha channel a 3D matrix. This can be done by simply replicating the alpha map 3 times, and stacking it into a 3D matrix. We can do this by using repmat.
Once we have this, we can finally mix in the logo with the image. #liangbright has the equation right. If you want to mix two images together, given an alpha channel, you do it this way:
out = alpha*im1 + (1-alpha)*im2;
im1 is the image you want to mix in, while im2 is the image where im1 will be placed on top of this image. In our case, im1 is our MATLAB logo, while im2 is Jack Bauer. Before we can even do this, the alpha channel returned from imread actually (it's usually...) an unsigned 8-bit integer type image which has its alpha values span from [0-255]. As such, we need to transform the alpha map so that it spans between [0-1]. You can use im2double to do this for us.
Finally, we can use imresize to scale the image down so that it is 10% original size. We will also need to know the dimensions of this resized image so that we can properly put this into our bigger image.
One final note: We need to temporally convert the type of each image to double as the alpha maps are now double. We need to make sure that when you are multiplying two matrices together, they must be the same type. Once we finish mixing the stuff together, we then cast this part of the image back to uint8, as that is what the original type of bigger image was.
Without further ado, here's the code you should use. Note that I have saved the images to my computer before running this:
%// Load in MATLAB logo
[logo, map, alpha] = imread('Matlab_Logo.png');
%// Load in Jack Bauer
jack = imread('Kiefer-Sutherland-in-24.jpg');
%// Resize the MATLAB logo
logoResize = imresize(logo, 0.1, 'bilinear');
%// Make sure you do the same for the alpha map
alphaResize = imresize(alpha, 0.1, 'bilinear');
%// Duplicate the alpha map to make this three channels - This is a colour image
alphaResize = repmat(alphaResize, [1 1 3]);
%// Make double to ensure mixing
alphaResize = im2double(alphaResize);
%// Get the size of the resized logo - we need this
%// to properly mix the stuff in
rows = size(logoResize, 1);
cols = size(logoResize, 2);
%// Mix in the logo with the image
jack(1:rows,1:cols,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(1:rows,1:cols,:)));
figure;
imshow(jack);
This is the image I get:
Now, supposing you want to change the location of the logo so that it appears in either the top right, bottom left, or bottom right. As such, you simply need to change the last statement of the code before you show the final image. The last statement basically controls where you want the logo to go in the bigger image.
Specifically, you have to change the indexes of where we want to assign to the output. As such, let's do the other three cases where I'll show you each statement, and then the resulting image after.
Top Right
jack(1:rows,end-cols+1:end,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(1:rows,end-cols+1:end,:)));
Bottom Left
jack(end-rows+1:end,1:cols,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(end-rows+1:end,1:cols,:)));
Bottom Right
jack(end-rows+1:end,end-cols+1:end,:) = uint8(alphaResize.*double(logoResize) + ...
(1-alphaResize).*double(jack(end-rows+1:end,end-cols+1:end,:)));
Minor Note
The images that you may want to mix into your bigger image may not have an alpha channel. Examples of this are JPEG images. If you don't have access to the alpha channel, then you can do what #liangbright suggests and simply specify a constant for the alpha channel. As such, simply do the following. Most of the code that I showed above would disappear as there is no alpha channel. The code would thus simplify to:
%// Load in MATLAB logo without alpha channel
logo = imread('Matlab_Logo.png');
%// Load in Jack Bauer
jack = imread('Kiefer-Sutherland-in-24.jpg');
%// Resize the MATLAB logo
logoResize = imresize(logo, 0.1, 'bilinear');
%// Get the size of the resized logo - we need this
%// to properly mix the stuff in
rows = size(logoResize, 1);
cols = size(logoResize, 2);
%// Specify alpha here
alpha = 0.9;
%// Mix in the logo with the image
jack(1:rows,1:cols,:) = uint8(alpha.*double(logoResize) + ...
(1-alpha).*double(jack(1:rows,1:cols,:)));
figure;
imshow(jack);
... and this is the image I get:
Take note that putting in the MATLAB logo like this doesn't make the logo look like it's naturally there. This is because we assumed that all of the alpha values for the logo are the same, where the alphas should be zero except along the edges of the logo. Also, the actual logo pixels (not along the edges or the background) should have an alpha value of 1, as you want this to appear on top of the bigger image. With all of this, this roughly defines how the alpha channel should behave and thus make the transition between the logo and the bigger image more natural.
I've also decided not to show you what the logo looks like in the other corner positions with the simplified alpha, as the code is basically the same as the top left case. Just specify alpha to be a constant, then modify the last statement of your code before you show the image to be whichever case you want (top right, bottom left, bottom right).
Hope this helps!
I : the image
M : the logo
I(a:b, c:d) = (1-Alpha)*I(a:b, c:d)+ Alpha*M
(set Alpha = 0.9)
a:b c:d is related to the top left corner
then you show the image I
you can not just plot two images, one by one, because the second will cover the first

Boundary around an object

I want to make a boundary around an object and the object is within a grayscale image.
The approach that I want to perform is to subtract the region inside the boundary from the background.
This was the code I used:
s=imread('C:\Users\Deepinder\Desktop\dd.jpg');
t=im2bw(s);
se=strel('disk',2);
f1=imerode(t,se);
CC=f1-t;
imshow(CC)
However, I am getting a completely black image as a result. What am I doing wrong?
I've come up with one solution, but I don't believe it is as accurate as you want, but it's something to start off with.
The image you are dealing with is actually quite complicated. This is the image that you have shown me:
What you would like to do is extract only the pixels that concern the face while making the background pixels black.
What we originally wanted to do was convert the image to black and white, then do an erosion and subtract this result with the original. This would work ONLY if the object had an overall brighter intensity than the background.
If you tried to do a straight up im2bw(), this would convert the image to grayscale first for colour images, then assume a threshold of 128. Anything larger than 128 would be white, while anything smaller is 0. This is the image that we would get followed by the accompanied code:
im = imread('dd.jpg');
imshow(im2bw(im));
As you can see, the background is also classified as white, and so our first approach won't work. What I did was decompose the image into separate channels (red, green and blue). This is what I get and here's the code to show it:
titles = {'Red', 'Green', 'Blue'};
for i = 1 : 3
subplot(1,3,i);
imshow(im(:,:,i));
title(titles{i});
end
If you take a look at the red and green channels, the red channel is very noisy and so we'll leave that alone. The green channel has the background being very similar to the face, and so we'll leave that one too. The best one we can use is the blue channel as there is a relatively good separation between the face intensity profile and the background.
By using impixelinfo and moving around the blue channel image, I saw that intensity profiles of the face varied roughly between 120 to 200. As such, let's create a binary mask that does such:
im = imread('dd.jpg');
faceGray = im(:,:,3);
faceBW = faceGray > 120 & faceGray < 200;
This is the output I get:
We're almost there. I want to get rid of the outline of the hair. What I did was an opening filter with a disk structuring element of radius 3. This should thin out any small objects while keeping the bigger predominant objects.
se = strel('disk', 2);
faceOpened = imopen(faceBW, se);
This is what I get:
Now let's go ahead and fill in the holes. imfill won't work because it only fills in regions that are closed. As such, I'm going to cheat a bit and do a closing filter with a larger size disk. I chose a radius of 30 this time.
se2 = strel('disk', 30);
faceClosed = imclose(faceOpened, se2);
This is what I get:
Now the final step is to use this mask and mask out all of the background pixels:
mask = repmat(faceClosed, [1 1 3]);
out = uint8(zeros(size(im)));
out(mask) = im(mask);
... and this is what I get:
This is by no means perfect, but it gives you something to work with. Also, the intensity profile around the neck is very similar to the face and so doing it my way can't avoid extracting the neck. What I would suggest you do is crop out the image so that you mostly see the face, then try and do some morphology or even edge detection to help you out in a similar fashion to what I did. Hope this helps!
I would recommend to convert your image to HSV space with rgb2hsv function. Then you can use the first hue layer to make a mask.
im = imread(filename);
im2 = rgb2hsv(im);
mask = im2(:,:,1)>0.4 & im2(:,:,1)<0.6;
im3 = im;
im3(repmat(mask,[1 1 3])) = 255;
imshow(im3)
You can play more with this mask to fill a few gaps. I don't have the toolbox to test it throughly.

How to remove the thick border produced when applying ADAPTIVETHRESH - Wellner's adaptive thresholding

With reference to the mentioned links below:-
Image1:
Image2:
Image 2 is obtained after the application of adapthisteq followed by Wellner's adapive threshold
Can somebody help me in removing that thick border please, because when processing the image, the coordinates for the image border is also being extracted. I have tried the imclearborder but those veins touching the border is also getting removed.
Also, I am having the impression that the vein patterns in image 2 has increased in size when compared to image 1.
Thank You.
The images you provided aren't the same size. But the below code is the general idea:
Code:
hand = imread('hand.png'); % this the hand
hand = hand(1:235,1:309);
thresh = imread('thresh.png'); % this is the "veined" image with the large border
thresh = thresh(:,:,1);
thresh(hand < 100) = 256;
figure, imshow(thresh)
Output:
Basically, just do a simple threshold on the fist. Select these points through logical indexing. Then, set the value of these indices in the "veined" picture to the white value (either 1 or 256 depending if it's logical or not).
Also, the slight black bordered region to the right will go away if the images you provide are the same size and aligned. I'd also recommend using imdilate with imerode to get rid of the small bits.

MATLAB. Inverse crop images.

I would like to crop an image but I want to retain the part of image that is outside of the rectangle. How can this can be done?
It seems that with imcrop only the part within the rectangle can be retained.
An image in Matlab is represented by a matrix, just like any other matrix, you can read more about representation forms here.
It seems that what you want to do is to take the area that you don't want and change the values of the corresponding cells in the matrix to the color that you want to put instead (each cell in the matrix is a pixel in the image). That is if you know the place where your unwanted data is.
If you don't know where it is, and want to use the tool given by imcrop to manually choose the "cropped" area, you can take the resulting matrix, and find the part of the original image which is an exact match with the cropped part, and to color it as you wish.
The code for doing this:
I=imread('img_9.tif');
I2=imcrop(I,[60,50,85,85]);
n_big=size(I);
n_small=size(I2);
for j1=1:(n_big(1)-n_small(1))
for j2=1:(n_big(2)-n_small(2))
Itest=I(j1:j1+n_small(1)-1,j2:j2+n_small(2)-1,:);
if ( Itest == I2)
I(j1:j1+n_small(1)-1,j2:j2+n_small(2)-1,:) = zeros(n_small(1),n_small(2),3);
end
end
end
figure(1);
imshow(I);
figure(2);
imshow(I2);
The results of my test were:
original:
cropped:
resulting image:
maybe what you want to do is first a mask with the inverse area of what you want to crop and save this result.