基本思想:手中有一块微软的深度相机,结合手册和逻辑写个代码测试一下
注意:深度相机实际与实例分隔模型相结合是效果最佳的,基本思路就是分隔出目标,然后将深度图和RGB图进行对其,然后对实例的图像去关键点,计算均值深度值,获取准确的结果,要是为了简单开发,那就检测目标,然后取目标中心点,本篇博客是这么做的,而这篇44、使用OrienMask进行实例分割目标检测,并进行mnn部署和ncnn部署_sxj731533730的博客-CSDN博客博客是在实例分割的基础上开发的,如果,你仅仅会目标检测 ,可以参考本篇博客学习使用
第一步:window11进行代码开发和测试,主要是测试距离,然后集成到自己的项目中
Releases · IntelRealSense/librealsense · GitHub
首先使用Depth.Quality.Tool.exe 进行相机标定
1)、首先保证相机是照射在一个光滑的平面上,我照射在一个电脑的屏幕上,该屏幕处于关电状态,然后打开标定软件,保证蓝色画面正处于标定状态,无其它信息显示,然后标定数据写入相机,即相机自动标定内外参数,不用手动标定板写入,还是蛮方便的
2)实测距离为30厘米左右
软件测试距离308毫米=30.8厘米,还是蛮准的
使用Intel.RealSense.Viewer.exe工具测试,也是如此将鼠标放在检测区域,测试距离仍然正确
第二步:写代码获取一下距离参数 官网的例子 librealsense/wrappers/python/examples at development · IntelRealSense/librealsense · GitHub
F:\pyrealsense>pip3 install pyrealsense2
测试代码(参考大佬的代码,链接参考附录,做过修改)
import pyrealsense2 as rs
import numpy as np
import cv2
pc = rs.pointcloud()
points = rs.points()
pipeline = rs.pipeline() # 创建一个管道
config = rs.config() # Create a config并配置要流式传输的管道。
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 15)
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 15)
# 使用选定的流参数显式启用设备流
# Start streaming 开启流
pipe_profile = pipeline.start(config)
align_to = rs.stream.color
align = rs.align(align_to) # 设置为其他类型的流,意思是我们允许深度流与其他流对齐
print(type(align))
cap = cv2.VideoCapture(0)
object_x=300 #修改成检测目标的中心点即可
object_y=250
while True:
frames = pipeline.wait_for_frames() # 等待开启通道
# ret, frame = cap.read() # ret 读取到图片为True 未读到图片为Falst
# frame = cv2.flip(frame, 1)
aligned_frames = align.process(frames) # 将深度框和颜色框对齐
depth_frame = aligned_frames.get_depth_frame() # ?获得对齐后的帧数深度数据(图)
color_frame = aligned_frames.get_color_frame() # ?获得对齐后的帧数颜色数据(图)
img_color = np.asanyarray(color_frame.get_data()) # 把图像像素转化为数组
img_depth = np.asanyarray(depth_frame.get_data()) # 把图像像素转化为数组
# img_color2 = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
# Intrinsics & Extrinsics
depth_intrin = depth_frame.profile.as_video_stream_profile().intrinsics
color_intrin = color_frame.profile.as_video_stream_profile().intrinsics
depth_to_color_extrin = depth_frame.profile.get_extrinsics_to(color_frame.profile)
# 获取深度传感器的深度标尺
depth_sensor = pipe_profile.get_device().first_depth_sensor()
depth_scale = depth_sensor.get_depth_scale()
# 由深度到颜色
depth_pixel = [240, 320] # Random pixel
depth_point = rs.rs2_deproject_pixel_to_point(depth_intrin, depth_pixel, depth_scale)
color_point = rs.rs2_transform_point_to_point(depth_to_color_extrin, depth_point)
color_pixel = rs.rs2_project_point_to_pixel(color_intrin, color_point)
print('depth: ', color_point)
print('depth: ', color_pixel)
pc.map_to(color_frame)
points = pc.calculate(depth_frame)
vtx = np.asanyarray(points.get_vertices()) # points.get_vertices() 检索点云的顶点
tex = np.asanyarray(points.get_texture_coordinates())
i = 640 * 200 + 200
print('depth: ', [np.float(vtx[i][0]), np.float(vtx[i][1]), np.float(vtx[i][2])])
cv2.circle(img_color, (object_x, object_y), 8, [255, 0, 255], thickness=-1)
cv2.putText(img_color, "Distance/mm:" + str(img_depth[object_x, object_y]), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1.2,
[255, 0, 255])
cv2.putText(img_color, "X:" + str(np.float(vtx[i][0])), (80, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, [255, 0, 255])
cv2.putText(img_color, "Y:" + str(np.float(vtx[i][1])), (80, 120), cv2.FONT_HERSHEY_SIMPLEX, 1, [255, 0, 255])
cv2.putText(img_color, "Z:" + str(np.float(vtx[i][2])), (80, 160), cv2.FONT_HERSHEY_SIMPLEX, 1, [255, 0, 255])
cv2.imshow('rgb_frame', img_color)
cv2.imshow("depth_frame", img_depth)
key = cv2.waitKey(1)
if key == 27:
cv2.destroyAllWindows()
break
cv2.waitKey(0)
cv2.destroyAllWindows()
pipeline.stop()
测试结果yolov5lite+track+测距
第三步:集成到自己项目中的效果,检测+测距,比双目的测距更为准确一些33、C++双目摄像头进行测距实验_sxj731533730的博客-CSDN博客_双目测距代码c++
实际工程中我用的是实例分割+深度检测计算目标距离信息,这样取得距离信息才是准确的可以用ncnn+yolact也可以使用我这篇博客的内容进行部署44、使用OrienMask进行实例分割目标检测,并进行mnn部署和ncnn部署_sxj731533730的博客-CSDN博客
c++代码是参考索引的地一个大佬的,我怕它cadn某一天看不到,就拷贝贴下面了,需要自己和实例分割代码结合
cmakelists.txt
project(measure_distance)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
set(CMAKE_CXX_FLAGS "-std=c++11")
#寻找opencv库
find_package(OpenCV REQUIRED)
#message(STATUS ${OpenCV_INCLUDE_DIRS})
#添加头文件
include_directories(${OpenCV_INCLUDE_DIRS})
#链接Opencv库
target_link_libraries(measure_distance ${OpenCV_LIBS} )
#添加后可进行调试
set( CMAKE_BUILD_TYPE Debug )
set(DEPENDENCIES realsense2 )
target_link_libraries(measure_distance ${DEPENDENCIES})
源码
#include <iostream>
#include <sstream>
#include <iostream>
#include <fstream>
#include <algorithm>
#include<string>
#include<opencv2/highgui/highgui_c.h>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
#include<librealsense2/rs.hpp>
#include<librealsense2/rsutil.h>
//获取深度像素对应长度单位(米)的换算比例
float get_depth_scale(rs2::device dev)
{
// Go over the device's sensors
for (rs2::sensor& sensor : dev.query_sensors())
{
// Check if the sensor if a depth sensor
if (rs2::depth_sensor dpt = sensor.as<rs2::depth_sensor>())
{
return dpt.get_depth_scale();
}
}
throw std::runtime_error("Device does not have a depth sensor");
}
//深度图对齐到彩色图函数
Mat align_Depth2Color(Mat depth,Mat color,rs2::pipeline_profile profile){
//声明数据流
auto depth_stream=profile.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>();
auto color_stream=profile.get_stream(RS2_STREAM_COLOR).as<rs2::video_stream_profile>();
//获取内参
const auto intrinDepth=depth_stream.get_intrinsics();
const auto intrinColor=color_stream.get_intrinsics();
//直接获取从深度摄像头坐标系到彩色摄像头坐标系的欧式变换矩阵
//auto extrinDepth2Color=depth_stream.get_extrinsics_to(color_stream);
rs2_extrinsics extrinDepth2Color;
rs2_error *error;
rs2_get_extrinsics(depth_stream,color_stream,&extrinDepth2Color,&error);
//平面点定义
float pd_uv[2],pc_uv[2];
//空间点定义
float Pdc3[3],Pcc3[3];
//获取深度像素与现实单位比例(D435默认1毫米)
float depth_scale = get_depth_scale(profile.get_device());
int y=0,x=0;
//初始化结果
//Mat result=Mat(color.rows,color.cols,CV_8UC3,Scalar(0,0,0));
Mat result=Mat(color.rows,color.cols,CV_16U,Scalar(0));
//对深度图像遍历
for(int row=0;row<depth.rows;row++){
for(int col=0;col<depth.cols;col++){
//将当前的(x,y)放入数组pd_uv,表示当前深度图的点
pd_uv[0]=col;
pd_uv[1]=row;
//取当前点对应的深度值
uint16_t depth_value=depth.at<uint16_t>(row,col);
//换算到米
float depth_m=depth_value*depth_scale;
//将深度图的像素点根据内参转换到深度摄像头坐标系下的三维点
rs2_deproject_pixel_to_point(Pdc3,&intrinDepth,pd_uv,depth_m);
//将深度摄像头坐标系的三维点转化到彩色摄像头坐标系下
rs2_transform_point_to_point(Pcc3,&extrinDepth2Color,Pdc3);
//将彩色摄像头坐标系下的深度三维点映射到二维平面上
rs2_project_point_to_pixel(pc_uv,&intrinColor,Pcc3);
//取得映射后的(u,v)
x=(int)pc_uv[0];
y=(int)pc_uv[1];
// if(x<0||x>color.cols)
// continue;
// if(y<0||y>color.rows)
// continue;
//最值限定
x=x<0? 0:x;
x=x>depth.cols-1 ? depth.cols-1:x;
y=y<0? 0:y;
y=y>depth.rows-1 ? depth.rows-1:y;
result.at<uint16_t>(y,x)=depth_value;
}
}
//返回一个与彩色图对齐了的深度信息图像
return result;
}
void measure_distance(Mat &color,Mat depth,cv::Size range,rs2::pipeline_profile profile)
{
//获取深度像素与现实单位比例(D435默认1毫米)
float depth_scale = get_depth_scale(profile.get_device());
//定义图像中心点
cv::Point center(color.cols/2,color.rows/2);
//定义计算距离的范围
cv::Rect RectRange(center.x-range.width/2,center.y-range.height/2,range.width,range.height);
//遍历该范围
float distance_sum=0;
int effective_pixel=0;
for(int y=RectRange.y;y<RectRange.y+RectRange.height;y++){
for(int x=RectRange.x;x<RectRange.x+RectRange.width;x++){
//如果深度图下该点像素不为0,表示有距离信息
if(depth.at<uint16_t>(y,x)){
distance_sum+=depth_scale*depth.at<uint16_t>(y,x);
effective_pixel++;
}
}
}
cout<<"遍历完成,有效像素点:"<<effective_pixel<<endl;
float effective_distance=distance_sum/effective_pixel;
cout<<"目标距离:"<<effective_distance<<" m"<<endl;
char distance_str[30];
sprintf(distance_str,"the distance is:%f m",effective_distance);
cv::rectangle(color,RectRange,Scalar(0,0,255),2,8);
cv::putText(color,(string)distance_str,cv::Point(color.cols*0.02,color.rows*0.05),
cv::FONT_HERSHEY_PLAIN,2,Scalar(0,255,0),2,8);
}
int main()
{
const char* depth_win="depth_Image";
namedWindow(depth_win,WINDOW_AUTOSIZE);
const char* color_win="color_Image";
namedWindow(color_win,WINDOW_AUTOSIZE);
//深度图像颜色map
rs2::colorizer c; // Helper to colorize depth images
//创建数据管道
rs2::pipeline pipe;
rs2::config pipe_config;
pipe_config.enable_stream(RS2_STREAM_DEPTH,640,480,RS2_FORMAT_Z16,30);
pipe_config.enable_stream(RS2_STREAM_COLOR,640,480,RS2_FORMAT_BGR8,30);
//start()函数返回数据管道的profile
rs2::pipeline_profile profile = pipe.start(pipe_config);
//定义一个变量去转换深度到距离
float depth_clipping_distance = 1.f;
//声明数据流
auto depth_stream=profile.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>();
auto color_stream=profile.get_stream(RS2_STREAM_COLOR).as<rs2::video_stream_profile>();
//获取内参
auto intrinDepth=depth_stream.get_intrinsics();
auto intrinColor=color_stream.get_intrinsics();
//直接获取从深度摄像头坐标系到彩色摄像头坐标系的欧式变换矩阵
auto extrinDepth2Color=depth_stream.get_extrinsics_to(color_stream);
while (cvGetWindowHandle(depth_win)&&cvGetWindowHandle(color_win)) // Application still alive?
{
//堵塞程序直到新的一帧捕获
rs2::frameset frameset = pipe.wait_for_frames();
//取深度图和彩色图
rs2::frame color_frame = frameset.get_color_frame();//processed.first(align_to);
rs2::frame depth_frame = frameset.get_depth_frame();
rs2::frame depth_frame_4_show = frameset.get_depth_frame().apply_filter(c);
//获取宽高
const int depth_w=depth_frame.as<rs2::video_frame>().get_width();
const int depth_h=depth_frame.as<rs2::video_frame>().get_height();
const int color_w=color_frame.as<rs2::video_frame>().get_width();
const int color_h=color_frame.as<rs2::video_frame>().get_height();
//创建OPENCV类型 并传入数据
Mat depth_image(Size(depth_w,depth_h),
CV_16U,(void*)depth_frame.get_data(),Mat::AUTO_STEP);
Mat depth_image_4_show(Size(depth_w,depth_h),
CV_8UC3,(void*)depth_frame_4_show.get_data(),Mat::AUTO_STEP);
Mat color_image(Size(color_w,color_h),
CV_8UC3,(void*)color_frame.get_data(),Mat::AUTO_STEP);
//实现深度图对齐到彩色图
Mat result=align_Depth2Color(depth_image,color_image,profile);
measure_distance(color_image,result,cv::Size(20,20),profile);
//显示
imshow(depth_win,depth_image_4_show);
imshow(color_win,color_image);
//imshow("result",result);
waitKey(1);
}
return 0;
}
参考
Intel RealSense Depth Camera D435相机调用,深度图调用及测距_佳佳鸽的博客-CSDN博客
realsense SDK2.0学习::(五)D435利用深度信息做测距工具_dieju8330的博客-CSDN博客_d435测距
librealsense/distribution_linux.md at master · IntelRealSense/librealsense · GitHub
GitHub - IntelRealSense/librealsense at v2.47.0
librealsense/wrappers/python/examples at development · IntelRealSense/librealsense · GitHub
Realsense D435i深度测距和普通摄像头单目测距的区别(附带可用实测代码)_手里有风的博客-CSDN博客_d435深度摄像头