功能包:~/yahboomcar_ws/src/yahboomcar_visual
本节效果可在安装了我们相对应镜像的主板上演示。
增强现实(Augmented Reality),简称“AR”,技术是一种将虚拟信息与真实世界巧妙融合的技术,广泛运用了多媒体、三维建模、实时跟踪及注册、智能交互、传感等多种技术手段,将计算机生成的文字、图像、三维模型、音乐、视频等虚拟信息模拟仿真后,应用到真实世界中,两种信息互为补充,从而实现对真实世界的“增强”。
AR系统具有三个突出的特点:①真实世界和虚拟世界的信息集成;②具有实时交互性;③是在三维尺度空间中增添定位虚拟物体。
增强现实技术包含了多媒体、三维建模、实时视频显示及控制、多传感器融合、实时跟踪及注册、场景融合等新技术与新手段。
在使用AR案例时,必须得有相机的内参,不然无法运行。内参文件与代码同目录(功能包的AR文件夹下);不同相机对应不同内参。
(我们对应主板镜像里已存放好标定的相机内参文件,无需二次标定)
启动单目相机/树莓派 CSI相机
xxxxxxxxxx
roslaunch usb_cam usb_cam-test.launch
启动Jetson CSI相机
xxxxxxxxxx
roslaunch yahboomcar_visual yahboom_csi.launch
启动标定节点 (单目相机/树莓派 CSI相机)
xxxxxxxxxx
rosrun camera_calibration cameracalibrator.py image:=/usb_cam/image_raw camera:=/usb_cam --size 9x6 --square 0.02
启动标定节点 (jetson CSI相机)
xxxxxxxxxx
rosrun camera_calibration cameracalibrator.py image:=/csi_cam_0/image_raw camera:=/csi_cam_0 --size 9x6 --square 0.02
标定完后,将【calibrationdata.tar.gz】文件移动到【home】目录下。
xxxxxxxxxx
sudo mv /tmp/calibrationdata.tar.gz ~
解压后,将该文件夹里面的【ost.yaml】打开,找到相机内参矩阵和畸变系数修改到【USB_camera.yaml】或者【csi_camera.yaml】文件对应的位置,只需修改两处【data】的内容即可。例如:以下内容。
xxxxxxxxxx
camera_matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [615.50506, 0. , 365.84388,
0. , 623.69024, 238.778 ,
0. , 0. , 1. ]
distortion_model: plumb_bob
distortion_coefficients: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [0.166417, -0.160106, -0.008776, 0.025459, 0.000000]
一共12种效果。
xxxxxxxxxx
["Triangle", "Rectangle", "Parallelogram","WindMill","TableTennisTable", "Ball", "Arrow", "Knife", "Desk",
"Bench", "Stickman", "ParallelBars"]
启动命令
xxxxxxxxxx
roslaunch yahboomcar_visual simple_AR.launch display:=true flip:=false
根据需求设置参数,也可直接修改launch文件,启动时便无需附带参数。不开启画面时,可使用网络监控方式查看
xxxxxxxxxx
开启设备的IP:8080
1)在显示画面的情况下(即display为true),【q】键退出,【f】键切换不同效果,也可以使用命令行切换。
使用【f】或【F】键切换不同效果。
2)在不显示画面的情况下(即display为false),只能通过命令行切换效果
使用RANSAC方案从3D-2D点对应中查找对象姿势。
RanSaC算法(随机采样一致)原本是用于数据处理的一种经典算法,其作用是在大量噪声情况下,提取物体中特定的成分。下图是对RanSaC算法效果的说明。图中有一些点显然是满足某条直线的,另外有一团点是纯噪声。目的是在大量噪声的情况下找到直线方程,此时噪声数据量是直线的3倍。
如果用最小二乘法是无法得到这样的效果的,直线大约会在图中直线偏上一点。
RANSAC的基本假设是: (1)数据由“局内点”组成,例如:数据的分布可以用一些模型参数来解释; (2)“局外点”是不能适应该模型的数据; (3)除此之外的数据属于噪声。 局外点产生的原因有:噪声的极值;错误的测量方法;对数据的错误假设。 RANSAC也做了以下假设:给定一组(通常很小的)局内点,存在一个可以估计模型参数的过程;而该模型能够解释或者适用于局内点。
设计流程:
launch文件
xxxxxxxxxx
<launch>
<arg name="flip" default="False"/>
<arg name="display" default="False"/>
<node name="simple_AR" pkg="yahboomcar_visual" type="simple_AR.py" output="screen" args="$(arg display)">
<param name="flip" type="bool" value="$(arg flip)"/>
<remap from="/simpleAR/camera" to="/simpleAR/camera"/>
</node>
<!-- web_video_server -->
<node pkg="web_video_server" type="web_video_server" name="web_video_server" output="screen"/>
</launch>
python主函数
xxxxxxxxxx
def process(self, img):
if self.flip == 'True': img = cv.flip(img, 1)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 查找每个图片的角点
retval, corners = cv.findChessboardCorners(
gray, self.patternSize, None,
flags=cv.CALIB_CB_ADAPTIVE_THRESH + cv.CALIB_CB_NORMALIZE_IMAGE + cv.CALIB_CB_FAST_CHECK)
# 查找角点亚像素
if retval:
corners = cv.cornerSubPix(
gray, corners, (11, 11), (-1, -1),
(cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001))
# 计算对象姿态solvePnPRansac
retval, rvec, tvec, inliers = cv.solvePnPRansac(
self.objectPoints, corners, self.cameraMatrix, self.distCoeffs)
# 输出图像点和雅可比矩阵
image_Points, jacobian = cv.projectPoints(
self.__axis, rvec, tvec, self.cameraMatrix, self.distCoeffs, )
# 绘制图像
img = self.draw(img, corners, image_Points)
return img
关键函数
https://docs.opencv.org/3.0-alpha/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
xxxxxxxxxx
def findChessboardCorners(image, patternSize, corners=None, flags=None):
'''
查找图片角点
:param image: 输入原始的棋盘板图像。该图像必须是一张8位的灰度图或色彩图。
:param patternSize: (w,h),棋盘上每一排和每一列的内角数。w=棋盘板一行上黑白块的数量-1,h=棋盘板一列上黑白块的数量-1。
例如:10x6的棋盘板,则(w,h)=(9,5)
:param corners: array,检测到的角点的输出数组。
:param flags: int,不同的操作标记,能够为0或者下述值的组合:
CALIB_CB_ADAPTIVE_THRESH 使用自适应阈值法把图像转换为黑白图,而不是使用一个固定的阈值。
CALIB_CB_NORMALIZE_IMAGE 在利用固定阈值或自适应阈值法二值化图像之前,利用直方图均衡化图像。
CALIB_CB_FILTER_QUADS 使用额外的标准(如轮廓面积,周长,正方形形状)来过滤掉在轮廓检索阶段提取的假四边形。
CALIB_CB_FAST_CHECK 对图像运行一个快速检查机制以查找棋盘板的角点,如果没有找到角点则返回一个快捷提醒。
当没有观察到棋盘时,可以极大地加快在退化条件下的调用。
:return: retval, corners
'''
pass
我们需要使用cornerSubPix()对检测到的角点作进一步的优化计算,可使角点的精度达到亚像素级别。
xxxxxxxxxx
def cornerSubPix(image, corners, winSize, zeroZone, criteria):
'''
亚像素角点检测函数
:param image: 输入图像
:param corners: 像素角点(既作为输入也作为输出)
:param winSize: 区域大小为 NXN; N=(winSize*2+1)
:param zeroZone: 类似于winSize,但是总具有较小的范围,Size(-1,-1)表示忽略
:param criteria: 停止优化的标准
:return: 亚像素角点
'''
pass
xxxxxxxxxx
def solvePnPRansac(objectPoints, imagePoints, cameraMatrix, distCoeffs,
rvec=None, tvec=None, useExtrinsicGuess=None, iterationsCount=None,
reprojectionError=None, confidence=None, inliers=None, flags=None):
'''
计算对象姿态
:param objectPoints: 对象点列表
:param imagePoints: 角点列表
:param cameraMatrix: 相机矩阵
:param distCoeffs: 畸变系数
:param rvec:
:param tvec:
:param useExtrinsicGuess:
:param iterationsCount:
:param reprojectionError:
:param confidence:
:param inliers:
:param flags:
:return: retval, rvec, tvec, inliers
'''
pass
使用RANSAC方案从3D-2D点对应关系中查找对象姿态。该函数在给定一组对象点、它们对应的图像投影以及相机矩阵和失真系数的情况下,估计对象姿势。此函数找到一个使重新投影误差最小的姿势,即重新观察误差,即观察到的像素点投影imagePoints与物体投影(projectPoints()
)objectPoints之间的平方距离之和。 RANSAC的使用可以避免异常值对结果的影响。
def projectPoints(objectPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints=None, jacobian=None, aspectRatio=None):
'''
输出图像点和雅可比矩阵
:param objectPoints:
:param rvec: 旋转向量
:param tvec: 平移向量
:param cameraMatrix: 摄影机矩阵
:param distCoeffs: 失真系数
:param imagePoints:
:param jacobian:
:param aspectRatio:
:return: imagePoints, jacobian
'''
pass