Bilinear interpolation algorithm and python implementation

Bilinear interpolation algorithm [The main content of the article is reprinted, and the code is written by myself], here are also thanks to some big blog posts.

http://www.cnblogs.com/linkr/p/3630902.html

http://www.cnblogs.com/funny-world/p/3162003.html

bilinear interpolation

      Suppose the source image is of size mxn and the destination image is axb. Then the side length ratios of the two images are: m/a and n/b. Note that usually this ratio is not an integer, and a floating-point type should be used when programming and storing. The (i, j)th pixel (i row j column) of the target image can be mapped back to the source image through the side length ratio. Its corresponding coordinates are (i*m/a, j*n/b). Obviously, the corresponding coordinates are generally not integers, and non-integer coordinates cannot be used on discrete data such as images. Bilinear interpolation calculates the value (gray value or RGB value) of the point by finding the four closest pixel points to the corresponding coordinate.

  If the image is a grayscale image, then the mathematical calculation model of the grayscale value of point (i, j) is:

f(x,y)=b1+b2x+b3y+b4xy

Where b1, b2, b3, b4 are related coefficients. The calculation process about it is as follows:

      As shown in the figure, Q12, Q22, Q11, and Q21 are known, but the point to be interpolated is point P, which requires bilinear interpolation. First, interpolate the two points R1 and R2 in the direction of the x-axis. Very simple, and then interpolate point P according to R1 and R2, which is called bilinear interpolation.

clip_image001

 

Attached: Wikipedia – Bilinear interpolation:

      Bilinear interpolation, also known as bilinear interpolation. Mathematically , bilinear interpolation is a linear interpolation extension of an interpolation function with two variables , and its core idea is to perform a linear interpolation in two directions respectively.

If we want to get the value of the unknown function  f at the point  P=\left( x, y\right) , suppose we know the value of the function  f at  Q_{11} = \left( x_1, y_1 \right)Q_{12} = \left( x_1, y_2 \right)Q_{21} = \left( x_2, y_1 \right), and  Q_{22} = \left( x_2, y_2 \right) four points.

First perform linear interpolation in the x direction to get

f(R_1) \approx \frac{x_2-x}{x_2-x_1} f(Q_{11}) + \frac{x-x_1}{x_2-x_1} f(Q_{21}) \quad\mbox{Where}\quad R_1 = (x,y_1),
f(R_2) \approx \frac{x_2-x}{x_2-x_1} f(Q_{12}) + \frac{x-x_1}{x_2-x_1} f(Q_{22}) \quad\mbox{Where}\quad R_2 = (x,y_2).

Then perform linear interpolation in the y direction to get

f(P) \approx \frac{y_2-y}{y_2-y_1} f(R_1) + \frac{y-y_1}{y_2-y_1} f(R_2).

This gives the desired result  f \left( x, y \right),

f(x,y) \approx \frac{f(Q_{11})}{(x_2-x_1)(y_2-y_1)} (x_2-x)(y_2-y) + \frac{f(Q_{21})}{(x_2-x_1)(y_2-y_1)} (x-x_1)(y_2-y)
+ \frac{f(Q_{12})}{(x_2-x_1)(y_2-y_1)} (x_2-x)(y-y_1) + \frac{f(Q_{22})}{(x_2-x_1)(y_2-y_1)} (x-x_1)(y-y_1).

If a coordinate system is selected  f so that the four known point coordinates are (0, 0), (0, 1), (1, 0) and (1, 1), then the interpolation formula can be simplified as

f(x,y) \approx f(0,0) \, (1-x)(1-y) + f(1,0) \, x(1-y) + f(0,1) \, (1-x)y + f(1,1) xy.

Or expressed in matrix operations as

f(x,y) \approx \begin{bmatrix}1-x & x \end{bmatrix} \begin{bmatrix}f(0,0) & f(0,1) \\f(1,0) & f(1,1) \end{bmatrix} \begin{bmatrix}1-y \\y \end{bmatrix}

The result of this interpolation method is usually not linear, and the result of linear interpolation is independent of the order of interpolation. The interpolation in the y direction is performed first, and then the interpolation in the x direction, and the result obtained is the same.

Bilinear interpolation in opencv and Matlab

   The premise of this part is that you already understand what bilinear interpolation is and given the size of the source image and the target image, you can use a pen to calculate the value of a certain pixel of the target image. Of course, the best situation is that you have implemented the original or reprinted bilinear interpolation algorithm on a large number of blogs on the Internet in a certain language, and then found that the calculated result is the same as the result obtained by the resize() function corresponding to matlab and openCV totally different.

So what is going on with this?

In fact, the answer is very simple, it is the choice of the coordinate system, or the correspondence between the source image and the target image.

According to some blogs on the Internet, the origin (0, 0) of the source image and the target image are both selected in the upper left corner, and then each pixel of the target image is calculated according to the interpolation formula. Suppose you need to reduce a 5x5 image to 3x3, then The correspondence between each pixel of the source image and the target image is as follows:

Only one line is drawn for illustration. It can be clearly seen from the figure that if the upper right corner is selected as the origin (0, 0), then the rightmost and lowermost pixels do not actually participate in the calculation, and the target image The gray value calculated by each pixel is also left-up relative to the source image.

So, how about adding 1 to the coordinates or choosing the bottom right corner as the origin? Unfortunately, the same effect, but this time the resulting image will be right and down.

The best way is that the geometric centers of the two images coincide, and each pixel of the target image is equally spaced, and there is a certain margin from both sides, which is also the practice of matlab and openCV. As shown below:

If you don't understand what I said above, it doesn't matter, just change to the following formula when calculating the corresponding coordinates,

int x=(i+0.5)*m/a-0.5

int y=(j+0.5)*n/b-0.5

replace

int x=i*m/a

int y=j*n/b

Using the above formula, the correct bilinear interpolation result will be obtained

Implementation code

# --*-- encoding: utf-8 --*--
'''
Date: 2018.09.13
Content: python3 实现双线性插值图像缩放算法
'''

import numpy as np
import cv2
import math

def bi_linear(src, dst, target_size):
    pic = cv2.imread(src)       # 读取输入图像
    th, tw = target_size[0], target_size[1]
    emptyImage = np.zeros(target_size, np.uint8)
    for k in range(3):
        for i in range(th):
            for j in range(tw):
                # 首先找到在原图中对应的点的(X, Y)坐标
                corr_x = (i+0.5)/th*pic.shape[0]-0.5
                corr_y = (j+0.5)/tw*pic.shape[1]-0.5
                # if i*pic.shape[0]%th==0 and j*pic.shape[1]%tw==0:     # 对应的点正好是一个像素点,直接拷贝
                #   emptyImage[i, j, k] = pic[int(corr_x), int(corr_y), k]
                point1 = (math.floor(corr_x), math.floor(corr_y))   # 左上角的点
                point2 = (point1[0], point1[1]+1)
                point3 = (point1[0]+1, point1[1])
                point4 = (point1[0]+1, point1[1]+1)

                fr1 = (point2[1]-corr_y)*pic[point1[0], point1[1], k] + (corr_y-point1[1])*pic[point2[0], point2[1], k]
                fr2 = (point2[1]-corr_y)*pic[point3[0], point3[1], k] + (corr_y-point1[1])*pic[point4[0], point4[1], k]
                emptyImage[i, j, k] = (point3[0]-corr_x)*fr1 + (corr_x-point1[0])*fr2

    cv2.imwrite(dst, emptyImage)
    # 用 CV2 resize函数得到的缩放图像
    new_img = cv2.resize(pic, (200, 300))
    cv2.imwrite('pic/1_cv_img.png', new_img)

def main():
    src = 'pic/raw_1.jpg'
    dst = 'pic/new_1.png'
    target_size = (300, 200, 3)     # 变换后的图像大小

    bi_linear(src, dst, target_size)

if __name__ == '__main__':
    main()

Guess you like

Origin blog.csdn.net/pku_Coder/article/details/82690128