首先,我们将讨论传感器校准,也就是说,从几何形状,失真和噪声方面校准相机如何看待周围的世界。了解相机的校准对于了解测量数据如何代表实际物理环境至关重要。
之后,我们将讨论过滤数据。
对于3D点云,大多数数据实际上对应于不需要的背景对象或其他必须过滤掉的对象,然后才能执行对象检测或识别。
最后,我们将介绍分段,这是将经过过滤的点云数据分解为有意义的片段的过程,每个片段都对应于数据中的一个对象或一组对象。
我们将使用“随机样本共识”或RANSAC算法,这是在存在噪声或异常高级数据的情况下执行细分的强大方法。
要校准相机,我们需要测量世界上的3D点如何向下映射到相机的2D图像平面上。实际上,这是一个相当复杂的过程,但是在接下来的这些练习中,我们将使用一些的OpenCV工具使其变得简单。
第一步是选择校准图案。我们使用以下棋盘样式:
棋盘并不是测试图案的唯一选择,它可以是由其他一些简单形状(例如圆形)组成的图案。无论使用哪种形状,测试图案的目的都是提供一种已知的几何形状,您可以使用相机拍摄该图像,并在将3D世界点映射到2D图像点时用作参考。
下一步是打印出测试图案并为其拍照!您可以固定照相机的位置并在场景中四处移动测试图案,也可以固定照相机的位置并在场景中四处移动相机以从不同角度和距离拍摄照片。
在这里,测试图案每个正方形为10cm x 10cm,并将其粘贴到墙上,从各个方面拍摄了如下照片:
一旦获得测试图案的图像,首先需要在每个图像中找到测试图案。
使用OpenCV功能findChessboardCorners()
和drawChessboardCorners()
在棋盘图案的图像上自动找到并绘制“内角”。
要了解有关这两个功能的更多信息,可以在此处查看OpenCV文档:cv2.findChessboardCorners()和cv2.drawChessboardCorners()。
将这两个功能应用于样本图像,将获得如下结果:
计算任何给定行中的内角数,然后在变量中输入该值nx。同样,计算给定列中的角数并将其存储在中ny。请记住,内角仅是两个黑色和两个白色正方形相交的点,换句话说,仅计算内角,而不计算外角。
import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import glob# #准备对象点
nx = 8 # TODO: 在x中输入内边角的数量
ny = 6 # TODO: 在y中输入内边角的数量img = cv2.imread('chessboardpattern.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 转换为灰度
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
cv2.imshow('iamge', img)
# 找到棋盘的角
ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)# 如果找到,画角
if ret == True:# 绘制和显示角cv2.drawChessboardCorners(img, (nx, ny), corners, ret)# 使用cv2进行输出cv2.imshow('coners', img)# 使用plt进行输出plt.imshow(img)plt.show()cv2.waitKey()
输出如下:
在示例程序中,我们使用了Opencv进行校准,所用到的函数为:cv2.findChessboardCorners
,这个函数可以用来寻找棋盘图的内角点位置。通常作为我们使用Opencv校准的第一步。
然后我们可以使用cv2.calibrateCamera()
计算校准矩阵和失真系数。然后使用cv2.undistort()
函数使测试图像不失真。
关于cv2.calibrateCamera()
的使用方法:
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, (img.shape[1], img.shape[0]), None, None)
我们需要关注的输出为mtx
和dist
,分别包含摄像机本征矩阵和失真系数。
固有摄像机矩阵的形式为:
camaeramatrix=[fx0cx0fycy001]camaera matrix = egin{bmatrix}f_x &0& c_x \ 0 & f_y & c_y \ 0 & 0 & 1end{bmatrix}camaera matrix=⎣⎡fx000fy0cxcy1⎦⎤
上面矩阵中fxf_xfx和fyf_yfy焦距(当像素为正方形时它们相等),而 cxc_xcx 和 cyc_ycy
对应于相机中的(光学)中心 (x,y)(x ,y )(x,y) 平面。
共有五个失真系数,dist
中按以下顺序给出:
DistortionCoefficients=(k1,k2,p1,p2,k3)Distortion Coefficients = (k_1, k_2, p_1, p_2, k_3)Distortion Coefficients=(k1,k2,p1,p2,k3)
其中,k是径向失真系数,p是切向失真系数。要校正图像的径向和切向畸变,将使用cv2.undistort()
函数应用以下方程式:
使用cv2.undistort()
函数来使图像不失真:
undist = cv2.undistort(img, mtx, dist, None, mtx)
import numpy as np
import cv2
import glob
import matplotlib.pyplot as plt
import matplotlib.image as mpimg# 规定内角数量
nx = 8
ny = 6
# 准备目标点, 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((ny * nx, 3), np.float32)
# 关于np.mgrid的用法:https://www.cnblogs.com/wanghui-garcia/p/10763103.html
# .T是矩阵的转置
# reshape是转换成两列
objp[:, :2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)# 用于存储来自所有图像的对象点和图像点的数组。
objpoints = [] # 在真实空间中的3D点
imgpoints = [] # 在图像平面的2D点'''
# 制作校准图像列表
images = glob.glob('./ Cal * .jpg')
# 单步通过名单和搜索棋盘内角
for idx, fname in enumerate(images):img = mpimg.imread(fname)gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)# 找到棋盘的内角ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)# 如果找到,添加目标点,图像点if ret == True:objpoints.append(objp)imgpoints.append(corners)
'''
# 代替上面的校准图像列表
img = cv2.imread('test_image.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)# 找到棋盘的内角
ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)# 如果找到,添加目标点,图像点
if ret == True:objpoints.append(objp)imgpoints.append(corners)img = cv2.imread('test_image.png')
img_size = (img.shape[1], img.shape[0])# 摄像机标定给定的目标点和图像点
# calivrateCamera函数参考博客:https://blog.csdn.net/u011574296/article/details/73823569
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img_size, None, None)# 执行undistortion函数使测试图像不失真
undist = cv2.undistort(img, mtx, dist, None, mtx)# 展示 undistortion
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
f.tight_layout()
ax1.imshow(img)
ax1.set_title('Original Image', fontsize=50)
ax2.imshow(undist)
ax2.set_title('Undistorted Image', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
plt.show()
输出结果如下:
images = glob.glob('./ Cal * .jpg')
glob.glob : 返回所有匹配的文件路径列表。它只有一个参数pathname,定义了文件路径匹配规则,这里可以是绝对路径,也可以是相对路径。注释掉的部分是因为我只有一张图片,所以我选择了按照上一个程序的的读入方法。
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img_size, None, None)
mtx :内参数矩阵。
dist :畸变矩阵。
rvecs :旋转向量。
tvecs :位移向量。
objectPoints :世界坐标系中的点。
imagePoints :其对应的图像点。
imageSize :图像的大小,在计算相机的内参数和畸变矩阵需要用到;
2D像素坐标中的点的位置与3D世界坐标中的对应点的位置之间的关系由针孔相机模型定义:
zc[uv1]=K[RT][xwywzw1]z_cegin{bmatrix}u\v\1end{bmatrix} = Kegin{bmatrix}R& Tend{bmatrix}egin{bmatrix}x_w\y_w\z_w\1end{bmatrix}z
点云PCL免费知识星球,点云论文速读。标题:三维点云分割综述(上)排版:particle欢迎各位加入免费知识星球,获取PDF文档,欢迎转发朋友圈,分享快乐。这是一篇综述性论文,以下只做概述性介绍,介绍文章已共享在微信群和免费知识星球中,文章在公众号将分成三个部分:第一部分介绍点云的获取以及各种传感器获取点云的特性,以及分割概念的区别...
点云PCL免费知识星球,点云论文速读。文章:DLL: Direct LIDAR Localization. A map-based localization approach for aerial robots作者:Fernando Caballero1 and Luis Merino编译:点云PCL代码:https://githu...
CloudCompare是一个三维点云(网格)编辑和处理软件。最初,它被设计用来对稠密的三维点云进行直接比较。它依赖于一种特定的八叉树结构,在进行点云对比这类任务时具有出色的性能【1】。此外,由于大多数点云都是由地面激光扫描仪采集的,CloudCompare的目的是在一台标准笔记本电脑上处理大规模的点云——通常超过1000万个点云。...
点云PCL免费知识星球,点云论文速读。文章:Open3DGen: Open-Source Software for Reconstructing Textured 3D Models from RGB-D Images作者:Teo T. Niemirepo, Marko Viitanen, and Jarno Vanne编译:点云P...
点云PCL免费知识星球,点云论文速读。标题:Real-Time Spatio-Temporal LiDAR Point Cloud Compression作者:Yu Feng , Shaoshan Liu , and Yuhao Zhu来源:2020IROS本文仅做学术分享,如有侵权,请联系删除。欢迎各位加入免费知识星球,获取PDF...
nan 是not a number ,inf是无穷大 numpy.nan_to_num(x): 使用0代替数组x中的nan元素,使用有限的数字代替inf元素...
简介 Simple Reference 基础CUDA示例,适用于初学者, 反映了运用CUDA和CUDA runtime APIs的一些基本概念.Utilities Reference 演示如何查询设备能力和衡量GPU/CPU 带宽的实例程序。Graphics Reference 图形化示例展现的是 CUDA, OpenGL,...
在做开发的过程中难免需要给内核及下载的一些源码打补丁,所以我们先学习下Linux下使用如如何使用diff制作补丁以及如何使用patch打补丁。...
我在调研ATS 4.2.3挂载SSD的过程中,遇到很多坑,特此详细记录我摸索的主要过程,以便大家以后避免之。 基本思路可以完全照搬参考文献[2][3] 下面的安装假定是以root用户身份进行的,Linux服务器已经安装好系统,磁盘已经做好分区。 首先需要认识我们的Linux服务器的硬件配置和软件情况 硬件配置: DELL...
该博文整理一些在使用stl编程过程中遇到的小经验: 1.在多线程环境下面打印调试,如何使用cout及时刷新到屏幕上? 在C中我们经常这样使用: printf("Hello World "); fflush(stdout); 如果使用stl,我们可以这样使用: cout << "Hello World" << endl <...
#include