python双目相机标定极线校正,棋盘格 主要功能描述: 1、程序界面使用pyqt开发; 2、自动检测无效图像并去除; 3、标定后显示重投影误差分布散点图; 4、依据标定参数对图像做极线校正并显示; 5、标定结果存储到xml文件;

在机器视觉领域,双目相机标定与极线校正可是相当重要的环节。今天咱就用 Python 搭配 PyQt 来实现这么一个超酷的功能,还会用到棋盘格来辅助我们完成标定哦。

1. 程序界面使用 PyQt 开发

PyQt 是 Python 下强大的 GUI 开发框架,咱先搭建个基础界面框架。首先得安装 PyQt,一般用 pip install PyQt5 就能搞定。

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setWindowTitle('双目相机标定与校正')
        self.setGeometry(100, 100, 800, 600)

        label = QLabel('欢迎使用双目相机标定程序', self)
        label.move(300, 250)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())

上面这段代码创建了一个简单的主窗口,设置了标题和大小,并在窗口中添加了一个欢迎标签。之后我们会在这个基础上不断丰富功能。

2. 自动检测无效图像并去除

在标定过程中,有些图像可能因为棋盘格检测不到等原因是无效的。我们利用 OpenCV 来检测棋盘格从而判断图像是否有效。

import cv2
import numpy as np

def detect_chessboard(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
    if ret:
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
        corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        return True
    else:
        return False

这段代码中,先把图像转成灰度图,然后用 cv2.findChessboardCorners 尝试检测棋盘格角点,如果检测到就进一步优化角点位置,返回 True,否则返回 False。在实际处理图像集合时,就可以根据这个函数返回值来剔除无效图像。

3. 标定后显示重投影误差分布散点图

相机标定后,重投影误差能很好地反映标定的精度。我们使用 cv2.calibrateCamera 进行标定后,计算并绘制重投影误差散点图,这里会用到 matplotlib 库,安装命令 pip install matplotlib

import matplotlib.pyplot as plt

def calculate_and_plot_reprojection_error(objpoints, imgpoints, mtx, dist, rvecs, tvecs):
    mean_error = 0
    error_list = []
    for i in range(len(objpoints)):
        imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
        error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
        error_list.append(error)
        mean_error += error
    mean_error /= len(objpoints)
    print(f"总平均误差: {mean_error}")

    plt.scatter(range(len(error_list)), error_list)
    plt.xlabel('图像索引')
    plt.ylabel('重投影误差')
    plt.title('重投影误差分布散点图')
    plt.show()

上述代码先循环计算每张图像的重投影误差,保存到列表 error_list 中,最后用 matplotlib 绘制散点图,直观展示误差分布情况。

4. 依据标定参数对图像做极线校正并显示

有了标定参数,就可以进行极线校正啦。

def rectify_images(left_img, right_img, mtx1, dist1, mtx2, dist2, R, T):
    R1, R2, P1, P2, Q, _, _ = cv2.stereoRectify(mtx1, dist1, mtx2, dist2, (left_img.shape[1], left_img.shape[0]), R, T)
    map1x, map1y = cv2.initUndistortRectifyMap(mtx1, dist1, R1, P1, (left_img.shape[1], left_img.shape[0]), cv2.CV_32FC1)
    map2x, map2y = cv2.initUndistortRectifyMap(mtx2, dist2, R2, P2, (right_img.shape[1], right_img.shape[0]), cv2.CV_32FC1)

    rectified_left = cv2.remap(left_img, map1x, map1y, cv2.INTER_LINEAR)
    rectified_right = cv2.remap(right_img, map2x, map2y, cv2.INTER_LINEAR)

    return rectified_left, rectified_right

这里通过 cv2.stereoRectify 计算校正变换矩阵,再用 cv2.initUndistortRectifyMapcv2.remap 完成图像的校正。

5. 标定结果存储到 xml 文件

最后一步,把标定结果保存到 xml 文件里,方便后续使用。

import cv2
import numpy as np
import xml.etree.ElementTree as ET

def save_calibration_results_to_xml(mtx1, dist1, mtx2, dist2, R, T, filename='calibration_results.xml'):
    root = ET.Element('calibration_results')

    mtx1_elem = ET.SubElement(root,'mtx1')
    for row in mtx1:
        row_elem = ET.SubElement(mtx1_elem, 'row')
        for val in row:
            ET.SubElement(row_elem, 'value').text = str(val)

    dist1_elem = ET.SubElement(root, 'dist1')
    for val in dist1[0]:
        ET.SubElement(dist1_elem, 'value').text = str(val)

    # 类似处理 mtx2, dist2, R, T

    tree = ET.ElementTree(root)
    tree.write(filename)

这段代码把标定得到的相机内参、畸变系数等结果写入 xml 文件,后续使用时可以方便地读取。

以上就是利用 Python 实现双目相机标定与极线校正的主要过程啦,一步步来,机器视觉的神奇世界就一点点展现在我们眼前咯。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐