Image Fusion using stationary wavelet transform (SWT) (MATLAB) - image

I'm trying to fuse two images using SWT. But I'm getting this error :
The level of decomposition 1
and the size of the image (1,5)
are not compatible.
Suggested size: (2,6)
How to change the size of the image to make it compatible for transform?
Code I've used is :
clc
i=1;
fol=1;
n=0;
for fol=1:5
f='folder';
folder = strcat(f, num2str(fol));
cd(folder)
d= numel(D);
i=(n+1);
Fname1 = strcat(int2str(i),'.bmp');
Fname2 = strcat(int2str(i+1),'.bmp');
im1 = imread(Fname1);
im2 = imread(Fname2);
im1=double(im1);
im2=double(im2);
% image decomposition using discrete stationary wavelet transform
[A1L1,H1L1,V1L1,D1L1] = swt2(im1,1,'sym2');
[A2L1,H2L1,V2L1,D2L1] = swt2(im2,1,'sym2');
% fusion start
AfL1 = 0.5*(A1L1+A2L1);
D = (abs(H1L1)-abs(H2L1))>=0;
HfL1 = D.*H1L1 + (~D).*H2L1;
D = (abs(V1L1)-abs(V2L1))>=0;
VfL1 = D.*V1L1 + (~D).*V2L1;
D = (abs(D1L1)-abs(D2L1))>=0;
DfL1 = D.*D1L1 + (~D).*D2L1;
% fused image
imf = iswt2(AfL1,HfL1,VfL1,DfL1,'sym2');
figure;
imshow(imf,[]);
Iname= strcat(int2str(fol),'.bmp');
imwrite(imf,Iname);
end

To address your first problem, that image is really small. I'm assuming that's an image of size 1 x 5. I would suggest changing your image so that it's larger, or perhaps do an imresize on the image. However, as what Ander said in his comment to you... I wouldn't call a 1 x 5 matrix an image.
To address your second problem, once you finally load in an image, the wavelet transform will most likely give you floating point numbers that are beyond the dynamic range of any sensible floating point precision image. As such, it's good that you normalize the image first, then save it to file.
Therefore, do this right before you save the image:
%// ...
%// Your code...
imshow(imf,[]);
%// Normalize the image - Change
imf = (imf - min(imf(:))) / (max(imf(:)) - min(imf(:)));
%// Your code again
%// Now save
Iname= strcat(int2str(fol),'.bmp');
imwrite(imf,Iname);
The above transformation normalizes an image so that the minimum is 0 and the maximum is 1. Once you do that, it should be visualized properly. FWIW, doing imshow(imf,[]); does this normalization for you and displays that result, but it doesn't modify the image.

Related

Correct image size in image mosaic

I'm implementing image mosaic in Matlab using SURF.the problem is
outputView = imref2d(size(img1)*2);
Ir = imwarp(img2,tform,'OutputView',outputView);
it produces
i want it something like this
if i change
outputView = imref2d(size(img1)*2);
to
outputView = imref2d(size(img1));
matlab crops the second image so it can fit in first image size after transforming.
Notice that when you warp the image with respect to the target plane, many of the pixels in this new plane are equal to 0. A very rudimentary algorithm is to simply threshold your image so that you find values above 0 then find the largest bounding box that encompasses the non-zero pixels... then crop:
[rows,cols] = find(Ir(:,:,1) > 0);
topLeftRow = min(rows);
topLeftCol = min(cols);
bottomRightRow = max(rows);
bottomRightCol = max(cols);
Ir_crop = Ir(topLeftRow:bottomRightRow, topLeftCol:bottomRightCol, :);

Laplacian Image Filtering and Sharpening Images in MATLAB

I am trying to "translate" what's mentioned in Gonzalez and Woods (2nd Edition) about the Laplacian filter.
I've read in the image and created the filter. However, when I try to display the result (by subtraction, since the center element in -ve), I don't get the image as in the textbook.
I think the main reason is the "scaling". However, I'm not sure how exactly to do that. From what I understand, some online resources say that the scaling is just so that the values are between 0-255. From my code, I see that the values are already within that range.
I would really appreciate any pointers.
Below is the original image I used:
Below is my code, and the resultant sharpened image.
Thanks!
clc;
close all;
a = rgb2gray(imread('e:\moon.png'));
lap = [1 1 1; 1 -8 1; 1 1 1];
resp = uint8(filter2(lap, a, 'same'));
sharpened = imsubtract(a, resp);
figure;
subplot(1,3,1);imshow(a); title('Original image');
subplot(1,3,2);imshow(resp); title('Laplacian filtered image');
subplot(1,3,3);imshow(sharpened); title('Sharpened image');
I have a few tips for you:
This is just a little thing but filter2 performs correlation. You actually need to perform convolution, which rotates the kernel by 180 degrees before performing the weighted sum between neighbourhoods of pixels and the kernel. However because the kernel is symmetric, convolution and correlation perform the same thing in this case.
I would recommend you use imfilter to facilitate the filtering as you are using methods from the Image Processing Toolbox already. It's faster than filter2 or conv2 and takes advantage of the Intel Integrated Performance Primitives.
I highly recommend you do everything in double precision first, then convert back to uint8 when you're done. Use im2double to convert your image (most likely uint8) to double precision. When performing sharpening, this maintains precision and prematurely casting to uint8 then performing the subtraction will give you unintended side effects. uint8 will cap results that are negative or beyond 255 and this may also be a reason why you're not getting the right results. Therefore, convert the image to double, filter the image, sharpen the result by subtracting the image with the filtered result (via the Laplacian) and then convert back to uint8 by im2uint8.
You've also provided a link to the pipeline that you're trying to imitate: http://www.idlcoyote.com/ip_tips/sharpen.html
The differences between your code and the link are:
The kernel has a positive centre. Therefore the 1s are negative while the centre is +8 and you'll have to add the filtered result to the original image.
In the link, they normalize the filtered response so that the minimum is 0 and the maximum is 1.
Once you add the filtered response onto the original image, you also normalize this result so that the minimum is 0 and the maximum is 1.
You perform a linear contrast enhancement so that intensity 60 becomes the new minimum and intensity 200 becomes the new maximum. You can use imadjust to do this. The function takes in an image as well as two arrays - The first array is the input minimum and maximum intensity and the second array is where the minimum and maximum should map to. As such, I'd like to map the input intensity 60 to the output intensity 0 and the input intensity 200 to the output intensity 255. Make sure the intensities specified are between 0 and 1 though so you'll have to divide each quantity by 255 as stated in the documentation.
As such:
clc;
close all;
a = im2double(imread('moon.png')); %// Read in your image
lap = [-1 -1 -1; -1 8 -1; -1 -1 -1]; %// Change - Centre is now positive
resp = imfilter(a, lap, 'conv'); %// Change
%// Change - Normalize the response image
minR = min(resp(:));
maxR = max(resp(:));
resp = (resp - minR) / (maxR - minR);
%// Change - Adding to original image now
sharpened = a + resp;
%// Change - Normalize the sharpened result
minA = min(sharpened(:));
maxA = max(sharpened(:));
sharpened = (sharpened - minA) / (maxA - minA);
%// Change - Perform linear contrast enhancement
sharpened = imadjust(sharpened, [60/255 200/255], [0 1]);
figure;
subplot(1,3,1);imshow(a); title('Original image');
subplot(1,3,2);imshow(resp); title('Laplacian filtered image');
subplot(1,3,3);imshow(sharpened); title('Sharpened image');
I get this figure now... which seems to agree with the figures seen in the link:

Why does downsample appear as a gray image?

In the implementation of downsampling by a factor of 2 to the image, the downsampled image is gray. What should I do in order to add all of the color components to the downsampling implementation so that it will be a color image?
I = imread('lena.gif','gif');
[j k] = size(I)
x_new = j./2;
y_new = k./2;
x_scale = j./x_new;
y_scale = k./y_new;
M = zeros(x_new,y_new);
for count1 = 1:x_new
for count2 = 1:y_new
M(count1,count2) = I(count1.*x_scale,count2.*y_scale);
end
end
figure,imshow(I);
title('Original Image');
M = uint8(M);
figure,imshow(M);
title('Downsample');
GIF images are what are known as indexed images. This means that what you read in with imread are values that are indices to a colour map. Each index generates a unique colour for you, and that's how GIF images are stored. They choose from a predefined set of colours, and each pixel in the GIF image comes from one of the colours in the colour map.
You first need to convert the image into RGB, and you do that with ind2rgb. However, you need to read in the colour map first with the two-output version of imread. You also will want to convert the images to uint8 as good practice with im2uint8:
[X,map] = imread('lena.gif');
I = im2uint8(ind2rgb(X,map));
What you need to do next is what #NKN suggested. You must apply the algorithm to all channels.
As such, simply make an output matrix that has three channels, and apply the algorithm to each plane independently. If I can make a suggestion, when accessing pixels this way after you downsample, make sure you floor or round the image coordinates so you're not inadvertently specifying locations that aren't defined - things like (13.8, 25.5) for example. Image pixel locations are integer, so you need to make sure the coordinates are integer too.
[X,map] = imread('lena.gif');
I = im2uint8(ind2rgb(X,map));
j = size(I,1); %// Change
k = size(I,2);
x_new = j./2;
y_new = k./2;
x_scale = j./x_new;
y_scale = k./y_new;
M = zeros(x_new,y_new,size(I,3)); %// Change
for jj = 1 : size(I,3) %// Change
for count1 = 1:x_new
for count2 = 1:y_new
M(count1,count2,jj) = I(floor(count1.*x_scale),floor(count2.*y_scale),jj); %// Change
end
end
end
figure,imshow(I);
title('Original Image');
M = uint8(M);
figure,imshow(M);
title('Downsample');
To test this, I'm using the mandrill dataset that's part of MATLAB. It is an indexed image with an associated colour map. These are coincidentally stored in X and map respectfully:
load mandrill;
I = im2uint8(ind2rgb(X,map));
Running the modified code, I get these two figures:
When you read the original image it contains 3 layers, R-G-B (as suggested by #rayryeng:
[X,map] = imread('lena.gif');
I = ind2rgb(X,map);
size(I)
ans =
768 1024 3
You should perform the down-sampling process on all the layers:
The code you provided does not down-sample. A simple downsampling example is as follows:
imshow(I(1:2:end,1:2:end,:))

Resize an image with bilinear interpolation without imresize

I've found some methods to enlarge an image but there is no solution to shrink an image. I'm currently using the nearest neighbor method. How could I do this with bilinear interpolation without using the imresize function in MATLAB?
In your comments, you mentioned you wanted to resize an image using bilinear interpolation. Bear in mind that the bilinear interpolation algorithm is size independent. You can very well use the same algorithm for enlarging an image as well as shrinking an image. The right scale factors to sample the pixel locations are dependent on the output dimensions you specify. This doesn't change the core algorithm by the way.
Before I start with any code, I'm going to refer you to Richard Alan Peters' II digital image processing slides on interpolation, specifically slide #59. It has a great illustration as well as pseudocode on how to do bilinear interpolation that is MATLAB friendly. To be self-contained, I'm going to include his slide here so we can follow along and code it:
Please be advised that this only resamples the image. If you actually want to match MATLAB's output, you need to disable anti-aliasing.
MATLAB by default will perform anti-aliasing on the images to ensure the output looks visually pleasing. If you'd like to compare apples with apples, make sure you disable anti-aliasing when comparing between this implementation and MATLAB's imresize function.
Let's write a function that will do this for us. This function will take in an image (that is read in through imread) which can be either colour or grayscale, as well as an array of two elements - The image you want to resize and the output dimensions in a two-element array of the final resized image you want. The first element of this array will be the rows and the second element of this array will be the columns. We will simply go through this algorithm and calculate the output pixel colours / grayscale values using this pseudocode:
function [out] = bilinearInterpolation(im, out_dims)
%// Get some necessary variables first
in_rows = size(im,1);
in_cols = size(im,2);
out_rows = out_dims(1);
out_cols = out_dims(2);
%// Let S_R = R / R'
S_R = in_rows / out_rows;
%// Let S_C = C / C'
S_C = in_cols / out_cols;
%// Define grid of co-ordinates in our image
%// Generate (x,y) pairs for each point in our image
[cf, rf] = meshgrid(1 : out_cols, 1 : out_rows);
%// Let r_f = r'*S_R for r = 1,...,R'
%// Let c_f = c'*S_C for c = 1,...,C'
rf = rf * S_R;
cf = cf * S_C;
%// Let r = floor(rf) and c = floor(cf)
r = floor(rf);
c = floor(cf);
%// Any values out of range, cap
r(r < 1) = 1;
c(c < 1) = 1;
r(r > in_rows - 1) = in_rows - 1;
c(c > in_cols - 1) = in_cols - 1;
%// Let delta_R = rf - r and delta_C = cf - c
delta_R = rf - r;
delta_C = cf - c;
%// Final line of algorithm
%// Get column major indices for each point we wish
%// to access
in1_ind = sub2ind([in_rows, in_cols], r, c);
in2_ind = sub2ind([in_rows, in_cols], r+1,c);
in3_ind = sub2ind([in_rows, in_cols], r, c+1);
in4_ind = sub2ind([in_rows, in_cols], r+1, c+1);
%// Now interpolate
%// Go through each channel for the case of colour
%// Create output image that is the same class as input
out = zeros(out_rows, out_cols, size(im, 3));
out = cast(out, class(im));
for idx = 1 : size(im, 3)
chan = double(im(:,:,idx)); %// Get i'th channel
%// Interpolate the channel
tmp = chan(in1_ind).*(1 - delta_R).*(1 - delta_C) + ...
chan(in2_ind).*(delta_R).*(1 - delta_C) + ...
chan(in3_ind).*(1 - delta_R).*(delta_C) + ...
chan(in4_ind).*(delta_R).*(delta_C);
out(:,:,idx) = cast(tmp, class(im));
end
Take the above code, copy and paste it into a file called bilinearInterpolation.m and save it. Make sure you change your working directory where you've saved this file.
Except for sub2ind and perhaps meshgrid, everything seems to be in accordance with the algorithm. meshgrid is very easy to explain. All you're doing is specifying a 2D grid of (x,y) co-ordinates, where each location in your image has a pair of (x,y) or column and row co-ordinates. Creating a grid through meshgrid avoids any for loops as we will have generated all of the right pixel locations from the algorithm that we need before we continue.
How sub2ind works is that it takes in a row and column location in a 2D matrix (well... it can really be any amount of dimensions you want), and it outputs a single linear index. If you're not aware of how MATLAB indexes into matrices, there are two ways you can access an element in a matrix. You can use the row and column to get what you want, or you can use a column-major index. Take a look at this matrix example I have below:
A =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
If we want to access the number 9, we can do A(2,4) which is what most people tend to default to. There is another way to access the number 9 using a single number, which is A(11)... now how is that the case? MATLAB lays out the memory of its matrices in column-major format. This means that if you were to take this matrix and stack all of its columns together in a single array, it would look like this:
A =
1
6
11
2
7
12
3
8
13
4
9
14
5
10
15
Now, if you want to access element number 9, you would need to access the 11th element of this array. Going back to the interpolation bit, sub2ind is crucial if you want to vectorize accessing the elements in your image to do the interpolation without doing any for loops. As such, if you look at the last line of the pseudocode, we want to access elements at r, c, r+1 and c+1. Note that all of these are 2D arrays, where each element in each of the matching locations in all of these arrays tell us the four pixels we need to sample from in order to produce the final output pixel. The output of sub2ind will also be 2D arrays of the same size as the output image. The key here is that each element of the 2D arrays of r, c, r+1, and c+1 will give us the column-major indices into the image that we want to access, and by throwing this as input into the image for indexing, we will exactly get the pixel locations that we want.
There are some important subtleties I'd like to add when implementing the algorithm:
You need to make sure that any indices to access the image when interpolating outside of the image are either set to 1 or the number of rows or columns to ensure you don't go out of bounds. Actually, if you extend to the right or below the image, you need to set this to one below the maximum as the interpolation requires that you are accessing pixels to one over to the right or below. This will make sure that you're still within bounds.
You also need to make sure that the output image is cast to the same class as the input image.
I ran through a for loop to interpolate each channel on its own. You could do this intelligently using bsxfun, but I decided to use a for loop for simplicity, and so that you are able to follow along with the algorithm.
As an example to show this works, let's use the onion.png image that is part of MATLAB's system path. The original dimensions of this image are 135 x 198. Let's interpolate this image by making it larger, going to 270 x 396 which is twice the size of the original image:
im = imread('onion.png');
out = bilinearInterpolation(im, [270 396]);
figure;
imshow(im);
figure;
imshow(out);
The above code will interpolate the image by increasing each dimension by twice as much, then show a figure with the original image and another figure with the scaled up image. This is what I get for both:
Similarly, let's shrink the image down by half as much:
im = imread('onion.png');
out = bilinearInterpolation(im, [68 99]);
figure;
imshow(im);
figure;
imshow(out);
Note that half of 135 is 67.5 for the rows, but I rounded up to 68. This is what I get:
One thing I've noticed in practice is that upsampling with bilinear has decent performance in comparison to other schemes like bicubic... or even Lanczos. However, when you're shrinking an image, because you're removing detail, nearest neighbour is very much sufficient. I find bilinear or bicubic to be overkill. I'm not sure about what your application is, but play around with the different interpolation algorithms and see what you like out of the results. Bicubic is another story, and I'll leave that to you as an exercise. Those slides I referred you to does have material on bicubic interpolation if you're interested.
Good luck!

How to process a "Very Large image file" in MATLAB and find out the pixel with largest value

I have to process a very large image ( say 10 MB image file or even more).I have to remove artifacts and dead pixels in MATLAB
I have read about Block Processing of Large Images, but have no idea how to apply it to a 16 bit image.
I am referring to removal of pixels which have highest value into the average value of surrounding pixel .my code is not working on my image which is 80 MB of size
numIterations = 30;
avgPrecisionSize = 16; % smaller is better, but takes longer
% Read in the image grayscale:
originalImage = double(rgb2gray(imread('C:\Documents and Settings\admin\Desktop\TM\image5.tif')));
% get the bad pixels where = 0 and dilate to make sure they get everything:
badPixels = (originalImage == 0);
badPixels = imdilate(badPixels, ones(12));
%# Create a big gaussian and an averaging kernel to use:
G = fspecial('gaussian',[1 1]*100,50);
H = fspecial('average', [1,1]*avgPrecisionSize);
%# User a big filter to get started:
newImage = imfilter(originalImage,G,'same');
newImage(~badPixels) = originalImage(~badPixels);
% Now average to
for count = 1:numIterations
newImage = imfilter(newImage, H, 'same');
newImage(~badPixels) = originalImage(~badPixels);
end
%% Plot the results
figure(123);
clf;
% Display the mask:
subplot(1,2,1);
imagesc(badPixels);
axis image
title('Region Of the Bad Pixels');
% Display the result:
subplot(1,2,2);
imagesc(newImage);
axis image
set(gca,'clim', [0 255])
title('Infilled Image');
colormap gray
newImage2 = roifill(originalImage, badPixels);
figure(44);
clf;
imagesc(newImage2);
colormap gray
You are doing a few things which are obvious problems (but it might depend specifically on how far you can get into the code before you run out of memory)
1) You are immediately converting the whole image to double
2) You are identifying certain pixels which you want to replace, but passing the whole image to imfilter and then throwing away (presumably) most of the output:
newImage = imfilter(originalImage,G,'same'); % filter across the entire image
newImage(~badPixels) = originalImage(~badPixels); % replace all the good pixels!
Without converting to double, why not first check where the bad pixels are, do your processing on subregions of the appropriate size around those pixels (the subregions can be converted to double and back), and then reassemble the image at the end?
blockproc may work if you can write your filtering option as a function which takes in an image area and returns the correct area - you'll have to use the border_size option appropriately and make sure your function just returns the original image without bothering to do any filtering if it hits a block with no bad pixels in. You can even have it write out to file as well.

Resources