机器视觉初步14:相机标定原理及应用

相机标定是指通过已知的相机参数,解算相机内部参数矩阵和外部参数矩阵。
在这里插入图片描述

文章目录

  • 1.为什么要标定?
  • 2.工业场景中常见的标定方法
    • 2.1. 使用棋盘格标定板(Checkerboard Markers)
    • 2.2 使用相机自标定
    • 2.3. 使用三维物体标定
    • 2.4.九孔标定

1.为什么要标定?

在工业中,更多的用户青睐于它在非接触三维尺寸测量上的应用。
所谓的三维测量是广义的三维测量,它不仅包括三维物体的重构与测量,还包括在三维空间中识别任意二维平面上的尺寸以及位置。
这种技术目前已被应用在高精度的工业模具以及装配测量中,其中任意二维平面上的尺寸检测技术应用得更为广泛。

参考文章:相机标定解析
在这里插入图片描述

相机的参数包含内参1和外参2,这些参数是将空间点坐标从相机坐标系转换到像素坐标系所需的。相机标定的目标是获得这些参数,使得我们可以从像素坐标系中的坐标得到图像中的坐标。

为了获取更高的测量精度,我们需要通过标定来实现坐标平面的转换以及图像的校正。
在这里插入图片描述

2.工业场景中常见的标定方法

在工业场景中,相机标定通常采用以下几种方法:

2.1. 使用棋盘格标定板(Checkerboard Markers)

棋盘格标定板是最常见的相机标定方法,它由黑白相间的正方形组成,棋盘格的对角线交点形成一个共用角点。使用棋盘格标定板,可以通过拍摄多张带有棋盘格的图像,并在图像中标记棋盘格的角点,从而计算相机的内外参数。在这里插入图片描述

例如,可以使用一个三维棋盘格标定板(或者投影到一张二维图像上),在相机拍摄的图像中标记棋盘格的角点。然后,通过最小化相机视场中像素坐标和标定板上角点坐标之间的误差来计算相机的内外参数。

import numpy as np
import cv2# 棋盘格尺寸
pattern_size = (9, 6)# 准备棋盘格标定板的世界坐标
objp = np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)# 存储棋盘格角点的世界坐标和图像坐标
objpoints = []  # 世界坐标系中的棋盘格角点
imgpoints = []  # 图像平面中的棋盘格角点# 读取图像
images = ['image1.jpg', 'image2.jpg', 'image3.jpg']  # 替换为实际图像的文件名列表for fname in images:img = cv2.imread(fname)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 查找棋盘格角点ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)# 如果找到棋盘格角点,则添加到objpoints和imgpoints中if ret == True:objpoints.append(objp)imgpoints.append(corners)# 绘制并显示角点cv2.drawChessboardCorners(img, pattern_size, corners, ret)cv2.imshow('img', img)cv2.waitKey(500)cv2.destroyAllWindows()# 相机标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)# 打印相机内参数矩阵和畸变系数
print("相机内参数矩阵:")
print(mtx)
print("\n畸变系数:")
print(dist)

2.2 使用相机自标定

相机自标定方法不需要使用特殊的标定板,而是通过拍摄带有不同纹理和几何形状的物体(如带有条纹的纸张、弯曲的金属片等),然后通过分析相机拍摄的图像来计算相机的内外参数。
例如,可以拍摄一张带有条纹的纸张,并在纸张上的条纹区域和背景区域拍摄多张图像。然后,通过最小化相机视场中像素坐标和条纹区域的边界之间的误差来计算相机的内外参数。

2.3. 使用三维物体标定

使用三维物体标定方法是通过将三维物体投影到二维图像中,然后计算相机的内外参数。这种方法通常用于三维物体的尺寸和形状对于相机的视场而言非常明显的场景。
例如,可以将一个具有不同尺寸和形状的三维物体(如盒子、球体等)放置在相机视场中,并拍摄多张带有该物体的图像。然后,通过最小化相机视场中像素坐标和物体边界之间的误差来计算相机的内外参数。

import cv2
import numpy as np# 读取标定板图像
image = cv2.imread('calibration_image.jpg')# 定义标定板的尺寸
board_size = (9, 6)# 寻找标定板角点
ret, corners = cv2.findChessboardCorners(image, board_size, None)# 如果找到了角点
if ret:# 优化角点位置corners = cv2.cornerSubPix(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), corners, (11, 11), (-1, -1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))# 定义标定板上的三维点object_points = np.zeros((board_size[0] * board_size[1], 3), np.float32)object_points[:, :2] = np.mgrid[0:board_size[0], 0:board_size[1]].T.reshape(-1, 2)# 定义图像上的二维点image_points = corners.reshape(-1, 2)# 进行相机标定ret, camera_matrix, distortion_coefficients, rotation_vectors, translation_vectors = cv2.calibrateCamera([object_points], [image_points], image.shape[::-1], None, None)# 打印相机矩阵和畸变系数print("Camera Matrix:")print(camera_matrix)print("Distortion Coefficients:")print(distortion_coefficients)
else:print("Cannot find chessboard corners in the image.")

2.4.九孔标定

九孔标定(9-cell calibration)是指使用9个像素来检测和标定摄像头的标定方法。
在这里插入图片描述

在计算机视觉领域,这种方法常常被用来进行摄像头畸变校正、图像缩放、图像旋转等操作。下面是用Halcon实现九孔标定的步骤。
步骤1:准备九个像素
确保你有9个像素的图像,这些图像需要覆盖摄像头的每个视野。例如,你可以使用9张标定板(包含9个孔的标定板)的不同视图,或者9张带有9个明显标志的标定板。

步骤2:使用Halcon提供的函数计算图像尺寸
使用rectifyImage函数计算每个图像的像素尺寸。例如,假设你的标定板有500像素宽,500像素高,你可以这样计算:

read_image (Image, 'Calibration_board_images/Calibration_board.png')
get_image_size (Image, Width, Height)
rectify_image (Image, ImageReduced, 'nearest_neighbor', 'true')
dev_display (ImageReduced)

步骤3:调整相机参数
使用set_system函数设置相机参数。例如,你可能需要设置焦距、内径和外径等参数。

set_system ('Display Size', [8, 7])
set_system ('Cursor Size', [3, 4])
set_system ('Image Size', [Width, Height])
set_system ('Display Interval', 1000)

步骤4:使用Halcon的标定工具进行标定
在Halcon中,有一个内置的标定工具,可以自动计算摄像头参数并生成标定板图像。
首先,你需要运行以下代码以启动标定工具:

open_framegrabber ('DirectShow', 1, 1, 0, 0, 0, 0, 'default', 9, -1, -1, 'default', 'false', 0, 0, 'rgb_color', 'false', 1, 'default', [], [], [], [], [], [], [], ptr)
grab_image_start (Image, -1, -1, 'black', -1, 'false')
while (true)grab_image_async (Image, ImageGrabbed, -1, [], [], 'rgb_color', 'false', 'default', 'false')dev_update_window ('off')dev_display (ImageGrabbed)wait_seconds (1)
endwhile
close_framegrabber (ptr)

这段代码将运行标定工具并捕获标定板的图像。标定过程完成后,你可以将标定板图像绘制在标定板上,计算它们的畸变系数,并使用这些参数进行图像畸变校正。
步骤5:使用图像畸变校正
首先,根据你的摄像头配置计算畸变参数。然后,使用Halcon的correct_image_points函数进行图像畸变校正:

read_image (Image, 'Calibration_board_images/Calibration_board.png')
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_color ('red')
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()dev_set_color ('blue')
correct_image_points (Image, 'Default', 'true', 'true', CorrectedImage)
dev_set_color ('red')
dev_display (CorrectedImage)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

这段代码将使用correct_image_points函数对图像进行畸变校正,并将校正后的图像绘制在显示窗口中。
总之,要用Halcon实现九孔标定,你需要准备九张标定板图像,计算图像尺寸,调整相机参数,运行标定工具,然后使用畸变校正算法对图像进行畸变校正。


  1. 相机的内参数(Intrinsic Parameters)是描述相机自身几何特性的参数,包括:
    1.摄像机的主点(Principal Point):也称为摄像机的质心,它是由相机的各轴的中点组成的。
    2.摄像机的基线(Basis Line):也称为摄像机的成像基线,是主点和焦距的连线。
    3.摄像机的光学畸变参数:包括径向畸变(Radial Distortion)、切向畸变(Tangential Distortion)和垂轴畸变(Vertical Distortion)。
    4.焦距(Focal Length):是从摄像机光心到焦平面的距离。
    5.像素单位(Pixel Unit):相机的一个像素代表的实际物理长度。 ↩︎

  2. 相机的外参数(Extrinsic Parameters)是描述相机相对于外部世界的投影关系的参数,包括:
    1.旋转矩阵(Rotation Matrix):用于描述摄像机绕着某一坐标轴旋转的参数。
    2.平移矩阵(Translation Matrix):用于描述摄像机在某一位置的平移变换的参数。
    3.畸变参数:径向畸变参数、切向畸变参数和垂轴畸变参数。
    4.畸变系数(Distortion Coefficients):径向畸变参数、切向畸变参数和垂轴畸变参数的组合。 ↩︎

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

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

相关文章

【Linux】—— 进程的创建和退出

序言: 在上期,我们已经对 Linux的进程的相关知识进行了相关的学习。接下来,我们要学习的便是关于进程控制 的基本知识!!! 目录 (一)进程创建 1、fork函数初识 2、写时拷贝 3、f…

Vue中一个新闻类型的弹框Demo

1.设计弹框组件 首先&#xff0c;创建一个名为NewsPopup的弹框组件&#xff0c;用于显示新闻内容。组件的模板包括一个标题和新闻列表。 <template><div class"news-popup"><h2>{{ title }}</h2><ul><li v-for"news in newsL…

Docker中容器数据卷

容器数据卷 一.什么是容器数据卷二.使用数据卷方式一&#xff1a;直接使用命令来挂载 -v 三.具名和匿名挂载 一.什么是容器数据卷 docker理念 将应用和环境打包成一个镜像&#xff01; 数据&#xff1f;如果数据都在容器中&#xff0c;那么我们的容器删除&#xff0c;数据就会…

【Linux操作系统】Ubuntu和center两个Linux发行版本中指令的区别

Ubuntu和center是Linux的两个发行版本&#xff0c;本文将详细介绍两个发行版的使用命令区别&#xff0c;分析两者的优缺点。 文章目录 常见的区别&#xff1a;细节差异&#xff1a;两个发行版本各自的优点和缺点Ubuntu 的优点&#xff1a;Ubuntu 的缺点&#xff1a;CentOS 的优…

Vue中的组件渲染

在Vue中&#xff0c;组件的被渲染意味着将组件的内容转换为真实的DOM元素并添加到页面上。当Vue应用启动时&#xff0c;根组件会被渲染&#xff0c;并递归地渲染其子组件。 当组件被渲染时&#xff0c;Vue会将组件的模板解析成虚拟DOM&#xff08;Virtual DOM&#xff09;的形…

oracle 19c打补丁遭遇OPATCHAUTO-72043OPATCHAUTO-68061

最近&#xff0c;在AIX上的新装oracle 19C数据库基础版本&#xff0c;使用opatchauto打PSU补丁集35037840时遇到了OPATCHAUTO-72043报错&#xff0c;无法正常应用GI补丁。 一、环境描述 操作系统&#xff1a;AIX 数据库版本&#xff1a;oracle rac 19.3.0新装基础版 应用PS…

2023拒绝内卷!两年转行网络安全真实看法!

我目前转行网络安全两年&#xff0c;没啥天分&#xff0c;全靠努力&#xff0c;基本能够得上中级的水平了。看到大家对转行网络安全挺感兴趣&#xff0c;也有挺多争议&#xff0c;想把我的建议和经验告诉大家。 有很多人觉得网络安全已经饱和了&#xff0c;现在选择这个工作&a…

Spring Boot : ORM 框架 JPA 与连接池 Hikari

数据库方面我们选用 Mysql &#xff0c; Spring Boot 提供了直接使用 JDBC 的方式连接数据库&#xff0c;毕竟使用 JDBC 并不是很方便&#xff0c;需要我们自己写更多的代码才能使用&#xff0c;一般而言在 Spring Boot 中我们常用的 ORM 框架有 JPA 和 Mybaties &#xff0c;本…

面试之多线程案例(四)

1.单例模式 单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时&#xff0c;为了防止频繁地创建对象使得内存飙升&#xff0c;单例模式可以让程序仅在内存中创建一个对象&#xff0c;让所有需要调用的地方都共享这一单例对象。…

【洛谷 P5707】【深基2.例12】上学迟到 题解(时间计算)

【深基2.例12】上学迟到 题目描述 学校和 yyy 的家之间的距离为 s s s 米&#xff0c;而 yyy 以 v v v 米每分钟的速度匀速走向学校。 在上学的路上&#xff0c;yyy 还要额外花费 10 10 10 分钟的时间进行垃圾分类。 学校要求必须在上午 8:00 \textrm{8:00} 8:00 到达&…

[React]生命周期

前言 学习React&#xff0c;生命周期很重要&#xff0c;我们了解完生命周期的各个组件&#xff0c;对写高性能组件会有很大的帮助. Ract生命周期 React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁 初始化 1、getDefaultProps() 设置默认的props&#xff0c;也可以用duf…

【数据结构】实现单链表的增删查

目录 1.定义接口2.无头单链表实现接口2.1 头插addFirst2.2 尾插add2.3 删除元素remove2.4 修改元素set2.5 获取元素get 3.带头单链表实现接口3.1 头插addFirst3.2 尾插add3.3 删除元素remove3.4 判断是否包含元素element 1.定义接口 public interface SeqList<E>{//默认…

关于拓扑排序

又重新学了一下拓扑排序&#xff0c;这次发现就十分简单了&#xff0c;拓扑排序的步骤 1.他必须是一个有向无环图&#xff0c;起点我们就是入度为0的点 2.我们首先要输出的就是入度为0的点&#xff0c;然后依次删除这些点连向的点&#xff0c;使这些点的入度-1&#xff0c;如果…

ubuntu 有 1 个软件包没有被完全安装或卸载

ubuntu 有 1 个软件包没有被完全安装或卸载&#xff0c;安装时出现问题&#xff0c;一直卡在 rti-connext-dds-5.3.1 安装问题上。 下面是我安装 sqlite3 出现的问题&#xff1a; sukaiG7-7500:~/1/111/workspace_ros_car_noetic$ sudo apt-get install sqlite3 正在读取软件…

Java集合数组相互转换

1.集合转换成数组 &#xff08;1&#xff09;集合a通过toArray()方法进行转换为数组&#xff0c;可以转换成为指定类型的数组&#xff0c;但是这些类型都必须是object类型的子类&#xff0c;基本类型不可以。 必要时我们使用强制类型转换&#xff0c;转成我们需要的类型。 Li…

运维工程师第二阶段linux基础

文章目录 linux基础1.linux发展史--前身unix2.linux特点3.linux操作系统安装4.linux基础操作5.shell与终端6.Linux基础命令使用管理员找回密码linux的目录和管理1.根目录下目录结构及作用文件类型2.基本的目录管理命令查看基本的文件管理命令重定向① 几个概念② Linux打包操作…

葡萄叶病害数据集

1.数据集 分成训练集和测试集 训练集有四个文件夹 第一个文件夹为 Grape Black Measles&#xff08;葡萄黑麻疹&#xff09;病害&#xff08;3783张&#xff09; Grape Black rot葡萄黑腐病病害数据集&#xff08;3596张&#xff09; Grape Healthy 健康葡萄叶&#xff08;25…

Maven项目解决cannot resolve plugin maven-deploy-plugin:2.7

导入maven项目后&#xff0c;编辑的时候提示一些插件加载失败&#xff01;大概率是你的网络有问题&#xff0c;插件下载失败。 如下图&#xff1a;&#xff08;网络突然好了&#xff0c;我想截图但是没有复现&#xff0c;用网上找到的截图代替&#xff0c;明白意思就行&#x…

解决外部主机无法访问Docker容器的方法

使用Docker启动了一个tomcat容器&#xff0c;并做了端口映射&#xff0c;但是外部主机仍然无法访问。 编辑centos上的配置文件 vi /etc/sysctl.conf net.ipv4.ip_forward1 systemctl restart network保存以后即可生效&#xff0c;这个配置是开启linux的ip数据包转发功能&#…

Anaconda创建虚拟环境

参考文章 1 Win10RTX3060配置CUDA等深度学习环境 pytorch 管网&#xff1a;PyTorch 一 进入 Anaconda 二 创建虚拟环境 conda create -n pytorch python3.9注意要注意断 VPN切换镜像&#xff1a; 移除原来的镜像 # 查看当前配置 conda config --show channels conda config…