【摄像头标定】单目摄像头标定及矫正-opencv(python)

单目摄像头标定及矫正

①标定

既然是标定,就需要准备使用待标定单目摄像头拍摄的标定板图片。

这里使用棋盘格标定板,可以到网上下载,需要知道棋盘格的角点。

由于我的摄像头是嵌入于开发板底板中,并且摄像头数据通过ros话题发布,所以拍照方式比较不一样,使用ros作为工具,编写节点代码进行拍照,不了解ros的可以自己搜索一下如何对连接到开发板上的usb摄像头拍照,一般开发板连接USB摄像头的话,可以直接通过opencv的videocapture打开摄像头获取数据,比较方便的拍照。拍摄不同角度和位置的图片10-20张即可。

标定代码如下:可以在各种能运行python代码的IDE中运行,比如pycharm、vscode等等。

复制代码
import cv2
import numpy as np
import glob
import os
import yaml
# 相机标定
# 设置棋盘格w和h方向的角点数量
w_corners = 8               #改!数棋盘格宽有多少个格子,然后减一
h_corners = 5               #改!数棋盘格高有多少个格子,然后减一
# 设置图像路径
images = glob.glob(r"C:\new_pycharm_project\yolov10-main\daijiaozheng\*.png")         #改!改成自己存放图片的路径

criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)

# 获取标定板角点的位置
objp = np.zeros((w_corners * h_corners, 3), np.float32)
objp[:, :2] = np.mgrid[0:w_corners, 0:h_corners].T.reshape(-1, 2)
objp = objp * 21            #改!这里的21是一个格子的长度,单位是mm

obj_points = []  # 存储3D点
img_points = []  # 存储2D点

i = 0

def save_calibration_to_yaml(file_path, cameraMatrix_l, distCoeffs_l):
    data = {
        'camera_matrix': {
            'rows': 3,
            'cols': 3,
            'dt': 'd',
            'data': cameraMatrix_l.flatten().tolist()
        },
        'dist_coeff': {
            'rows': 1,
            'cols': 5,
            'dt': 'd',
            'data': distCoeffs_l.flatten().tolist()
        }
    }

    with open(file_path, 'w') as file:
        yaml.dump(data, file, default_flow_style=False)
    print(f"Calibration parameters saved to {file_path}")

for fname in images:
    if not os.path.exists(fname):
        print(f"文件不存在: {fname}")
        continue

    try:
        with open(fname, 'rb') as f:
            print(f"文件正常读取: {fname}")
    except Exception as e:
        print(f"无法读取文件: {fname}, 错误: {e}")
        continue

    img = cv2.imread(fname)
    if img is None:
        print(f"OpenCV 无法读取文件: {fname}")
        continue

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    size = gray.shape[::-1]
    ret, corners = cv2.findChessboardCorners(gray, (w_corners, h_corners), None)

    if ret:
        obj_points.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)
        if [corners2]:
            img_points.append(corners2)
        else:
            img_points.append(corners)

        cv2.drawChessboardCorners(img, (w_corners, h_corners), corners, ret)
        i += 1

        new_size = (1280, 800)
        resized_img = cv2.resize(img, new_size)
        cv2.imshow('img', resized_img)
        cv2.waitKey(150)

print(len(img_points))
cv2.destroyAllWindows()

if len(img_points) > 0:
    # 标定
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)
    save_calibration_to_yaml('calibration_danmu.yaml', mtx, dist)         #改!换成自己yaml文件想要的路径和名字

    print("ret:", ret)
    print("mtx:\n", mtx)
    print("dist:\n", dist)
    print("rvecs:\n", rvecs)
    print("tvecs:\n", tvecs)

else:
    print("没有检测到角点,无法进行相机标定。")

需要更改的地方已在代码中标出。

标定过程中会可视化画了角点连线的图,标定结果会保存到一个yaml文件中:

复制代码
camera_matrix:
  cols: 3
  data:
    - 538.5703097550794
    - 0
    - 638.7847675804244
    - 0
    - 542.6025156738463
    - 419.4305002874007
    - 0
    - 0
    - 1
  dt: d
  rows: 3
dist_coeff_left:
  cols: 5
  data:
    - -0.1879080034212516
    - 0.06154713313351551
    - 4.605878792222752e-05
    - 0.002483271337902348
    - -0.003210439918482585
  dt: d
  rows: 1

其中camera_matrix为相机的内参矩阵,dist_coeff_left为畸变系数,接下来就可以使用这两个参数对图像进行矫正。

②矫正:

复制代码
import cv2
import numpy as np
import glob
import os
import yaml


def load_camera_params_from_yaml(yaml_file):
    with open(yaml_file, 'r') as f:
        calib_data = yaml.safe_load(f)

    camera_matrix = np.array(calib_data['camera_matrix']['data']).reshape(3, 3)
    dist_coeffs = np.array(calib_data['dist_coeff_left']['data'])

    return camera_matrix, dist_coeffs


def cam_calib_correct_img(distort_img_dir, crct_img_dir, cameraMatrix, distCoeffs):
    imgs = glob.glob(os.path.join(distort_img_dir, "*.png"))
    imgs.extend(glob.glob(os.path.join(distort_img_dir, "*.png")))
    imgs.extend(glob.glob(os.path.join(distort_img_dir, "*.bmp")))

    for img_ in imgs:
        print("已读取待校正图像:", img_)
        img = cv2.imread(img_)
        (h1, w1) = img.shape[:2]

        newcameramtx, roi = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, (w1, h1), 1, (w1, h1))

        dst = cv2.undistort(img, cameraMatrix, distCoeffs, None, newcameramtx)

        x, y, w, h = roi
        dst = dst[y:y + h, x:x + w]
        resized_dst = cv2.resize(dst, (w1, h1))

        imgname = os.path.basename(img_).split('.')[0]
        rlt_path = os.path.join(crct_img_dir, imgname + "_crct.png")
        cv2.imwrite(rlt_path, resized_dst)

        print("已保存校正图像:", rlt_path)


if __name__ == "__main__":
    distort_img_dir = 'daijiaozheng'  # 待校正图像的路径
    crct_img_dir = 'jiaozheng_result'  # 保存校正图像的路径
    yaml_file = 'calibration_danmu.yaml'  # YAML文件路径

    cameraMatrix, distCoeffs = load_camera_params_from_yaml(yaml_file)
    cam_calib_correct_img(distort_img_dir, crct_img_dir, cameraMatrix, distCoeffs)

完成后可以在jiaozheng_result文件夹中看到矫正完的图像,现在给出两张照片进行对照:

明显看出畸变减小,可以注意看头顶的线条。

相关推荐
晨间晓15 小时前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭18 小时前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓19 小时前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云
晨间晓19 小时前
二值图里的噪点怎么去掉?用华为云码道开发 OpenCV 形态学操作工具
人工智能·opencv·华为云
晨间晓21 小时前
图片里的角点在哪里?用华为云码道开发 OpenCV Harris 角点检测工具
人工智能·opencv·华为云
晨间晓1 天前
图片细节丰富不丰富?用华为云码道开发 OpenCV 纹理复杂度分析工具
人工智能·opencv·华为云
richard_yuu2 天前
OpenCV 实战第 15 篇:G-API 图计算,工业流水线的 CPU/GPU 混合执行
人工智能·opencv·计算机视觉
老唐7772 天前
OpenCV5实测:纯CPU跑YOLO26目标检测
图像处理·人工智能·opencv·yolo·目标检测·计算机视觉
把我格子衫拿来2 天前
PnP 位姿估计:从二维像素求三维姿态,为什么 tvec 不是相机位置?
python·opencv·计算机视觉·pnp·相机位姿
晨间晓2 天前
图片边缘主要朝哪里?用华为云码道开发 OpenCV 梯度方向分析工具
人工智能·opencv·华为云