Introduction:
Through this LAB, I have known the principle and formula of nearest neighbor interpolation and bilinear interpolation, and Use nearest neighbor interpolation and bilinear interpolation to interpolate a grey scale image. At the same time, I find some aspects that can be optimized in these two methods.
Lab results & Analysis:
Figure 1 the area of pixels
Let i + u, j + v (i, j is a positive integer, u, v is a decimal greater than zero and less than 1) be the pixel coordinate we want to get, then the greyscale we want to know is f (i + u, j + v).
If (i + u, j + v) falls in area A, that is u<0.5 and v<0.5, the greyscale of the upper-left pixel will be assigned to the pixel we want to get. Similarly, if it falls in area B, the greyscale of the upper-right pixel will be assigned; if it falls in area C, the greyscale of the lower-left pixel will be assigned; if it falls in area D, the greyscale of the lower-right pixel will be assigned.
This algorithm is simple and easy to understand and program, so that I will not write the pseudo code for this algorithm. I will give detailed comments in the program.
clear;
close all;
clc;
img = imread('rice.tif');
[ input_img,new_img ] = Nearest_11711118(img,[.8,.8]);
show(img,new_img);
function show(img,new_img)%print the figure
[height,width] = size(img);
figure;imshow(img);
axis on
title(['Input Figure with Size(',num2str(height),'*',num2str(width),'):']);
[new_height,new_width,] =size(new_img);
figure;imshow(new_img);
axis on
title(['Output Figure with Size( ',num2str(new_height),'*',num2str(new_width),'):']);
end
function[ input_img,new_img ]= Nearest_11711118(input_img, dim)
input_img=double(input_img);
swh=size(input_img); %Get the width and height of the original image
inputWidth=swh(:,2); %Get the width of the original image
inputHigh=swh(:,1); %Get the height of the original image
r=dim(:,1);
c=dim(:,2);
outputHigh=ceil(inputHigh * c);
outputWidth=ceil(inputWidth * r);
new_img=zeros(outputHigh,outputWidth);
orignalx = [1:outputHigh];
orignaly = [1:outputWidth];
for i=1:outputHigh
orignalx(i)=round(i/r);
end
for j=1:outputWidth
orignaly(j)=round(j/c);
end
for i=1:outputHigh
for j=1:outputWidth
if(orignalx(i) < 1) %If the coordinates cross the border, make adjustments
orignalx(i) = 1;
end
if(orignalx(i) > inputHigh)
orignalx(i) = swh;
end
if(orignaly(j) < 1)
orignaly(j) = 1;
end
if(orignaly(j) > inputWidth)
orignaly(j) = inputWidth;
end
new_img(i,j)=input_img(orignalx(i),orignaly(j)); %The Grayscale of the position of the scaled image coordinate at the original image is assigned to the scaled image
end
end
new_img=uint8(new_img);
end
Figure 2 shrinked figure
Figure 3 enlarged figure
The Advantages and disadvantages of nearest neighbor interpolation:
Then we take a closer look at our pictures to verify the Analysis:
Figure 4 closer look of shrink figure
Figure 5 : the closer look of the enlarged figure
We can see it clearly the details in enlarge image is very jagged and details in shrink image is very distorted. The root of the result is bad is the nearest neighbor interpolation caused serious image distortion, for example, when the target figure's push to get the coordinates of the source map is the coordinates of a floating number, the rounding method was adopted, directly using the floating-point number and the nearest pixel value, this method is not scientific, when pushed to coordinate values of 0.75, should not take 1 is simple, the number is 0.25 smaller than 1. It is 0.75 larger than 0.
The target pixel value should be calculated according to the real points around the virtual point in the source graph, so as to achieve a better scaling effect.
I think of two optimization aspects:
The optimized codes are(in order to save the space, I only show the function part):
function put_img = Nearest_11711118(input_img, dim)
ima=imread(input_img);
imshow(ima);
title('In put Figure');
ima=double(ima);
swh=size(ima); %Get the width and height of the original image
inputWidth=swh(:,2); %Get the width of the original image
inputHigh=swh(:,1); %Get the height of the original image
r=dim(:,1);
c=dim(:,2);
outputHigh=ceil(inputHigh * c);
outputWidth=ceil(inputWidth * r);
resIma=zeros(outputHigh,outputWidth);
orignalx = [1:outputHigh];
orignaly = [1:outputWidth];
for i=1:outputHigh
orignalx(i)=round(i/r);
end
for j=1:outputWidth
orignaly(j)=round(j/c);
end
for i=1:outputHigh
for j=1:outputWidth
if(orignalx(i) < 1) %If the coordinates cross the border, make adjustments
orignalx(i) = 1;
end
if(orignalx(i) > inputHigh)
orignalx(i) = swh;
end
if(orignaly(j) < 1)
orignaly(j) = 1;
end
if(orignaly(j) > inputWidth)
orignaly(j) = inputWidth;
end
resIma(i,j)=ima(orignalx(i),orignaly(j)); %The Grayscale of the position of the scaled image coordinate at the original image is assigned to the scaled image
end
end
resIma=uint8(resIma);
figure;
imshow(resIma);
title('The Output Figure');
end
Figure 6 example of bilinear interpolation
The key idea is to perform linear interpolation first in one direction, and then again in the other direction.
If we want to know the value of the unknown function f at the point P = (x, y), let's say we know the value of the function f at the points Q11 = (x1, y1), Q12 = (x1, y2), Q21 = (x2, y1), and Q22 = (x2, y2).
First, perform linear interpolation in the x direction, and get:
And then we do linear interpolation in the y direction, and we can get:
So that, the value of
Pseudo code of the algorithm:
Input: original image :img, scaling factor:dim
Output: output image,
f (x, y) = (1 - u) * (1 - v) * f (I, j) + (1 - u) * v * f (I, j + 1) + u * (1 - v) * f (I + 1, j) + u * v * f (I + 1, j + 1);.
clear;
close all;
clc;
img = imread('rice.tif');
[ori,img_new] = Bilinear_11711118(img,[0.8,0.8]);
show(ori,img_new);
function show(original,new_img)
[height,width] = size(original);
figure;imshow(original);
axis on
title(['Input Figure with Size(',num2str(height),'*',num2str(width),'):']);
[new_height,new_width,] =size(new_img);
figure;imshow(new_img);
axis on
title(['Output Figure with Size( ',num2str(new_height),'*',num2str(new_width),'):']);
end
function [ original,new_img ] = Bilinear_11711118( original,dim )
[height,width] = size(original);
new_height = round(height*dim(:,1)); % Calculate the height of the scaled image
new_width = round(width*dim(:,2)); % %calculates the width of the scaled image
new_img = zeros(new_height,new_width);
%%Extend the size of matrix
img_scale = zeros(height+2,width+2);
img_scale(2:height+1,2:width+1,:) = original;
%%assigns values to the extended edges
img_scale(1,2:width+1,:) = original(1,:,:);
img_scale(height+2,2:width+1,:) = original(height,:,:);
img_scale(2:height+1,1,:) = original(:,1,:);
img_scale(2:height+1,width+2,:) = original(:,width,:);
%%assign values to the extended four vertices
img_scale(1,1,:) = original(1,1,:);
img_scale(1,width+2,:) = original(1,width,:);
img_scale(height+2,1,:) = original(height,1,:);
img_scale(height+2,width+2,:) = original(height,width,:);
for zj = 1:new_width
for zi = 1:new_height
% (zi,zj) represents the coordinates in the new diagram
% ( ii,jj) represents the coordinates in the original diagram
ii = (zi-1)/dim(:,1); jj = (zj-1)/dim(:,2);
i = floor(ii); j = floor(jj);
u = ii - i; v = jj - j;
i = i + 1; j = j + 1;
new_img(zi,zj,:) = (1-u)*(1-v)*img_scale(i,j,:) + u*(1-v)*img_scale(i,j+1,:)...
+ (1-u)*v*img_scale(i+1,j,:) + u*v*img_scale(i+1,j+1,:);
end
end
new_img = uint8(new_img);
end
Figure 7 shrinked figure
Figure 8 enlarged figure
The image quality of the bilinear interpolation algorithm is high. The greyscale is continuous. However, this algorithm has the property of low-pass filter, which damages the high-frequency components, so the image contour may be blurred to some extent.
Then we take a closer look at our pictures to verify the Analysis:
and we can see that the figure contour is blurred to some extent.
Figure 9 closer look of enlarged figure
I think of two optimization aspects:
SrcX = dstX * (srcWidth/dstWidth),
SrcY = dstY * (srcHeight/dstHeight)
Center alignment:
SrcX = (dstX + 0.5) * (srcWidth/dstWidth) to 0.5
SrcY = (dstY + 0.5) * (srcHeight/dstHeight) to 0.5
SrcX =dstX* (srcWidth/dstWidth)+0.5*(srcWidth/dstWidth-1)
This is equivalent to adding 0.5*(srcWidth/dstWidth-1) to the original floating point coordinates. The symbol can be positive or negative, depending on the ratio of srcWidth/dstWidth. Let's take an example: suppose the source image is 3*3, the center point coordinate (1,1) and the target image is 9*9, and the center point coordinate (4,4). When we do the interpolation, we want to use the pixel information of the source image as evenly as possible. The most intuitive is that (4,4) maps to (1,1). That is srcX=4*3/9=1.3333!=1, the pixels we used in the interpolation are concentrated in the lower right of the image, rather than evenly distributed throughout the image. Now consider center alignment, srcX=(4+0.5)*3/9-0.5=1, which just meets our requirements.