MATLAB: Combine Two Grayscale Images With Different Alpha - matlab

I started writing a program in MATLAB to overlay two grayscale images of same size with different alpha dynamically. Therefore both images are plotted in one figure and beneath them is a slider with which the alpha of the second image can be increased from zero to one. So when moving the slider one can actually sees the two images blending. Suppose the slider is at 0.3 then the 'AlphaData' of the second image is set to 0.3, while the 'AlphaData' of the first image is always 1. On the screen I now see an image, which is a combination of these two images.
Now I want to get exactly this image from the figure (with the same size, as the images before) and work with it. But I have no idea how to do it.

Grayscale image is just array of numbers. Depending on how you get the data it could be 0~1 or 1~255. Overlaying two images is merely adding the numbers. Blending two images is merely computing their weighted sum.
clear;clc;close all
I1_rgb = imread('peppers.png');
I1_gray = rgb2gray(I1_rgb);
figure(1)
imshow(I1_gray)
I2_gray = imread('coins.png');
I2_gray = padarray(I2_gray, size(I1_gray)-size(I2_gray), ...
'circular', 'post');
figure(2)
imshow(I2_gray)
alpha = .3; % this can be dynamically adjusted by a slider
O1 = I1_gray + I2_gray*alpha; % overlay
figure(3)
imshow(O1)
O2 = I1_gray*(1-alpha) + I2_gray*alpha; % blend
figure(4)
imshow(O2)
For mixing colored images, see my answer at MATLAB: Applying transparent mask over an RGB image and blending with another

Related

How to create an inverse gray scale?

I have an image with dark blue spots on a black background. I want to convert this to inverse gray scale. By inverse, I mean, I want the black ground to be white.
When I convert it to gray scale, it makes everything look black and it makes it very hard to differentiate.
Is there a way to do an inverse gray scale where the black background takes the lighter shades?
Or, another preferable option is to represent the blue as white and the black as black.
I am using img = rgb2gray(img); in MATLAB for now.
From mathworks site:
IM2 = imcomplement(IM)
Is there a way to do an inverse gray scale where the black
background takes the lighter shades?
Based on your image description I created an image sample.png:
img1 = imread('sample.png'); % Read rgb image from graphics file.
imshow(img1); % Display image.
Then, I used the imcomplement function to obtain the complement of the original image (as suggested in this answer).
img2 = imcomplement(img1); % Complement image.
imshow(img2); % Display image.
This is the result:
Or, another preferable option is to represent the blue as white and
the black as black.
In this case, the simplest option is to work with the blue channel. Now, depending on your needs, there are two approaches you can use:
Approach 1: Convert the blue channel to a binary image (B&W)
This comment suggests using the logical operation img(:,:,3) > 0, which will return a binary array of the blue channel, where every non-zero valued pixel will be mapped to 1 (white), and the rest of pixels will have a value of 0 (black).
While this approach is simple and valid, binary images have the big disadvantage of loosing intensity information. This can alter the perceptual properties of your image. Have a look at the code:
img3 = img1(:, :, 3) > 0; % Convert blue channel to binary image.
imshow(img3); % Display image.
This is the result:
Notice that the round shaped spots in the original image have become octagon shaped in the binary image, due to the loss of intensity information.
Approach 2: Convert the blue channel to grayscale image
A better approach is to use a grayscale image, because the intensity information is preserved.
The imshow function offers the imshow(I,[low high]) overload, which adjusts the color axis scaling of the grayscale image through the DisplayRange parameter.
One very cool feature of this overload, is that we can let imshow do the work for us.
From the documentation:
If you specify an empty matrix ([]), imshow uses [min(I(:)) max(I(:))]. In other words, use the minimum value in I as black, and the maximum value as white.
Have a look at the code:
img4 = img1(:, :, 3); % Extract blue channel.
imshow(img4, []); % Display image.
This is the result:
Notice that the round shape of the spots is preserved exactly as in the original image.

Overlapping two images with transparency in MATLAB [duplicate]

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

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

Matlab: imgradient returns quantized images

In Matlab, I want to display the gradient magnitude and direction of a grayscale image. Here is the code I am trying:
image = imread('gray_image.bmp');
[gmag, gdir] = imgradient(image);
figure, imshow(image);
figure, imshow(gmag);
figure, imshow(gdir);
However, gmag and gdir seem to be quantized to just two values: black and white. Every pixel in gmag and gdir is either black, or white. My image itself has a range of gradient magnitudes and directions. Why are these not showing up in the gmag and gdir images? Yes, I would expect gmag to have pure black for pixels with zero gradient, and pure white for pixels with maximum gradient, but I would also expect a range of gray values for gradients between those. Similarly, I would expect a range of gray values in gdir representing the range of angles.
For example, here is the grayscale image:
Here is gmag:
And here is gdir:
Why are gmag and gdir only displaying black or white, with no intermediate gray values?
Two issues
'gmag' and 'gdir' calculated with IMGRADIENT have double datatype.
Thus, if you want to display them as such, MATLAB would treat them as
intensity images and would expect them to be in the range [0 1].
Thus, we need to normalize ‘gmag’ and ‘gdir’, which is shown in the
code later on.
If you wish to save these images, MATLAB expects UINT8 datatype and
the values must lie in the range [0 255].Thus, before saving you need
to multiply it by 255 and then convert to UINT8.
Code
image = imread('gray_image.bmp');
[gmag, gdir] = imgradient(image);
%%// Normalize gmag and gdir
gmag = (gmag-min(gmag(:)))./(max(gmag(:))-min(gmag(:)));
gdir = (gdir-min(gdir(:)))./(max(gdir(:))-min(gdir(:)));
%%// Display images
figure, imshow(image);
figure, imshow(gmag);
figure, imshow(gdir);
%%// Save gradient images
imwrite(uint8(255.*gmag),'Lena_gmag.bmp');
imwrite(uint8(255.*gdir),'Lena_gdir.bmp');
Ouput images
GMAG -
GDIR -
As a test, one can notice the bar-like structure right behind Lena in the GDIR image now, which wasn't visible before.