【相机与图像】2. 相机内外参的标定的代码示例

news2024/9/24 7:22:42

1 摄像头内参的标定

【相机标定具体操作】
使用将要标定的摄像头,以不同的角度采集棋盘格,要保证视野内出现完整的棋盘格。采集图片数量约15张左右即可。
以11*8的棋盘格为例,具体流程如下:

  • step 1. 设置棋盘格3D点;通过opencv角点检测获取2D点的坐标
    • 3D的点的生成:在每张图片上,共存在11*8个角点存在。每张图存在自己的世界坐标系,是以右上角(长边为底边)为3D坐标原点,所以在代码中需要生成一个shape=(11*8,3) 的numpy数组。存放着世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) …,(8,5,0)…。关键api:np.mgrid
    • 图片上的2D角点检测:该工作在opencv提供了对应的api直接调用即可,对应api为cv2.findChessboardCorners。也可以进一步进行角点精确化检测,对应api为 cv2.cornerSubPix
  • step 2. 估计相机内参,可得到相机内参和畸变参数
    • 对应api为 cv2.calibrateCamera
  • step 3. 反投影,计算误差。若误差大于一定阈值,则重新采集图片进行标定
    • 对应api为 cv2.projectPoints
  • step 4. 利用相机内参去畸变,并显示
    • 对应api为 cv2.undistort

摄像头捕获的用于标定的图片
在这里插入图片描述
然后角点检测可视化图片在这里插入图片描述


具体代码的实现如下:

' ''
step 1. 设置棋盘格3D点;通过opencv角点检测 获取2D点
step 2. 估计相机内参
step 3. 反投影,计算误差
step 4. 利用相机内参去畸变,并显示
'''

import os
import cv2
import glob
import numpy as np

path_image = "L:/WORKFILE/calibration-master/data_own/calib_image_1"
image_namelist = glob.glob(os.path.join(path_image, "*.png"))


criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
chess_board_w = 11
chess_board_h = 8

### step 1. 设置3D点;通过角点检测获取2D点=============================================== 
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0)
chess_points = np.zeros((chess_board_w * chess_board_h, 3), np.float32)
chess_points[:, :2] = np.mgrid[0:chess_board_w, 0:chess_board_h].T.reshape(-1, 2)
# chess_points = chess_points * 0.03 # 每个格子3cm

world_points = [] # 在世界坐标系中的3D点
image_points = [] # 在图像平面的2D点
for image_name in image_namelist:
    image = cv2.imread(image_name)
    if len(image.shape) == 3: gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 找到棋盘格角点
    # 入参为:棋盘图像(8位灰度或彩色图像)、棋盘尺寸、存放角点的位置
    finded, corners = cv2.findChessboardCorners(gray, (chess_board_w, chess_board_h))
    if finded == True:
        world_points.append(chess_points)
        image_points.append(corners)
    # if finded == True:
    #     # 角点精确检测,可选择使用
    #     # 入参为:输入图像、角点初始坐标、搜索窗口为2*winsize+1、死区、求角点的迭代终止条件
    #     corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
    #     # 将角点在图像上显示
    #     cv2.drawChessboardCorners(image, (chess_board_w, chess_board_h), corners2, finded)
    #     image_copy = cv2.resize(image, (500,500))
    #     cv2.imshow('image', image_copy)
    #     cv2.waitKey(10) 
    #     cv2.destroyWindow('image')

### step 2. 估计相机内参,并更新yaml文件=============================================== 
image_size = cv2.cvtColor(cv2.imread(image_namelist[0]), cv2.COLOR_BGR2GRAY).shape[::-1] # (H, W)        
_, inter_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(world_points, image_points, image_size, None, None)
# inter_matrix:相机内参; dist_coeffs:相机畸变系数; rvecs:旋转向量 (外参数); tvecs :平移向量 (外参数)
print("相机内参矩阵\n", inter_matrix, "\n畸变参数:\n", dist_coeffs)


### step 3. 反投影,计算误差=============================================== 
# 通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。
# 通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,
# 然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。
mean_error = 0
for i in range(len(world_points)):
    imgpoints2, _ = cv2.projectPoints(world_points[i], rvecs[i], tvecs[i], inter_matrix, dist_coeffs)
    error = cv2.norm(image_points[i], imgpoints2, cv2.NORM_L2)/len(imgpoints2)
    mean_error += error
print( "total error: {}".format(mean_error/len(world_points)) )


### step 4. 利用相机内参去畸变,并显示=============================================== 
#cap = cv2.VideoCapture(0)
while 1:
    frame = cv2.imread("L:/WORKFILE/calibration-master/detect1.jpg")
    # _, frame = cap.read() ## 从摄像头中捕获图片

    # 我们已经得到了相机内参和畸变系数,在将图像去畸变之前,
    # 我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,
    # 通过设定自由自由比例因子alpha。当alpha设为0的时候,
    # 将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;
    # 当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉
    ##
    ## cv2.undistort函数通过给定的相机矩阵(camera matrix)和畸变系数(distortion coefficients),
    ## 可以计算出原始畸变图像中每个像素点在无畸变图像中的正确位置,并据此对图像进行校正
    h,  w = frame.shape[:2]
    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(inter_matrix, dist_coeffs, (w,h), 1, (w,h))
    undistorted = cv2.undistort(frame, inter_matrix, dist_coeffs, None, newcameramtx)
    x, y, w, h = roi
    cv2.rectangle(undistorted, (x,y),(x+w,y+h),(255,0,255),2)

    mat = np.concatenate((frame, undistorted), axis=1)
    image_copy = cv2.resize(mat, (500*2,500))
    windows_name = "Left: Origin | Right: Undistorted"
    cv2.imshow(windows_name, image_copy)
    key = cv2.waitKey(1)
    if key == 27 or key & 0xFF == ord("q"):
        cv2.destroyWindow(windows_name)
        break

2 摄像头外参的标定

外参标定,可以用opencv中提供的 cv2.solvePnP 进行估计。

import os
import cv2
import glob
import numpy as np

##==step1: 给定标定的相机内参、图片上的2D坐标、以及对应的世界坐标系下的3D坐标
dist_coeffs = np.array([[ 1.26656599e-01, -8.62714566e-01,  1.95000458e-03, -6.37704248e-04,  1.11050691e+00]])
inter_matrix = np.array([[713.85537736,   0.          , 329.50142968],
                         [0.          ,   714.28046903, 235.29954597],
                         [0.          ,   0.          ,   1.        ]])
## 世界坐标系下的坐标
objPoints = np.array([[-0.25, -0.25, 0.], 
                      [-0.25,  0.25, 0.], 
                      [ 0.25,  0.25, 0.], 
                      [ 0.25, -0.25, 0.]]) 
## 像素坐标系下的坐标
marker_corner = np.array([[[52,  443],  # [x, y]
                           [124, 339],
                           [244, 358],
                           [197, 470]]], dtype=np.float32)

##==step2. 使用 cv2.solvePnP 计算对应的外参
valid, rvec_obj, tvec_obj = cv2.solvePnP(objPoints, marker_corner, cameraMatrix=inter_matrix, distCoeffs=dist_coeffs)
print(rvec_obj)
print(tvec_obj)

##==step3. 使用相机内外参,将3D的点转换为2D坐标
points_3d = np.float32([[0, 0, 0]])
imgpts, jac = cv2.projectPoints(points_3d, rvec_obj, tvec_obj, inter_matrix, dist_coeffs)

##==step4. 2D坐标可视化
frame = cv2.imread("L:/WORKFILE/calibration-master/detect1.jpg")
for pt in imgpts[:,0,:].astype(int):
    cv2.circle(frame, (pt[0], pt[1]), 5, (255, 0, 255), -1)
for pt in marker_corner[0].astype(int):
    cv2.circle(frame, (pt[0], pt[1]), 5, (0, 0, 255), -1)

cv2.imshow('result', frame)
cv2.waitKey(0)


## undistort,这里使用不到
# height_img, width_img = frame.shape[:2]
# newcameramtx, roi = cv2.getOptimalNewCameraMatrix(inter_matrix, dist_coeffs, (width_img, height_img), 1, (width_img, height_img))
# newcam_mtx = newcameramtx
# dst = cv2.undistort(frame, inter_matrix, dist_coeffs, None, newcameramtx)
# x, y, w, h = roi
# frame = dst[y:y+h, x:x+w]

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2033798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MapReduce_Writable序列化

使用序列化封装对象 将输入的csv按照员工号拆分成每个员工&#xff0c;每个员工存储为员工对象 数据处理过程 employee_noheader.csv 1,ZhangSan,101,5000 2,LiSi,102,6000 3,WangWu,101,5500 4,ZhaoLiu,103,7000 5,SunQi,102,6500pom.xml <?xml version"1.0&qu…

ctfshow-web入门-sql注入(web201-web205)系统练习sqlmap的使用

目录 1、web201 2、web202 3、web203 4、web204 5、web205 开始系统练习sqlmap的使用 1、web201 随便提交一个看下它调用的接口和请求的参数有哪些 可以看到 URL 为&#xff1a; https://32c7d026-d195-4074-a0f9-492c17dc1a2c.challenge.ctf.show/api/?id1&page1&…

微信答题小程序产品研发-前端开发

开发一款答题小程序界面&#xff0c;涉及到的技术栈&#xff0c;主要包括微信小程序的WXML、WXSS、JavaScript等。 由于时间有限&#xff0c;我先大致记录一下各个功能模块的基本开发概要&#xff0c;后面有空了再详细整理&#xff0c;分享给大家。 1. 首页 &#xff08;1&am…

Windows网络重置后无法连接网络

Windows网络重置后重启电脑无法连接到网络 打开命令提示符快捷键winR输入msconfig点击确定 在系统配置中找到服务先全部禁用&#xff0c;在全部启用&#xff0c;点击应用后重启电脑就可以了

LVS的简单配置及对Mysql主从复制的补充

Day 22 LVS的配置 环境准备 DSN() 用来解析各主机的域名和ip地址&#xff0c;配置域名解析huajuan&#xff0c;负责管理其他主机 web1--->web1.tangpin.huajuan web2--->web2.tangpin.huajuan dns--->dns.tangpin.huajuan web1(192.168.2.200) 用nginx…

解决 MacOS 连接公司 VPN 成功但是不能网络的问题

目录 解决办法2024 Mac mini 爆料 解决办法 操作比较简单&#xff0c;修改配置文件即可&#xff08;如果没有则需要手动创建&#xff09;。 sudo vim /etc/ppp/options在此文件下&#xff0c;加入 plugin L2TP.ppp&#xff1a; plugin L2TP.ppp如果文件里有l2tpnoipsec&…

基于ESP32的智能门锁系统测试

项目介绍 基于ESP32的智能门锁系统。可以运用在商务办公、家用住宅、酒店以及公租房短租公寓等领域。基于esp32的智能门锁系统是生物识别技术和嵌入式系统技术的完美结合&#xff0c;基于ESP32系统进行开发&#xff0c;同时在云端服务器搭建了MQTT服务器并连接开源的家庭自动化…

Apple Intelligence 最詳細解說

Apple Intelligence究竟是什麼&#xff1f; 顧名思義&#xff0c;Apple Intelligence就是Apple獨家開發的 AI 模型&#xff08;深度整合至 iOS 18、iPadOS 18 和 macOS Sequoia&#xff09;&#xff0c;旨在透過理解和生成語言和圖像、解讀上下文&#xff0c;並在特定App中執行…

【计算机网络】UDP实战

其实经过这几天写的几种不同的UDP的简易客户端与服务端&#xff0c;还是很有套路的&#xff0c;起手式都是非常像的。 更多的难点对我来说反而是解耦&#xff0c;各种各样的function一用&#xff0c;回调函数一调&#xff0c;呕吼&#xff0c;就会懵一下。 对于这篇文章&#x…

成功解决7版本的数据库导入 8版本数据库脚本报错问题

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…

大数据面试SQL(七):累加刚好超过各省GDP40%的地市名称

文章目录 累加刚好超过各省GDP40%的地市名称 一、题目 二、分析 三、SQL实战 四、样例数据参考 累加刚好超过各省GDP40%的地市名称 一、题目 现有各省地级市的gdp数据,求从高到低累加刚好超过各省GDP40%的地市名称&#xff0c;临界地市也需要。 例如&#xff1a; 浙江省…

设计模式-延迟加载(Lazy Load)

概念 一个对象&#xff0c;它虽然不包含所需要的所有数据&#xff0c;但是知道怎么获取这些数据。 加载一个对象会引起大量相关对象的加载&#xff0c;这样会损害系统的性能。延迟加载会暂时终止这个加载过程。 运行机制 四种实现延迟加载的方法&#xff1a; 延迟初始化&am…

ThreadLocal —— 让每个线程拥有自己的变量副本

在多线程编程中&#xff0c;数据共享是一个常见的话题。很多时候我们需要多个线程共享同一个数据&#xff0c;以实现数据的一致性和通信。然而&#xff0c;在一些场景下&#xff0c;我们并不希望数据被多个线程共享&#xff0c;而是希望每个线程都拥有自己独立的一份数据。这时…

【C++类和对象(中)】—— 我与C++的不解之缘(四)

前言&#xff1a; 接下来进行类和对象中的学习&#xff0c;了解类和对象的默认成员函数 一、类和对象默认成员函数 默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数。 一个类&#xff0c;我们不显示实现的情况下&#xff0c;编译器就会默认生成一下留…

无人机开启农林植保新篇章

嘿&#xff0c;小伙伴们&#xff0c;你们知道吗&#xff1f;无人机已经悄悄在农业领域大展拳脚&#xff0c;成为现代农业的“黑科技”新宠儿啦&#xff01; 想象一下&#xff0c;广袤的田野上空&#xff0c;无人机如同勤劳的蜜蜂&#xff0c;精准高效地完成着各项任务&#xff…

unity 使用 compute shader的步骤

这里详细的记载使用步骤&#xff0c;我这个例子是让一个立方体上下不停的动 创建一个compute shader 一个普通shader 一个材质 一个C# 先挨个写上类容 这里kernel 指定main函数入口&#xff0c;RWStructuredBuffer就是数组&#xff0c;具体size是在外部指定的&#xff0c;可能…

C#使用CEFSharp获取动态网页源码

CEF 全称是Chromium Embedded Framework&#xff08;Chromium嵌入式框架&#xff09;&#xff0c;是个基于Google Chromium项目的开源Web browser控件&#xff0c;支持Windows, Linux, Mac平台。CEFSharp就是CEF的C#移植版本。 访问以下链接可以获取CEF的详细介绍 chromiumem…

c++版opencv长文指南

c版opencv长文指南 1、配置opencv库1.1 下载1.2 配置1.2.1 配置包含目录1.2.2 配置库含目录1.2.3 配置链接器1.2.4 配置系统环境变量 2、学习路线3、入门知识3.1 图像读取与显示3.2 图像色彩空间转换3.2 图像对象的创建与赋值3.2.1 图像对象的创建3.2.2 图像对象的赋值 3.3 图像…

轻松搞定小程序生成短链接/二维码,你学会了吗?

朋友们&#xff0c;大家有没有遇到过这样的困扰&#xff1a;小程序由于不是链接&#xff0c;在短信或者其他平台里根本没法推广&#xff0c;导致小程序的用户量很难涨起来。 那小程序转成链接真的就没办法实现吗&#xff1f;当然不是&#xff01; 现在有一款超实用的工具——…

zigbee笔记:十、ZStack(2.3.0-1.4.0)的OSAL使用分析

zigbee笔记&#xff1a;九中&#xff0c;我们已经学会了利用模板&#xff0c;定制自己的个性开发工程&#xff0c;本文为协议栈&#xff08;ZStack-CC2530-2.3.0-1.4.0&#xff09;代码使用分析笔记&#xff0c;来进一步掌握协议栈的使用。 一、协议栈使用知识点 1、协调器、路…