How does warp Perspective work?

Posted by yaohong on Saturday, January 23, 2021

TOC

How does warp Perspective work?

1.warp perspective with cv2

if __name__ == "__main__":
    # coordinate: (y,x), left_top, right_rop, left_bottom, right_bottom
    src = np.float32([[20.0, 0.0], [20.0 ,315.0], [186.0, 17.2], [181.0, 299.0]])
    dst = np.float32([[0.0, 0.0],  [0.0,  315.0], [202.0, 7.0], [200.0, 306.0]])

    # load image
    warp_img = cv2.imread("./my_wide_angle_orig.jpg")
    warp_img = cv2.cvtColor(warp_img, cv2.COLOR_BGR2RGB)
    print("warp_img: ",warp_img.shape) # (638, 958, 3)
    width = int(warp_img.shape[1]/3)
    height = int(warp_img.shape[0]/3)
    warp_img  = cv2.resize(warp_img, (width,height), interpolation=cv2.INTER_LINEAR)
    print("warp_img.shape:",warp_img.shape) # (212, 319, 3)

    ## orig image
    plt.subplot(121),
    plt.title("warp_img")
    plt.imshow(warp_img)

    # cv2 warp perspective
    cv2_matrix = cv2.getPerspectiveTransform(src, dst)
    print("cv2_matrix:\n",cv2_matrix)
    cv2_fix_img = cv2.warpPerspective(warp_img, cv2_matrix, (width,height))
    plt.subplot(122),
    plt.title('cv2_fix_img')
    plt.imshow(cv2_fix_img) 
    plt.show()

2.Implement it in our way

Step1 calculate warp matrix:

my_warp_matrix reshape:
 [[ 1.13729359e+00 -8.24289989e-18 -2.27458717e+01]
 [-6.10786436e-02  9.69843448e-01  1.22157287e+00]
 [-3.44743207e-04 -7.38466280e-05  1.00000000e+00]]

Step2. use the warp matrix to warp perspective

codes are:


import numpy as np
from matplotlib import pyplot as plt
import cv2

class MyPerspectiveTransform:

    def calcWarpMatrix(self, src, dst):
        A_matrix        = [];
        B_vector        = [];
        for src_i, src_v in enumerate(src):
            # X0
            A_matrix.append( [src_v[0], src_v[1], 1, 0, 0, 0, 
                                    -src_v[0]*dst[src_i][0], - src_v[1]*dst[src_i][0] ]);
            B_vector.append(dst[src_i][0]);
            # Y0
            A_matrix.append( [0, 0, 0, src_v[0], src_v[1], 1, -src_v[0]*dst[src_i][1],  
                    -src_v[1]*dst[src_i][1] ]);
            B_vector.append(dst[src_i][1]);

        A_matrix = np.array(A_matrix)
        B_vector = np.array(B_vector)
        A_matrix = np.mat(A_matrix)
        B_vector = np.expand_dims(B_vector, axis = 1)

        # A_matrix * warp_matrix = B_vector
        # So, A_vectro = A_matrix^-1 * B_vector
        warp_matrix = A_matrix.I * B_vector 
        warp_matrix = np.insert(warp_matrix, warp_matrix.shape[0],1)
        warp_matrix = warp_matrix.reshape((3,3))
        print("my_warp_matrix reshape:\n", warp_matrix);
        self.warp_matrix = warp_matrix;
        return warp_matrix;

    def myWarpPerspective(self,warp_img):
        # for c in range(warp_img.shape):
        fix_matrix = self.warp_matrix;
        a_11 = fix_matrix[0,0]
        a_12 = fix_matrix[0,1]
        a_13 = fix_matrix[0,2]
        a_21 = fix_matrix[1,0]
        a_22 = fix_matrix[1,1]
        a_23 = fix_matrix[1,2]
        a_31 = fix_matrix[2,0]
        a_32 = fix_matrix[2,1]
        a_33 = fix_matrix[2,2]
        fix_img = np.zeros((warp_img.shape));

        max_y = warp_img.shape[0] - 1;
        max_x = warp_img.shape[1] - 1;
        for height_i in range(warp_img.shape[0]): # height or y
            for width_i in range(warp_img.shape[1]): # width or x
                Y_fix = height_i; 
                X_fix = width_i;
                
                # get y by 
                y_denominator =     (a_31*Y_fix - a_21)*a_12 - (a_31*Y_fix - a_21)*a_32*X_fix - (a_31*X_fix - a_11)*a_22 + (a_31*X_fix - a_11)*a_32*Y_fix ;
                y = ( (a_23 - a_33*Y_fix - ((a_31*Y_fix - a_21)*a_13)/(a_31*X_fix - a_11)
                        + ((a_31*Y_fix - a_21)*a_33*X_fix)/(a_31*X_fix - a_11) )
                        * (a_31*X_fix - a_11) ) / y_denominator

                x = (a_12*y + a_13 - (a_32*y*X_fix + a_33*X_fix)) / (a_31*X_fix - a_11)

                # print("height_i:",height_i,",width_i:",width_i,",y:",y,",fix_x:",x)
                y = int(np.round(y))
                x = int(np.round(x))
                if y < 0:
                    y = 0;
                if y > max_y:
                    y = max_y;
                if x < 0:
                    x = 0;
                if x > max_x:
                    x = max_x;

                c_i = 0;
                fix_img[height_i,width_i,c_i] = warp_img[y,x,c_i]
                c_i = 1;
                fix_img[height_i,width_i,c_i] = warp_img[y,x,c_i]
                c_i = 2;
                fix_img[height_i,width_i,c_i] = warp_img[y,x,c_i]
                print("height_i:",height_i,",width_i:",width_i,",y:",y,"fix_x:",x)

        return fix_img


if __name__ == "__main__":
    # coordinate: (y,x), left_top, right_rop, left_bottom, right_bottom
    src = np.float32([[20.0, 0.0], [20.0 ,315.0], [186.0, 17.2], [181.0, 299.0]])
    dst = np.float32([[0.0, 0.0],  [0.0,  315.0], [202.0, 7.0], [200.0, 306.0]])

    myPerspectiveTransform =  MyPerspectiveTransform()
    myPerspectiveTransform.calcWarpMatrix(src, dst) # my (x,y) 

    # load image
    warp_img = cv2.imread("./my_wide_angle_orig.jpg")
    warp_img = cv2.cvtColor(warp_img, cv2.COLOR_BGR2RGB)
    print("warp_img: ",warp_img.shape) # (638, 958, 3)
    width = int(warp_img.shape[1]/3)
    height = int(warp_img.shape[0]/3)
    warp_img  = cv2.resize(warp_img, (width,height), interpolation=cv2.INTER_LINEAR)
    print(width,",height:",height,", ",warp_img.shape) # (212, 319, 3)

    # 
    plt.subplot(121),
    plt.title("warp_img"),#plt.xticks([]);plt.yticks([]);
    plt.imshow(warp_img)

    # Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers)
    fix_img = myPerspectiveTransform.myWarpPerspective(warp_img)
    fix_img = (fix_img).astype(np.uint8)
    plt.subplot(122),
    plt.imshow(fix_img) 
    plt.title('my_fix_img'),#plt.xticks([]),plt.yticks([]);
    plt.show()

Here shows how to get x and y, codes:

'''
# get x
(a_31*x + a_32*y + a_33) * X_fix = (a_11*x + a_12*y + a_13)
=> a_31*x*X_fix + a_32*y*X_fix + a_33*X_fix = a_11*x + a_12*y + a_13
=> a_31*x*X_fix - a_11*x = a_12*y + a_13 - (a_32*y*X_fix + a_33*X_fix)
=> x = [a_12*y + a_13 - (a_32*y*X_fix + a_33*X_fix)] / (a_31*X_fix - a_11)

# get y
(a_31*x + a_32*y + a_33) * Y_fix = (a_21*x + a_22*y + a_23)
=> a_31*x*Y_fix + a_32*y* Y_fix + a_33*Y_fix - a_21*x = (a_22*y + a_23)    
=> a_31*x*Y_fix - a_21*x = (a_22*y + a_23)  - (a_32*y*Y_fix + a_33*Y_fix)
=> (a_31*Y_fix - a_21)*x = (a_22*y + a_23)  - (a_32*y*Y_fix + a_33*Y_fix)

# get y without x, remove x
=> (a_31*Y_fix - a_21){[a_12*y + a_13 - a_32*y*X_fix - a_33*X_fix] / (a_31*X_fix - a_11)} 
            = (a_22*y + a_23)  - (a_32*y*Y_fix + a_33*Y_fix)

=> (a_31*Y_fix - a_21){[a_12*y + a_13 - a_32*y*X_fix - a_33*X_fix] / (a_31*X_fix - a_11)} 
            = a_22*y + a_23  - a_32*y*Y_fix - a_33*Y_fix
=>  [(a_31*Y_fix - a_21)*a_12*y]        / (a_31*X_fix - a_11) + 
    [(a_31*Y_fix - a_21)*a_13]          / (a_31*X_fix - a_11) - 
    [(a_31*Y_fix - a_21)*a_32*y*X_fix]  / (a_31*X_fix - a_11) -
    [(a_31*Y_fix - a_21)*a_33*X_fix]    / (a_31*X_fix - a_11) = a_22*y + a_23  - a_32*y*Y_fix - a_33*Y_fix

=>  [(a_31*Y_fix - a_21)*a_12*y]        / (a_31*X_fix - a_11) + 
    [(a_31*Y_fix - a_21)*a_13]          / (a_31*X_fix - a_11) - 
    [(a_31*Y_fix - a_21)*a_32*y*X_fix]  / (a_31*X_fix - a_11) -
    [(a_31*Y_fix - a_21)*a_33*X_fix]    / (a_31*X_fix - a_11) - a_22*y  + a_32*y*Y_fix = a_23 - a_33*Y_fix

=>  [(a_31*Y_fix - a_21)*a_12*y]        / (a_31*X_fix - a_11)  - 
    [(a_31*Y_fix - a_21)*a_32*y*X_fix]  / (a_31*X_fix - a_11)  - a_22*y  + a_32*y*Y_fix 
    = a_23 - a_33*Y_fix 
        - [(a_31*Y_fix - a_21)*a_13]          / (a_31*X_fix - a_11)
        + [(a_31*Y_fix - a_21)*a_33*X_fix]    / (a_31*X_fix - a_11)

=> { [(a_31*Y_fix - a_21)*a_12*y]  - [(a_31*Y_fix - a_21)*a_32*y*X_fix]  - (a_31*X_fix - a_11)* a_22*y  + (a_31*X_fix - a_11)*a_32*y*Y_fix } 
        / (a_31*X_fix - a_11) 
    = a_23 - a_33*Y_fix 
        - [(a_31*Y_fix - a_21)*a_13]          / (a_31*X_fix - a_11)
        + [(a_31*Y_fix - a_21)*a_33*X_fix]    / (a_31*X_fix - a_11)

=>{ [(a_31*Y_fix - a_21)*a_12*y]  - [(a_31*Y_fix - a_21)*a_32*y*X_fix]  - (a_31*X_fix - a_11)* a_22*y  + (a_31*X_fix - a_11)*a_32*y*Y_fix } 
    = {a_23 - a_33*Y_fix 
        - [(a_31*Y_fix - a_21)*a_13]          / (a_31*X_fix - a_11)
        + [(a_31*Y_fix - a_21)*a_33*X_fix]    / (a_31*X_fix - a_11)} * (a_31*X_fix - a_11) 
    

=> y * { [(a_31*Y_fix - a_21)*a_12]  - [(a_31*Y_fix - a_21)*a_32*X_fix]  - (a_31*X_fix - a_11)* a_22  + (a_31*X_fix - a_11)*a_32*Y_fix } 
    = {a_23 - a_33*Y_fix 
        - [(a_31*Y_fix - a_21)*a_13]          / (a_31*X_fix - a_11)
        + [(a_31*Y_fix - a_21)*a_33*X_fix]    / (a_31*X_fix - a_11) } * (a_31*X_fix - a_11) 

=> y = { {a_23 - a_33*Y_fix 
        - [(a_31*Y_fix - a_21)*a_13]/(a_31*X_fix - a_11)
        + [(a_31*Y_fix - a_21)*a_33*X_fix]/(a_31*X_fix - a_11) } 
      * (a_31*X_fix - a_11) } 
      / { [(a_31*Y_fix - a_21)*a_12]  - [(a_31*Y_fix - a_21)*a_32*X_fix]  - (a_31*X_fix - a_11)* a_22  + (a_31*X_fix - a_11)*a_32*Y_fix } 

At the end, replace the curly bracket and square brackets with bracket while execute it python.
'''

「点个赞」

Yaohong

点个赞

使用微信扫描二维码完成支付