【鱼眼+普通相机】相机标定

一、简介

本文提供了鱼眼及普通相机的标定python版源码,调用opencv的接口,原理为张正友标定法。这里不过多赘述,话不多说无套路直接上源码,亲测有效,搬走即用。

注:

  1. 需准备一个标定版,在此网站下载打印出来即可;
  2. 例如12x8的棋盘格内角点为11x7.

二 、源码

2.1 鱼眼相机标定

python 复制代码
"""
~~~~~~~~~~~~~~~~~~~~~~~~~~
鱼眼相机标定
~~~~~~~~~~~~~~~~~~~~~~~~~~

用法:
    python calibrate_camera.py \
        -i 0 \
        -grid 9x6 \
        -out fisheye.yaml \
        -framestep 20 \
        --resolution 640x480
        --fisheye
"""
import argparse
import os
import numpy as np
import cv2


# 将相机参数文件保存到此目录
TARGET_DIR = os.path.join(os.getcwd(), "yaml")

# 默认参数文件
DEFAULT_PARAM_FILE = os.path.join(TARGET_DIR, "calib.yaml")


def main():
    global gray
    parser = argparse.ArgumentParser()

    # 输入视频流
    parser.add_argument("-i", "--input", type=int, default=0,
                        help="输入相机设备")

    # 棋盘格大小
    parser.add_argument("-grid", "--grid", default="10x7",
                        help="标定棋盘格的大小")

    parser.add_argument("-r", "--resolution", default="640x480",
                        help="相机图像的分辨率")

    parser.add_argument("-framestep", type=int, default=20,
                        help="在视频中使用每第n帧")

    parser.add_argument("-o", "--output", default=DEFAULT_PARAM_FILE,
                        help="输出yaml文件的路径")


    args = parser.parse_args()

    if not os.path.exists(TARGET_DIR):
        os.mkdir(TARGET_DIR)

    text1 = "按下 c 进行标定"
    text2 = "按下 q 退出"
    text3 = "设备: {}".format(args.input)
    font = cv2.FONT_HERSHEY_SIMPLEX
    fontscale = 0.6

    resolution_str = args.resolution.split("x")
    W = int(resolution_str[0])
    H = int(resolution_str[1])
    grid_size = tuple(int(x) for x in args.grid.split("x"))
    grid_points = np.zeros((1, np.prod(grid_size), 3), np.float32)
    grid_points[0, :, :2] = np.indices(grid_size).T.reshape(-1, 2)

    objpoints = []  # 真实世界空间中的3D点
    imgpoints = []  # 图像平面中的2D点

    device = args.input
    cap = cv2.VideoCapture(device)  # 打开设备
    # 设置分辨率
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, W)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, H)
    if cap is None or not cap.isOpened():
        print("无法打开设备")
        return

    quit = False
    do_calib = False
    i = -1
    while True:
        i += 1
        _r, img = cap.read()
        img= cv2.resize(img, (W, H))
        if i % args.framestep != 0:
            continue

        print("在第 " + str(i) + " 帧中寻找棋盘格角点...")
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        found, corners = cv2.findChessboardCorners(
            gray,
            grid_size,
            cv2.CALIB_CB_ADAPTIVE_THRESH +
            cv2.CALIB_CB_NORMALIZE_IMAGE +
            cv2.CALIB_CB_FILTER_QUADS
        )
        if found:
            term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.01)
            cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), term)
            print("OK")
            imgpoints.append(corners)
            objpoints.append(grid_points)
            cv2.drawChessboardCorners(img, grid_size, corners, found)

        cv2.putText(img, text1, (20, 70), font, fontscale, (255, 200, 0), 2)
        cv2.putText(img, text2, (20, 110), font, fontscale, (255, 200, 0), 2)
        cv2.putText(img, text3, (20, 30), font, fontscale, (255, 200, 0), 2)
        cv2.imshow("corners", img)
        key = cv2.waitKey(1) & 0xFF
        if key == ord("c"):
            print("\n进行标定...\n")
            N_OK = len(objpoints)
            if N_OK < 12:
                print("检测到的角点少于12个 (%d),标定失败" %(N_OK))
                continue
            else:
                do_calib = True
                break

        elif key == ord("q"):
            quit = True
            break

    if quit:
        print("标定已退出。")
        cap.release()
        cv2.destroyAllWindows()

    if do_calib:
        N_OK = len(objpoints)
        K = np.zeros((3, 3))
        D = np.zeros((4, 1))
        rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for _ in range(N_OK)]
        tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for _ in range(N_OK)]
        calibration_flags = (cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC +
                             cv2.fisheye.CALIB_CHECK_COND +
                             cv2.fisheye.CALIB_FIX_SKEW)
       
        ret, mtx, dist, rvecs, tvecs = cv2.fisheye.calibrate(
                objpoints,
                imgpoints,
                (W, H),
                K,
                D,
                rvecs,
                tvecs,
                calibration_flags,
                (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
            )
            

        if ret:
            fs = cv2.FileStorage(args.output, cv2.FILE_STORAGE_WRITE)
            fs.write("resolution", np.int32([W, H]))
            fs.write("camera_matrix", mtx)
            fs.write("dist_coeffs", dist)
            fs.release()
            print("相机数据保存成功")
            cv2.putText(img, "SUCCESS!", (220, 240), font, 2, (0, 0, 255), 2)

        else:
            cv2.putText(img, "FAILED!", (220, 240), font, 2, (0, 0, 255), 2)

        cv2.imshow("corners", img)
        cv2.waitKey(0)


if __name__ == "__main__":
    main()

2.2 普通工业相机标定

python 复制代码
"""
~~~~~~~~~~~~~~~~~~~~~~~~~~
普通工业相机标定
~~~~~~~~~~~~~~~~~~~~~~~~~~
用法:
    python calibrate_camera.py \
        -i 0 \
        -grid 7x10 \
        -out calib.yaml \
        -framestep 20 \
        --resolution 640x480
"""
import argparse
import os
import numpy as np
import cv2

# 将相机参数文件保存到此目录
TARGET_DIR = os.path.join(os.getcwd(), "calib_yaml")

# 默认参数文件
DEFAULT_PARAM_FILE = os.path.join(TARGET_DIR, "calib.yaml")


def main():
    global gray
    parser = argparse.ArgumentParser()  # 创建解析器

    # 输入视频流
    parser.add_argument("-i", "--input", default="0",
                        help="输入相机设备")    # type=int,

    # 棋盘格大小
    parser.add_argument("-grid", "--grid", default="11x8",
                        help="标定棋盘格的大小")

    parser.add_argument("-r", "--resolution", default="640x480",
                        help="相机图像的分辨率")

    parser.add_argument("-framestep", type=int, default=20,
                        help="在视频中使用每第n帧")

    parser.add_argument("-o", "--output", default=DEFAULT_PARAM_FILE,
                        help="输出yaml文件的路径")

    args = parser.parse_args()

    if not os.path.exists(TARGET_DIR):
        os.mkdir(TARGET_DIR)

    text1 = "Press c for calibration"
    text2 = "Press q to exit"
    text3 = "device: {}".format(args.input)
    font = cv2.FONT_HERSHEY_SIMPLEX
    fontscale = 0.6

    resolution_str = args.resolution.split("x")  # 分辨率
    W = int(resolution_str[0])
    H = int(resolution_str[1])
    grid_size = tuple(int(x) for x in args.grid.split("x"))  # 棋盘格大小
    grid_points = np.zeros((1, np.prod(grid_size), 3), np.float32)  # 3D点
    grid_points[0, :, :2] = np.indices(grid_size).T.reshape(-1, 2)  # 2D点

    objpoints = []  # 真实世界空间中的3D点
    imgpoints = []  # 图像平面中的2D点

    device = args.input  # 设备
    cap = cv2.VideoCapture(device)  # 打开设备
    # 设置分辨率
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, W)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, H)
    if cap is None or not cap.isOpened():
        print("无法打开设备")
        return

    quit = False
    do_calib = False
    i = -1
    while True:
        i += 1
        _r, img = cap.read()
        img= cv2.resize(img, (W, H))
        if i % args.framestep != 0:
            continue

        print("在第 " + str(i) + " 帧中寻找棋盘格角点...")
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图像
        found, corners = cv2.findChessboardCorners(  # 检测棋盘格角点
            gray,
            grid_size,
            cv2.CALIB_CB_ADAPTIVE_THRESH +
            cv2.CALIB_CB_NORMALIZE_IMAGE +
            cv2.CALIB_CB_FILTER_QUADS
        )
        if found:  # 如果找到棋盘格角点
            term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.01)  # 终止条件
            cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), term)  # 亚像素级角点检测
            print("OK")
            imgpoints.append(corners)  # 2D点
            objpoints.append(grid_points)  # 3D点
            cv2.drawChessboardCorners(img, grid_size, corners, found)  # 绘制棋盘格角点

        cv2.putText(img, text1, (20, 70), font, fontscale, (255, 200, 0), 2)
        cv2.putText(img, text2, (20, 110), font, fontscale, (255, 200, 0), 2)
        cv2.putText(img, text3, (20, 30), font, fontscale, (255, 200, 0), 2)
        cv2.imshow("corners", img)
        key = cv2.waitKey(1) & 0xFF
        if key == ord("c"):
            print("\n进行标定...\n")
            N_OK = len(objpoints)  # 有效的标定图像数量
            if N_OK < 12:
                print("检测到的角点少于12个 (%d),标定失败" % (N_OK))
                continue
            else:
                do_calib = True
                break

        elif key == ord("q"):
            quit = True
            break

    if quit:
        print("标定已退出。")
        cap.release()
        cv2.destroyAllWindows()

    if do_calib:
        N_OK = len(objpoints)
        K = np.zeros((3, 3))
        D = np.zeros((4, 1))
        rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for _ in range(N_OK)]
        tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for _ in range(N_OK)]

        ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
            objpoints,
            imgpoints,
            gray.shape[::-1],
            None,
            None)

        if ret:
            fs = cv2.FileStorage(args.output, cv2.FILE_STORAGE_WRITE)
            fs.write("resolution", np.int32([W, H]))
            fs.write("camera_matrix", mtx)  # 内参矩阵
            fs.write("dist_coeffs", dist)  # 畸变系数
            # print("rvecs:", rvecs)  # 旋转向量
            # print("tvecs:", rvecs)  # 平移向量
            fs.release()
            print("相机数据保存成功")
            cv2.putText(img, "SUCCESS!", (220, 240), font, 2, (0, 0, 255), 2)
        else:
            cv2.putText(img, "FAILED!", (220, 240), font, 2, (0, 0, 255), 2)

        cv2.imshow("corners", img)
        cv2.waitKey(0)


if __name__ == "__main__":
    main()
相关推荐
hixiong1231 小时前
C# OpenCVSharp使用 读光-票证检测矫正模型
人工智能·opencv·c#
沃达德软件3 小时前
智能识别车辆驾驶人特征
人工智能·目标检测·计算机视觉·目标跟踪·视觉检测
这张生成的图像能检测吗5 小时前
(论文速读)LyT-Net:基于YUV变压器的轻量级微光图像增强网络
图像处理·人工智能·计算机视觉·低照度
却道天凉_好个秋9 小时前
OpenCV(十九):图像的加法运算
opencv·计算机视觉
思则变11 小时前
[图像处理]图像美化
图像处理·人工智能
王哈哈^_^13 小时前
【完整源码+数据集】草莓数据集,yolov8草莓成熟度检测数据集 3207 张,草莓成熟度数据集,目标检测草莓识别算法系统实战教程
人工智能·算法·yolo·目标检测·计算机视觉·视觉检测·毕业设计
AndrewHZ13 小时前
【图像处理基石】提升图像通透感:从原理到实操的完整指南
图像处理·人工智能·计算机视觉·cv·对比度·动态范围·通透感
【赫兹威客】浩哥15 小时前
基于 YOLO11+PyQt6+OpenCV 的智能水果检测系统设计与实现
人工智能·opencv·计算机视觉
Antonio91519 小时前
【图像处理】图像的基础几何变换
图像处理·人工智能·计算机视觉
智驱力人工智能20 小时前
基于视觉分析的人脸联动使用手机检测系统 智能安全管理新突破 人脸与手机行为联动检测 多模态融合人脸与手机行为分析模型
算法·安全·目标检测·计算机视觉·智能手机·视觉检测·边缘计算