当前位置: 首页 > news >正文

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

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 nppath_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 # 每个格子3cmworld_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 = roicv2.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]

在这里插入图片描述

相关文章:

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

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

重启人生计划-拒绝内耗

🥳🥳🥳 茫茫人海千千万万,感谢这一刻你看到了我的文章,感谢观赏,大家好呀,我是最爱吃鱼罐头,大家可以叫鱼罐头呦~🥳🥳🥳 如果你觉得这个【重启人生…...

盘点电脑开机慢的几大高频原因

常规的话一台电脑正常我们都要用个2年以上的时间,有的可能更长,5年的都有,而电脑目前占多数的主流操作系统就是微软的Windows。那么随着使用年限的增加,无论是系统还是电脑硬件,都会随着使用次数和使用的时间的增加而有损耗,系统软件上就是文件越来越臃肿,空间越来越小,…...

2-64 基于matlab的Consensus-Based Bundle Algorithm (CBBA)算法

基于matlab的Consensus-Based Bundle Algorithm (CBBA)算法,可为异构代理网络上的多代理多任务分配问题提供良好的解决方案。支持具有有效时间窗口的任务、异构代理-任务兼容性要求,以及平衡任务奖励和燃料成本的得分函数。奖励和燃料成本的分数函数。程…...

Win10 去掉桌面右上角 了解有关此图片的信息

1. 进入注册表 Win R运行regedit 2. 找到以下路径 计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel 3. 新建 DWORD(32位)值(D) 右击 NewStartPanel新建 DWORD…...

tcpdump入门——抓取三次握手数据包

1. 使用docker启动一个tcp应用 参考:https://blog.csdn.net/LONG_Yi_1994/article/details/141175526 2. 获取容器id docker ps |grep gochat 3. 获取容器的 PID 首先,你需要获得容器的进程 ID(PID)。可以使用 docker inspect…...

漏洞复现-GitLab任意读取文件(CVE-2023-2825)

1.漏洞描述 GitLab是一个用于仓库管理系统的开源项目,其使用Git作为代码管理工具,可通过Web界面访问公开或私人项目。据悉,该漏洞影响 GitLab社区版(CE)和企业版(EE)的 16.0.0 版本,其它更早的版本几乎都不受影响。 该漏洞存在于GitLab CE/EE版本16.0.0…...

二叉树——9.找树左下角的值

力扣题目链接 给定一个二叉树,在树的最后一行找到最左边的值。 示例: 输出:7 题干很简单,找到树的最后一行,在该行找到最左边的值,结合完整代码进行分析。 完整代码如下: class Solution:d…...

如何用github制作个人网站

这里整理了一些参考资料。总结来说,如果系统学过html网页制作的话,可以不用看这篇博客了;这里适合于小白,就是那种 没有做过网页、打算以别人优秀的个人主页为框架做网页的小白。 一、简单说明 这是利用github.io来制作网页的&a…...

二.PhotoKit - 相册权限(彻底读懂权限管理)

引言 用户的照片和视频算是用户最私密的数据之一,由于内置的隐私保护功能,APP只有在用户明确授权的前提下才能访问用户的照片库。从iOS14 开始,PhotoKit进一步增强了用户的隐私控制,用户可以选择指定的照片或者视频资源的访问权限…...

二叉树------最小堆,最大堆。

什么是最小堆: 堆是一种二叉树,最小堆中所有父亲节点的值都要比自己的子节点的值要小。而根节点称为堆顶。根据定义我们可以得到堆中最小元素就在堆顶。(节点左上角是编号,内部是元素值) 假设该图中的堆顶元素是24呢&a…...

预约功能的知识整理

前置知识 如果项目为小程序的开发项目中: 我们确定数据库中有的字段有: 预约人姓名、手机号、家人名称、预约时间 根据我们的经定一表必须要有的6个字段: 主键、创建时间、修改时间、创建人、修改人、备注 使用我们现在有的字段为: 主键…...

Linux的常用操作-02

一:Linux的系统目录结构 /bin bin是ary的缩写,这个目录存放着最经常用的命令 /boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。 /dev:dev是Device(设备)的缩写,该目录下存放的是Lin…...

Android Studio 连接手机进行调试

总所周知,Android Studio里的虚拟手机下载后又大又难用。不如直接连手机用。本篇文章主要内容为Android Studio怎么连接手机进行程序调试。 1. 在AndroidSDK中下载google USB Driver: 2. 连接手机: 进入电脑设备管理器界面。并点开便携设备&#xff0c…...

Vue3项目创建及相关配置

Vue是一种用于构建用户界面的JavaScript框架。它采用了一种称为MVVM(Model-View-ViewModel)的架构模式。 MVVM是一种将用户界面与业务逻辑和数据分离的设计模式。它包括三个部分: Model(模型):表示应用程序…...

【Python】Python中一些有趣的用法

Python是一种非常灵活和强大的编程语言,它有很多有趣的用法,以下是一些例子: 一行代码实现FizzBuzz: print(\n.join([FizzBuzz[i%3*4:i%5*8:-1] or str(i) for i in range(1, 101)]))使用列表推导式生成斐波那契数列: …...

RCE复现问题和研究

目录 先了解一些常见的知识点 PHP常见命令执行函数 call_user_func eval() call_user_func_array array_filter 实战演练(RCE)PHP Eval函数参数限制在16个字符的情况下 ,如何拿到Webshell? 1、长度…...

MySQL中的索引——适合创建索引的情况

1.适合创建索引的情况 1、字段的数值有唯一性的限制 2、频繁作为 WHERE 查询条件的字段 某个字段在 SELECT 语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率。 …...

5款在线伪原创改写软件,智能改写文章效果好

在这个信息爆炸的时代,内容创作变得愈发重要,而对于创作者来说,有时需要一些得力的伪原创改写工具来辅助我们更好地改写出高质量的内容。今天我要和大家分享5款令人惊喜的在线伪原创改写软件,它们以出色的智能改写效果&#xff0c…...

opencv-python图像增强四:多曝光融合(方法一)

文章目录 一、简介:二、多曝光融合方案:三、算法实现步骤3.1 读取图像与曝光时间:3.2 计算响应曲线并合并3.3 色调映射 四:整体代码实现五:效果 一、简介: 在摄影和计算机视觉领域,高动态范围&…...

idea大量爆红问题解决

问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

2025季度云服务器排行榜

在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...