The Bilinear Interpolation Embedded Matlab Function Vs Bilinear Interpolation 'Re-Written or Coded' Function

129 次查看(过去 30 天)
Hello everyone!
I have a question. Can you please help me to understand why the embedded matlab function of the bilinear interpolation algorithm does not yield the result that looks EXACTLY the same as the result obtained when re-written/coded (manually) using the matlab platform ? Or can you share the source code of the embedded matlab function version of the bilinear interpolation algorithm ?
See the examples:
The coded matlab function:
function [out] = interpImg(im, ratio)
%// Get some necessary variables first
[in_rows, in_cols] = size(im);
out_rows = in_rows * ratio;
out_cols = in_cols * ratio;
% %// 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'
cf = cf / ratio;
rf = rf / ratio;
%// Let r = floor(rf) and c = floor(cf)
c = floor(cf);
r = floor(rf);
%// 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));
out = cast(out, 'like', 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,'like',im);
end
And, here's the demo version that include the embedded Matlab function:
close all
ratio = 3;
%%Input image arrays
red = [0.4 1 0; 0 1 1; 0.8 0.8 0.1 ];
green = [1 0.5 0; 0 0 1; 0.5 0.3 0.7];
blue = [0.0 0.0 0; 1.0 1.0 0.2; 1.0 0.4 1];
Colon RGB 120 images
x = cat(3, red, green, blue);
Bilinear function (in matlab)
y = imresize(x,ratio,'bilinear');
Bilinear function coded
for h = 1:3
s(:,:,h) = interpImg(x(:,:,h), ratio);
end
%%Output images
figure; image(x); title('INPUT image')
figure; image(y); title('BILINEAR image')
figure; image(s); title('BILINEAR-CODED image')
Here's outputs:
A. Input image
B. The Matlab (embedded) function:
C. The Matlab (coded or manually written) function:
%

采纳的回答

Gobert
Gobert 2016-8-17
The following script produces the result similar to the result produced by the Matlab embedded bilinear function:
function [Y] = trad_bil(I, ratio)
[h, w] = size(I);
H = (ratio * h);
W = (ratio * w);
Y = zeros(H,W);
hs = (h/H);
ws = (w/W);
for i=1:H
y = (hs * i) + (0.5 * (1 - 1/ratio));
for j=1:W
x = (ws * j) + (0.5 * (1 - 1/ratio));
%// Any values out of acceptable range
x(x < 1) = 1;
x(x > h - 0.001) = h - 0.001;
x1 = floor(x);
x2 = x1 + 1;
y(y < 1) = 1;
y(y > w - 0.001) = w - 0.001;
y1 = floor(y);
y2 = y1 + 1;
%// 4 Neighboring Pixels
NP1 = I(y1,x1);
NP2 = I(y1,x2);
NP3 = I(y2,x1);
NP4 = I(y2,x2);
%// 4 Pixels Weights
PW1 = (y2-y)*(x2-x);
PW2 = (y2-y)*(x-x1);
PW3 = (x2-x)*(y-y1);
PW4 = (y-y1)*(x-x1);
Y(i,j) = PW1 * NP1 + PW2 * NP2 + PW3 * NP3 + PW4 * NP4;
end
end
end
  2 个评论
Yiqing Zhou
Yiqing Zhou 2018-3-9
Hi John, I don't quite understand why did you use 0.5 in the following code? Can you explain more about it? .Thank you
for i=1:H y = (hs * i) + (0.5 * (1 - 1/ratio)); for j=1:W x = (ws * j) + (0.5 * (1 - 1/ratio));

请先登录,再进行评论。

更多回答(3 个)

Steve Eddins
Steve Eddins 2016-8-8
At least one significant difference between your code and imresize is that your code appears to use a different shift in the geometric transformation.
Compare your transformation:
%// Let r_f = r'*S_R for r = 1,...,R'
%// Let c_f = c'*S_C for c = 1,...,C'
cf = cf / ratio;
rf = rf / ratio;
to the one in imresize:
% Input-space coordinates. Calculate the inverse mapping such that 0.5
% in output space maps to 0.5 in input space, and 0.5+scale in output
% space maps to 1.5 in input space.
u = x/scale + 0.5 * (1 - 1/scale);
I did not closely examine other parts of your code.
  2 个评论
Gobert
Gobert 2016-8-10
Thanks, Steve Eddins , for clarification. However, I did not get similar results, even after using the geometric transformation of the imresize shift (pointed above) in the code I shared (and used to compare with your embedded function)! Can you please share a separate 2D bilinear interpolation script that produces the result similar to the result produced by the embedded function ?
Steve Eddins
Steve Eddins 2016-8-10
No, I'm sorry. I refer to you to the source code in imresize.m. It does contain a call to a MEX-file for the core computation, but the higher-level algorithm details are all exposed in imresize.m.

请先登录,再进行评论。


moahaimen talib
moahaimen talib 2018-5-13
can i get the psuedocode for this algorithm?

Elliot Smith
Elliot Smith 2022-11-17
This is partially an answer and partially another question on the subject. I am writing a bilinear interpolation function in matlab for some Uni coursework, so I am analysing this question.
As far as I can tell a 3x3 image scaled by 3 should actually produce a 7x7 image with an optional border (according to my lecturer), which is what seems to be happening in your figure B. The middle 7x7 pixels have been interpolated correctly in the matlab function. So to scale the image I would be doing (((1-w)* ratio) +1) and (((1-h)*ratio)+1) interpolating and then adding the border by just replicating the closest pixel. (Use the above mapping for 0.5 start: u = x/scale + 0.5 * (1 - 1/scale);)
In figure B the origianl pixels(from figure A) are on colum/row 2,5,8 whereas in your function there are on 2,6,9. The formula for bilinear interpolation states you should be adding 2 columns (for resize ratio = 3) in between each pixel except the last pixel.
So this is your code:
out_rows = in_rows * ratio;
out_cols = in_cols * ratio;
It should be:
out_rows = ((in_rows-1) * ratio) +1 (=7 in your case)
out_cols = ((in_cols-1) * ratio) +1 (=7 in your case)
This should perfectly replicate the centre 7x7 pixels from the matlab function if you use the correct 0.5 start mapping as well.
Then add the border after interpolating to create the 9X9 image.
Or edit your loop so it does not interpolate on the edge pixels (only the middle 7X7) and just repeats the closest pixel for the edge.
I will add my code here after I have done the coursework and it has been marked.
Please correct me if I am wrong about anything but I am fairly confident this is what is going on here.

类别

Help CenterFile Exchange 中查找有关 Graphics Object Programming 的更多信息

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by