不同相机之间图片像素对应关系求解(单应性矩阵求解)

一、场景

        相机1和相机2相对位置不变,相机拍摄图片有重叠,求他们交叠部分的一一对应关系。数学语言描述为已知相机1图片中P点像素(u1, v1),相机1中P点在相机2图片中像素值为(u2, v2),它们存在某种变换,求变换矩阵。

        因为涉及的场景比较简单,目前没有涉及深度,同时采集的目标近似平面,所以可以简化场景,采用单应性矩阵求解。所以上述所涉及的变换矩阵假设为单应性矩阵H(3*3矩阵),它们满足如下关系。

         这样的话,简单很多(如果场景复杂,涉及了深度或者采集对象不是平面,可以使用本质矩阵/基础矩阵的方法获取这个变换矩阵),只需借助标准标定板计算得到H。

二、单应性矩阵

        定义:用 [理想成像] 的相机从不同位置拍摄 [同一平面物体] 的图像之间存在单应性,可以用 [透视变换] 表示 。有以下公式:

         接下来就是求解H矩阵,上述公式展开如下:

         由平面坐标与齐次坐标对应关系,上式可以表示为:

         进一步,

        写成AX=0形式,如下。这种形式求解方式很多,前面的博客也有所涉及。不过需要特别指出的是,虽然H矩阵有9个未知数,但是只有8个自由度(平面关系),其中h33=1。所以求解方程只需要4个不共线点即可求解。

三、实际效果

3.1 全部代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cv2
import numpy as np


def OnMouseAction(event, x, y, flags, param):
    """
    鼠标的回调函数,处理鼠标事件
    :param event:
    :param x:
    :param y:
    :param flags:
    :param param:
    :return:
    """
    if event == cv2.EVENT_LBUTTONDOWN:
        global gimg_x, gimg_y, gis_ok
        gimg_x = x
        gimg_y = y
        gis_ok = True
    elif event == cv2.EVENT_RBUTTONDOWN:
        print("右键点击")
    elif flags == cv2.EVENT_FLAG_LBUTTON:
        print("左鍵拖曳")
    elif event == cv2.EVENT_MBUTTONDOWN:
        print("中键点击")


def verification(img1, img2, H):
    def nothing(x):
        pass

    cv2.namedWindow('image1')
    cv2.setMouseCallback('image1', OnMouseAction)
    # create trackbars for color change
    cv2.createTrackbar('thr', 'image1', 121, 255, nothing)
    cv2.createTrackbar('Shading', 'image1', 255, 255, nothing)
    count = 0
    while True:
        cv2.imshow("image1", img1)
        cv2.imshow("image2", img2)

        k = cv2.waitKey(1) & 0xFF
        # 通过关闭窗口的右上角关闭
        if cv2.getWindowProperty('image1', cv2.WND_PROP_AUTOSIZE) < 1:
            break
        # 通过按键盘的ESC退出
        if k == 27:
            break
        global gimg_x, gimg_y, gis_ok
        if gis_ok:
            count += 1
            cv2.circle(img1, (gimg_x, gimg_y), 3, (0, 0, 255), -1)
            cv2.putText(img1, str(count), (gimg_x, gimg_y), 2, 1, (0, 0, 255))
            gis_ok = False

            (x, y, z) = np.matmul(H, np.array([gimg_x, gimg_y, 1]).T)

            cv2.circle(img2, (int(x / z), int(y / z)), 2, (0, 0, 255), -1)
            cv2.putText(img2, str(count), (int(x / z), int(y / z)), 2, 1, (0, 0, 255))


def getHomography(img1, img2):
    gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

    ret, corners1_1 = cv2.findChessboardCorners(gray1, (gcols, grows), None)
    if not ret:
        return ret, None
    # sub-pixel corner detection
    corners1_2 = cv2.cornerSubPix(gray1, corners1_1, (11, 11), (-1, -1), criteria)

    ret, corners2_1 = cv2.findChessboardCorners(gray2, (gcols, grows), None)
    if not ret:
        return ret, None
    # sub-pixel corner detection
    corners2_2 = cv2.cornerSubPix(gray2, corners2_1, (11, 11), (-1, -1), criteria)

    H, mask = cv2.findHomography(corners1_2, corners2_2, cv2.RANSAC)

    return True, H


gimg1Root = "./image_homography/1080p_1.png"
gimg2Root = "./image_homography/1080p_2.png"
gimg3Root = "./image_homography/720p_3.png"
(grows, gcols) = (8, 11)
def main():
    img1 = cv2.imread(gimg1Root)
    img2 = cv2.imread(gimg3Root)
    is_ok, H = getHomography(img1, img2)
    print(H)

    verification(img1, img2, H)


global gimg_x, gimg_y, gis_ok
gimg_x = 0
gimg_y = 0
gis_ok = False
if __name__ == "__main__":
    main()

3.2 实际效果

猜你喜欢

转载自blog.csdn.net/qq_31112205/article/details/129047100