Detailed perspective transformation with the principles of code - division and correction Poker


Introduction
In the previous article, we introduced the affine transformation, we only need two lines through a transformation matrix M three would be able to achieve the image pan, zoom, flip, rotate operation. We find that these transformations actually belong to the plane transformation, if we want to transform the space yet?

FIG upper playing cards individually extracted, as shown in FIG.

At this time we should be how to achieve this function? This in fact involves a spatial transformation of the image, we need to use what we call a perspective transformation.

Perspective transformation
perspective transform (Perspective Transformation) refers to the use central perspective image point, the condition of the target point are collinear, the rotation of the bearing according to the law of perspective Movies surface (surface S) about a trace (perspective axis) is rotated a certain angle, destroy the original projection light beam, we can maintain the same geometric plane of the projection bearing Movies transformation. Briefly, a plane is projected through a projection matrix to the specified plane.

Analytical principle of
perspective transformation general transformation formula:



 
​    

8 by the above equation, we can solve for the eight parameters to obtain the perspective transformation matrix, and finally we achieved by using perspective transformation through the perspective transformation matrix opencv warpPerspective method, then we example by binding to a particular use it.
Perspective transformation examples to explain
where we are mainly realized through the features described above opencv

Read image

#读取图像
img = cv2.imread("poker.jpeg")
#将原图转为灰度图
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)


Canny edge detection
Canny function parameter analysis:

image: input image array
threshold1: minimum threshold value
threshold2: highest threshold
edges: an edge image output, a single-channel 8-bit image
apertureSize: Sobel operator size
L2gradient: indicates a Boolean value, if true, use the more accurate L2 norm is calculated, using the L1 norm or

#Canny边缘检测
canny_img = cv2.Canny(gray_img,100,150,3)
#显示边缘检测后的图像
cv2.imshow("canny_img",canny_img)
cv2.waitKey(0)


Hough line detection
HoughLinesP function parameter analysis:

image: After output of the Canny edge detection image
rho: polar radius values r at a resolution in units of pixels, typically only one pixel
theta: polar polar angle θ \ thetaθ in radians resolution unit is generally used 1 degree
threshold: the minimum required to detect an intersection curve straight
lines: straight lines detected stored, comprising starting and ending coordinates of the line
minLineLength: a minimum number of component points of a straight line, the straight line is less than the number of points to be discarded
maxLineGap: in the maximum distance of a point on a straight line

def draw_line(img,lines):
    # 绘制直线
    for line_points in lines:
        cv2.line(img,(line_points[0][0],line_points[0][1]),(line_points[0][2],line_points[0][3]),
                 (0,255,0),2,8,0)
    cv2.imshow("line_img", img)
    cv2.waitKey(0)
# #Hough直线检测
lines = cv2.HoughLinesP(canny_img,1,np.pi/180,70,minLineLength=30,maxLineGap=10)
#基于边缘检测的图像来检测直线
draw_line(img,lines)


Calculating vertex coordinates
to calculate intersection coordinates by a coordinate straight line joining the two end points, the position of the playing cards to find four vertices

#计算四条直线的交点作为顶点坐标
def computer_intersect_point(lines):
    def get_line_k_b(line_point):
        """计算直线的斜率和截距
        :param line_point: 直线的坐标点
        :return:
        """
        #获取直线的两点坐标
        x1,y1,x2,y2 = line_point[0]
        #计算直线的斜率和截距
        k = (y1 - y2)/(x1 - x2)
        b = y2 - x2 * (y1 - y2)/(x1 - x2)
        return k,b
    #用来存放直线的交点坐标
    line_intersect = []
    for i in range(len(lines)):
        k1,b1 = get_line_k_b(lines[i])
        for j in range(i+1,len(lines)):
            k2,b2 = get_line_k_b(lines[j])
            #计算交点坐标
            x = (b2 - b1) / (k1 - k2)
            y = k1 * (b2 - b1)/(k1 -k2) + b1
            if x > 0 and y > 0:
                line_intersect.append((int(np.round(x)),int(np.round(y))))
    return line_intersect
def draw_point(img,points):
    for position in points:
        cv2.circle(img,position,5,(0,0,255),-1)
    cv2.imshow("draw_point",img)
    cv2.waitKey(0)
#计算直线的交点坐标
line_intersect = computer_intersect_point(lines)
#绘制交点坐标的位置
draw_point(img,line_intersect)


Sorting the coordinates of the vertices
prior to calculating the coordinates of the perspective transformation matrix we need to correspond to the image coordinates of the image transform elements, according to the left -> on -> Right - Order> under

def order_point(points):
    """对交点坐标进行排序
    :param points:
    :return:
    """
    points_array = np.array(points)
    #对x的大小进行排序
    x_sort = np.argsort(points_array[:,0])
    #对y的大小进行排序
    y_sort = np.argsort(points_array[:,1])
    #获取最左边的顶点坐标
    left_point = points_array[x_sort[0]]
    #获取最右边的顶点坐标
    right_point = points_array[x_sort[-1]]
    #获取最上边的顶点坐标
    top_point = points_array[y_sort[0]]
    #获取最下边的顶点坐标
    bottom_point = points_array[y_sort[-1]]
    return np.array([left_point,top_point,right_point,bottom_point],dtype=np.float32)
def target_vertax_point(clockwise_point):
    #计算顶点的宽度(取最大宽度)
    w1 = np.linalg.norm(clockwise_point[0]-clockwise_point[1])
    w2 = np.linalg.norm(clockwise_point[2]-clockwise_point[3])
    w = w1 if w1 > w2 else w2
    #计算顶点的高度(取最大高度)
    h1 = np.linalg.norm(clockwise_point[1]-clockwise_point[2])
    h2 = np.linalg.norm(clockwise_point[3]-clockwise_point[0])
    h = h1 if h1 > h2 else h2
    #将宽和高转换为整数
    w = int(round(w))
    h = int(round(h))
    #计算变换后目标的顶点坐标
    top_left = [0,0]
    top_right = [w,0]
    bottom_right = [w,h]
    bottom_left = [0,h]
    return np.array([top_left,top_right,bottom_right,bottom_left],dtype=np.float32)
#对原始图像的交点坐标进行排序
clockwise_point = order_point(line_intersect)
#获取变换后坐标的位置
target_clockwise_point = target_vertax_point(clockwise_point)


Calculating a transform matrix for a perspective conversion

#计算变换矩阵
matrix = cv2.getPerspectiveTransform(clockwise_point,target_clockwise_point)
print(matrix)
#计算透视变换后的图片
perspective_img = cv2.warpPerspective(img,matrix,(target_clockwise_point[2][0],target_clockwise_point[2][1]))
cv2.imshow("perspective_img",perspective_img)
cv2.waitKey(0)

 

[[ 1.34133640e+00 -8.01200936e-01 -2.49362538e+01]
 [ 7.10053715e-01  1.67369804e+00 -1.62145838e+02]
 [ 2.49859580e-04  3.44969838e-03  1.00000000e+00]]

 

Published 86 original articles · won praise 267 · Views 1.77 million +

Guess you like

Origin blog.csdn.net/javastart/article/details/104325795