【摄像头标定】单目摄像头标定及矫正-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文件夹中看到矫正完的图像,现在给出两张照片进行对照:
在这里插入图片描述
在这里插入图片描述
明显看出畸变减小,可以注意看头顶的线条。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要进行相机标定的目的是为了去掉相机透镜畸变,使拍摄的图像更加准确,对于使用opencv库的python用户来讲,相机标定也是一项常规操作。以下是python-opencv相机标定的教程: 1. 收集标定图片:准备至少10到20张不同角度和位置的图片,要保证图片中有棋盘格子等模板。 2. 提取角点特征:用cv2.findChessboardCorners()函数提取棋盘格子的角点,这里用到的是cv2自带的提取工具。 3. 标定镜头:用cv2.calibrateCamera()函数对相机进行标定,得出相机内参矩阵等相关参数。 4. 存储标定结果: 使用cv2.FileStorage()函数存储标定参数。 5. 测试标定结果:使用cv2.undistort()函数果进行畸变校正,并观察校正后的图像是否有改善。 6. 应用标定结果:将标定结果应用到实际项目中,在程序中调用标定参数可以有效降低图像畸变,提高图像质量。 以上是python-opencv相机标定的教程,如果有需要的话,还可以使用均匀灰度图像等其他方式进行标定。通常情况下,一次标定的结果可以使用长时间,从而提高整个项目的精确度。 ### 回答2: Python-OpenCV相机标定教程是小型项目的标准。 在机器视觉和计算机视觉中,相机标定非常重要,这是获取全面、准确的数据的基础。相机标定的目的是为了减少照相机视角失真,提高拍摄到的图像质量,从而更好地支持照相机的图像处理。它的主要目的是矫正图像中的畸变并确定相机的内参和外参。 Python-OpenCV相机标定教程可以在Python编程语言中使用OpenCVPython库实现。这个过程包括多个步骤,如获取棋盘格角点、标定相机、计算相机的投影矩阵等。 在相机标定过程中,需要拍摄多张棋盘格图像。首先,必须定义棋盘格行列数量,然后手动测量棋盘格方格大小并加载图像到OpenCVPython中。接下来,寻找图像中棋盘格的角点,这些角点可以被处理以消除任何镜头失真。使用这些图像来标定相机并计算相机的投影矩阵。最后,保存相机内参和外参以对未来的图像应用重新计算。 相机标定的作用是消除由透视等导致的图像质量降低,从而使图像更清晰、更准确。Python-OpenCV相机标定教程为开发者提供了实现相机标定的基础,使他们可以快速构建照相机内参与外参算法并为数据处理提供基础。 ### 回答3: Python-OpenCV相机标定教程 OpenCV是一种非常流行的计算机视觉库,具有许多强大的功能,包括相机标定相机标定是将相机的内部参数和畸变参数计算出来,以便更好地将2D图像转换为3D场景。在此教程中,我们将介绍使用Python-OpenCV库进行相机标定的步骤。 第一步:获取棋盘格图像 在进行相机标定之前,需要获取一些棋盘格图像。为了获得尽可能准确的结果,您需要将棋盘格图像从不同的角度和位置拍摄,并确保棋盘格图像足够清晰。我们建议至少拍摄10张不同的图像。 第二步:检测棋盘格角点 使用OpenCV中的函数cv2.findChessboardCorners()可以检测棋盘角点。它需要棋盘的大小和图像。如果检测到角点,函数将返回True,并将角点位置存储在一个数组中。 第三步:计算相机内部参数和畸变参数 为了计算相机的内部参数和畸变参数,需要使用OpenCV中的函数cv2.calibrateCamera()。这个函数接受一个由棋盘格图像和对应的角点位置组成的列表,并返回摄像机矩阵,畸变系数和旋转矩阵。 第四步:评估相机标定结果 在评估相机标定结果时,您需要计算误差,这可以通过一个简单的公式完成。误差是指每个棋盘格角点的图像坐标和标准(真实)坐标之间的平均距离。您还可以使用OpenCV可视化函数来显示标定结果。 总结 这就是使用Python-OpenCV进行相机标定的基本步骤。相机标定是一个基本任务,但是它对于实现更复杂的计算机视觉任务非常重要。标定成功后,您可以更准确地进行2D到3D坐标的变换,从而实现更准确的跟踪和测量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值