双目测距+点云——使用MiddleBurry数据集的图片
效果
输入:
|
|
|
输出:
视差图
深度图
实现了鼠标点击图片中的位置,显示其深度。
点云
其他例子点云:
|
|
|
使用自己的双目摄像头拍摄的图片:
|
|
|
由于摄像头不是很好,所以最后效果没有数据集的好,但大致能分辨出物体。
代码
stereoConfig.py
# -*- coding: utf-8 -*-
# @Time : 2022/3/25 16:06
# @Author : Zhang Jun
# @File : stereoConfig.py
# @Software: PyCharm
import numpy as np
####################仅仅是一个示例###################################
# 双目相机参数
class stereoCamera(object):
def __init__(self):
# 左相机内参
self.cam_matrix_left = np.array([[1499.641, 0, 1097.616],
[0., 1497.989, 772.371],
[0., 0., 1.]])
# 右相机内参
self.cam_matrix_right = np.array([[1494.855, 0, 1067.321],
[0., 1491.890, 777.983],
[0., 0., 1.]])
# 左右相机畸变系数:[k1, k2, p1, p2, k3]
self.distortion_l = np.array([[-0.1103, 0.0789, -0.0004, 0.0017, -0.0095]])
self.distortion_r = np.array([[-0.1065, 0.0793, -0.0002, -8.9263e-06, -0.0161]])
# 旋转矩阵
self.R = np.array([[0.9939, 0.0165, 0.1081],
[-0.0157, 0.9998, -0.0084],
[-0.1082, 0.0067, 0.9940]])
# 平移矩阵
self.T = np.array([[-423.716], [2.561], [21.973]])
# 主点列坐标的差
self.doffs = 0.0
# 指示上述内外参是否为经过立体校正后的结果
self.isRectified = False
# def setMiddleBurryParams(self):
# self.cam_matrix_left = np.array([[3997.684, 0, 225.0],
# [0., 3997.684, 187.5],
# [0., 0., 1.]])
# self.cam_matrix_right = np.array([[3997.684, 0, 225.0],
# [0., 3997.684, 187.5],
# [0., 0., 1.]])
# self.distortion_l = np.zeros(shape=(5, 1), dtype=np.float64)
# self.distortion_r = np.zeros(shape=(5, 1), dtype=np.float64)
# self.R = np.identity(3, dtype=np.float64)
# self.T = np.array([[-193.001], [0.0], [0.0]])
# self.doffs = 131.111
# self.isRectified = True
def setMiddleBurryParams(self):
self.cam_matrix_left = np.array([[7190.247, 0, 1035.513],
[0., 7190.247, 945.196],
[0., 0., 1.]])
self.cam_matrix_right = np.array([[7190.247, 0, 1378.036],
[0., 7190.247, 945.196],
[0., 0., 1.]])
self.distortion_l = np.zeros(shape=(5, 1), dtype=np.float64)
self.distortion_r = np.zeros(shape=(5, 1), dtype=np.float64)
self.R = np.identity(3, dtype=np.float64)
self.T = np.array([[-174.945], [0.0], [0.0]])
self.doffs = 342.523
self.isRectified = True
stereo.py
# -*- coding: utf-8 -*-
# @Time : 2022/3/25 16:05
# @Author : Zhang Jun
# @File : stereo.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
import sys
import cv2
import numpy as np
import stereoConfig
import open3d as o3d
# 预处理
def preprocess(img1, img2):
# 彩色图->灰度图
if (img1.ndim == 3):
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # 通过OpenCV加载的图像通道顺序是BGR
if (img2.ndim == 3):
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 直方图均衡
img1 = cv2.equalizeHist(img1)
img2 = cv2.equalizeHist(img2)
return img1, img2
# 消除畸变
def undistortion(image, camera_matrix, dist_coeff):
undistortion_image = cv2.undistort(image, camera_matrix, dist_coeff)
return undistortion_image
# 获取畸变校正和立体校正的映射变换矩阵、重投影矩阵
# @param:config是一个类,存储着双目标定的参数:config = stereoconfig.stereoCamera()
def getRectifyTransform(height, width, config):
# 读取内参和外参
left_K = config.cam_matrix_left
right_K = config.cam_matrix_right
left_distortion = config.distortion_l
right_distortion = config.distortion_r
R = config.R
T = config.T
# 计算校正变换
R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(left_K, left_distortion, right_K, right_distortion,
(width, height), R, T, alpha=0)
map1x, map1y = cv2.initUndistortRectifyMap(left_K, left_distortion, R1, P1, (width, height), cv2.CV_32FC1)
map2x, map2y = cv2.initUndistortRectifyMap(right_K, right_distortion, R2, P2, (width, height), cv2.CV_32FC1)
return map1x, map1y, map2x, map2y, Q
# 畸变校正和立体校正
def rectifyImage(image1, image2, map1x, map1y, map2x, map2y):
rectifyed_img1 = cv2.remap(image1, map1x, map1y, cv2.INTER_AREA)
rectifyed_img2 = cv2.remap(image2, map2x, map2y, cv2.INTER_AREA)
return rectifyed_img1, rectifyed_img2
# 立体校正检验----画线
def draw_line(image1, image2):
# 建立输出图像
height = max(image1.shape[0], image2.shape[0])
width = image1.shape[1] + image2.shape[1]
output = np.zeros((height, width, 3), dtype=np.uint8)
output[0:image1.shape[0], 0:image1.shape[1]] = image1
output[0:image2.shape[0], image1.shape[1]:] = image2
# 绘制等间距平行线
line_interval = 50 # 直线间隔:50
for k in range(height // line_interval):
cv2.line(output, (0, line_interval * (k + 1)), (2 * width, line_interval * (k + 1)), (0, 255, 0), thickness=2,
lineType=cv2.LINE_AA)
return output
# 视差计算
def stereoMatchSGBM(left_image, right_image, down_scale=False):
# SGBM匹配参数设置
if left_image.ndim == 2:
img_channels = 1
else:
img_channels = 3
blockSize = 3
paraml = {'minDisparity': 0,
'numDisparities': 128,
'blockSize': blockSize,
'P1': 8 * img_channels * blockSize ** 2,
'P2': 32 * img_channels * blockSize ** 2,
'disp12MaxDiff': 1,
'preFilterCap': 63,
'uniquenessRatio': 15,
'speckleWindowSize': 100,
'speckleRange': 1,
'mode': cv2.STEREO_SGBM_MODE_SGBM_3WAY
}
# 构建SGBM对象
left_matcher = cv2.StereoSGBM_create(**paraml)
paramr = paraml
paramr['minDisparity'] = -paraml['numDisparities']
right_matcher = cv2.StereoSGBM_create(**paramr)
# 计算视差图
size = (left_image.shape[1], left_image.shape[0])
if down_scale == False:
disparity_left = left_matcher.compute(left_image, right_image)
disparity_right = right_matcher.compute(right_image, left_image)
else:
left_image_down = cv2.pyrDown(left_image)
right_image_down = cv2.pyrDown(right_image)
factor = left_image.shape[1] / left_image_down.shape[1]
disparity_left_half = left_matcher.compute(left_image_down, right_image_down)
disparity_right_half = right_matcher.compute(right_image_down, left_image_down)
disparity_left = cv2.resize(disparity_left_half, size, interpolation=cv2.INTER_AREA)
disparity_right = cv2.resize(disparity_right_half, size, interpolation=cv2.INTER_AREA)
disparity_left = factor * disparity_left
disparity_right = factor * disparity_right
# 真实视差(因为SGBM算法得到的视差是×16的)
trueDisp_left = disparity_left.astype(np.float32) / 16.
trueDisp_right = disparity_right.astype(np.float32) / 16.
return trueDisp_left, trueDisp_right
def getDepthMapWithQ(disparityMap: np.ndarray, Q: np.ndarray) -> np.ndarray:
points_3d = cv2.reprojectImageTo3D(disparityMap, Q)
depthMap = points_3d[:, :, 2]
reset_index = np.where(np.logical_or(depthMap < 0.0, depthMap > 65535.0))
depthMap[reset_index] = 0
return depthMap.astype(np.float32)
def getDepthMapWithConfig(disparityMap: np.ndarray, config: stereoConfig.stereoCamera) -> np.ndarray:
fb = config.cam_matrix_left[0, 0] * (-config.T[0])
doffs = config.doffs
depthMap = np.divide(fb, disparityMap + doffs)
reset_index = np.where(np.logical_or(depthMap < 0.0, depthMap > 65535.0))
depthMap[reset_index] = 0
reset_index2 = np.where(disparityMap < 0.0)
depthMap[reset_index2] = 0
return depthMap.astype(np.float32)
if __name__ == '__main__':
# 读取MiddleBurry数据集的图片
iml = cv2.imread('perfect001/Backpack-perfect/im0.png', 1) # 左图
imr = cv2.imread('perfect001/Backpack-perfect/im1.png', 1) # 右图
if (iml is None) or (imr is None):
print("Error: Images are empty, please check your image's path!")
sys.exit(0)
height, width = iml.shape[0:2]
# 读取相机内参和外参
# 使用之前先将标定得到的内外参数填写到stereoconfig.py中的StereoCamera类中
config = stereoConfig.stereoCamera()
config.setMiddleBurryParams()
print(config.cam_matrix_left)
# 立体校正
map1x, map1y, map2x, map2y, Q = getRectifyTransform(height, width, config) # 获取用于畸变校正和立体校正的映射矩阵以及用于计算像素空间坐标的重投影矩阵
iml_rectified, imr_rectified = rectifyImage(iml, imr, map1x, map1y, map2x, map2y)
print(Q)
# 绘制等间距平行线,检查立体校正的效果
line = draw_line(iml_rectified, imr_rectified)
cv2.imwrite('check_rectification.png', line)
# 立体匹配
iml_, imr_ = preprocess(iml, imr) # 预处理,一般可以削弱光照不均的影响,不做也可以
disp, _ = stereoMatchSGBM(iml, imr, True) # 这里传入的是未经立体校正的图像,因为我们使用的middleburry图片已经是校正过的了
cv2.imwrite('disaprity.png', disp)
# 计算深度图
#depthMap = getDepthMapWithQ(disp, Q)
depthMap = getDepthMapWithConfig(disp, config)
minDepth = np.min(depthMap)
maxDepth = np.max(depthMap)
print(minDepth, maxDepth)
depthMapVis = (255.0 * (depthMap - minDepth)) / (maxDepth - minDepth)
depthMapVis = depthMapVis.astype(np.uint8)
def callbackFunc(e, x, y, f, p):
if e == cv2.EVENT_LBUTTONDOWN:
print('目标的深度距离为 %2f mm' % depthMap[y][x])
cv2.namedWindow('DepthMap', 0)
cv2.setMouseCallback("DepthMap", callbackFunc, None)
cv2.imshow("DepthMap", depthMapVis)
cv2.waitKey(0)
# 使用open3d库绘制点云
iml = cv2.cvtColor(iml, cv2.COLOR_BGR2RGB)
colorImage = o3d.geometry.Image(iml)
depthImage = o3d.geometry.Image(depthMap)
rgbdImage = o3d.geometry.RGBDImage.create_from_color_and_depth(colorImage, depthImage, depth_scale=1000.0,
depth_trunc=np.inf,convert_rgb_to_intensity=False)
intrinsics = o3d.camera.PinholeCameraIntrinsic()
fx = config.cam_matrix_left[0, 0]
fy = fx
cx = config.cam_matrix_left[0, 2]
cy = config.cam_matrix_left[1, 2]
print(fx, fy, cx, cy)
intrinsics.set_intrinsics(width, height, fx=fx, fy=fy, cx=cx, cy=cy)
extrinsics = np.array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
pointcloud = o3d.geometry.PointCloud().create_from_rgbd_image(rgbdImage, intrinsic=intrinsics, extrinsic=extrinsics)
# 计算像素点的3D坐标(左相机坐标系下)
points_3d = cv2.reprojectImageTo3D(disp, Q) # 参数中的Q就是由getRectifyTransform()函数得到的重投影矩阵
# 构建点云--Point_XYZRGBA格式
o3d.io.write_point_cloud("0/PointCloud.pcd", pointcloud=pointcloud)
o3d.visualization.draw_geometries([pointcloud], width=720, height=480)
参考资料
双目测距理论及其python实现
MiddleBurry数据集官网
双目测距+点云——使用MiddleBurry数据集的图片的更多相关文章
- 学习笔记:使用opencv做双目测距(相机标定+立体匹配+测距).
最近在做双目测距,觉得有必要记录点东西,所以我的第一篇博客就这么诞生啦~ 双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道 ...
- 学习OpenCV双目测距原理及常见问题解答
学习OpenCV双目测距原理及常见问题解答 转自博客:https://blog.csdn.net/angle_cal/article/details/50800775 一. 整体思路和问题转化. 图 ...
- 使用OpenCV/python进行双目测距
在做SLAM时,希望用到深度图来辅助生成场景,所以要构建立体视觉,在这里使用OpenCV的Stereo库和python来进行双目立体视觉的图像处理. 立体标定 应用标定数据 转换成深度图 标定 在开始 ...
- 【计算机视觉】双目测距(六)--三维重建及UI显示
原文: http://blog.csdn.NET/chenyusiyuan/article/details/5970799 在获取到视差数据后,利用 OpenCV 的 reProjectImageTo ...
- 采用线性回归方法降低双目测距到平面的误差(sklearn)
继上篇,为了改善标定板的深度信息: remove_idx1 = np.where(Z <= 0) remove_idx2 = np.where(Z > 500)#将Z轴坐标限定在0-500 ...
- 图片流量节省大杀器:基于腾讯云CDN的sharpP自适应图片技术实践
目前移动端运营素材大部分依赖图片,基于对图片流量更少,渲染速度更快的诉求,我们推动CDN,X5内核,即通产品部共同推出了一套业务透明,无痛接入的CDN图片优化方案:基于CDN的sharpP自适应图片无 ...
- 【caffe-windows】 caffe-master 之 训练自己数据集(图片转换成lmdb or leveldb)
前期准备: 文件夹train:此文件夹中按类别分好子文件夹,各子文件夹里存放相应图片 文件夹test:同train,有多少类就有多少个子文件夹 trainlabels.txt : 存的是训练集的标签 ...
- 微信小程序里如何用阿里云上传视频,图片。。
纯手写,踩了半天多的坑干出来了... 网上也有对于阿里云如何在微信小程序里使用,但是很不全,包括阿里云文档的最佳实践里. 话不多说上代码了. upvideo(){ var aliOssParams = ...
- 使用OpenCV把二进制mnist数据集转换为图片
mnist数据集是以二进制形式保存的,这里借助OpenCV把mnist数据集转换成图片格式.转换程序如下: #include <iostream> #include <fstream ...
- 阿里云使用js 实现OSS图片上传、获取OSS图片列表、获取图片外网访问地址(读写权限私有、读写权限公共);
详情请参考:https://help.aliyun.com/document_detail/32069.html?spm=a2c4g.11186623.6.763.ZgC59a 或者https://h ...
随机推荐
- 齐博x1页面不直接报错,如何排查
有的页面是不会直接报错的,比如像下面这个,这个时候需要你用谷歌或火狐浏览器打开,按F12键进入开发者模式,然后选择Network选项,刷新一下当前的网页,就会看到红色的请求.单独打开他.就可以看到错误 ...
- 【MySQL】04_约束
约束 概述 为了保证数据的完整性,SQL规范以约束的方式对表数据进行额外的条件限制.从以下四个方面考虑: 实体完整性(Entity Integrity) :例如,同一个表中,不能存在两条完全相同无法区 ...
- Masked Label Prediction: Unified Message Passing Model for Semi-Supervised Classification
背景 消息传递模型(Message Passing Model)基于拉普拉斯平滑假设(领居是相似的),试图聚合图中的邻居的信息来获取足够的依据,以实现更鲁棒的半监督节点分类. 图神经网络(Graph ...
- DQL-聚合函数
DQL-聚合函数 SQL基本函数,聚合函数对一组值执行计算,并返回单个值,也被称为组函数. 聚合函数对一组值执行计算并返回单一的值.除 COUNT 以外,聚合函数忽略空值,如果COUNT函数的应用对象 ...
- 论文笔记 - Fantastically Ordered Prompts and Where to Find Them: Overcoming Few-Shot Prompt Order Sensitivity
prompt 的影响因素 Motivation Prompt 中 Example 的排列顺序对模型性能有较大影响(即使已经校准参见好的情况下,选取不同的排列顺序依然会有很大的方差): 校准可以大幅度提 ...
- Codeforces Round #805 (Div. 3)G2. Passable Paths
题目大意: 给出一个无向无环连通图(树),n个点n-1条边,m次查询,每次询问给出一个集合,问集合里的树是否都在同一条链上(即能否不重复的走一条边而遍历整个点集) 思路:通过求lca,若有三个点x,y ...
- 支持JDK19虚拟线程的web框架,之五(终篇):兴风作浪的ThreadLocal
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos <支持JDK19虚拟线程的web框架>系列 ...
- centos7内核升级记录
1. 挂载centos7.9最终版镜像,执行升级执行:yum update 2. 重启服务器系统:init 6 3. 查看当前内核版本:uname -r 4. 查看历史内核,并卸载没用的:rpm -q ...
- 重新认识下JVM级别的本地缓存框架Guava Cache(3)——探寻实现细节与核心机制
大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 通过<重新认识下JVM级别的本地 ...
- [.NET学习]EFCore学习之旅 -2 简单的增删改查
1.实例化创建数据库上下文类 首先实例化一个数据库操作上下文类,注意到DbContext实现了IDisposable接口,所以使用using语句,避免内存泄露. 2.插入 以Person类为例,先生成 ...
左图
右图
bicycle
motorcycle
bottle
laptop