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

210 visualizzazioni (ultimi 30 giorni)
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:
%

Risposta accettata

Gobert
Gobert il 17 Ago 2016
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 Commenti
Yiqing Zhou
Yiqing Zhou il 9 Mar 2018
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));
Gobert
Gobert il 13 Mag 2018
In output space maps to 0.5 in input space and '0.5+scale' in output. See below, Steve's answer/comment.

Accedi per commentare.

Più risposte (3)

Steve Eddins
Steve Eddins il 8 Ago 2016
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 Commenti
Gobert
Gobert il 10 Ago 2016
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 il 10 Ago 2016
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.

Accedi per commentare.


moahaimen talib
moahaimen talib il 13 Mag 2018
can i get the psuedocode for this algorithm?

Elliot Smith
Elliot Smith il 17 Nov 2022
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.

Community Treasure Hunt

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

Start Hunting!

Translated by