c++调用OAK相机实现rgb彩色图和depth深度图的移动测距

基本思想:学习oak双目相机实现rgb彩色图和depth深度图的移动测距

前言:

设备型号:OAK-D-Pro

一、环境配置参考

台式机ubuntu系统调用OAK相机_MFT小白的博客-优快云博客

二、python版本

python调用OAK相机实现人脸检测的简单demo_MFT小白的博客-优快云博客

三、测试

其中 utility 文件夹为oak官网 depthai_cpp_example 文件夹中

获取地址:GitHub - richard-xx/depthai_cpp_example

git clone https://github.com/richard-xx/depthai_cpp_example.git
cmakelist.txt
cmake_minimum_required(VERSION 3.16)
project(test_depthai)

set(CMAKE_CXX_STANDARD 14)
find_package(OpenCV REQUIRED)
find_package(depthai CONFIG REQUIRED)

include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include/utility)

add_executable(test_depthai main.cpp)

target_link_libraries(test_depthai ${OpenCV_LIBS} depthai::opencv)
main.cpp 
#include <iostream>
#include "depthai/depthai.hpp"
#include "utility.hpp"

#define Rgb 0
#define spatial_location_calculator 1


static constexpr float stepSize = 0.05f;

static std::atomic<bool> newConfig{false};


#if Rgb
int main() {

    dai::Pipeline pipeline;
    auto camRgb = pipeline.create<dai::node::ColorCamera>();
    auto xoutVideo = pipeline.create<dai::node::XLinkOut>();

    xoutVideo->setStreamName("video");

    camRgb->setBoardSocket(dai::CameraBoardSocket::RGB);
    camRgb->setResolution(dai::ColorCameraProperties::SensorResolution::THE_1080_P);
    camRgb->setVideoSize(1920, 1080);

    camRgb->video.link(xoutVideo->input);

    xoutVideo->input.setBlocking(false);
    xoutVideo->input.setQueueSize(1);

    dai::Device device(pipeline);

    auto video = device.getOutputQueue("video");

    while (true) {
        auto videoIn = video->get<dai::ImgFrame>();

        cv::Mat frame = videoIn->getCvFrame();

        cv::imshow("video", frame);
        int key = cv::waitKey(1);
        if (key == 'q' || key = 27) {
            return 0;
        }
    }

    return 0;
}


#elif spatial_location_calculator
int main() {
    using namespace std;

    // Create pipeline
    dai::Pipeline pipeline;
    dai::Device device;

    // Define sources and outputs
    auto camRgb = pipeline.create<dai::node::ColorCamera>();
    auto monoLeft = pipeline.create<dai::node::MonoCamera>();
    auto monoRight = pipeline.create<dai::node::MonoCamera>();
    auto stereo = pipeline.create<dai::node::StereoDepth>();
    auto spatialDataCaulator = pipeline.create<dai::node::SpatialLocationCalculator>();

    // Properties
    camRgb->setBoardSocket(dai::CameraBoardSocket::RGB);
    camRgb->setResolution(dai::ColorCameraProperties::SensorResolution::THE_1080_P);
    camRgb->setPreviewSize(1920, 1080);

    monoLeft->setBoardSocket(dai::CameraBoardSocket::LEFT);
    monoLeft->setResolution(dai::MonoCameraProperties::SensorResolution::THE_720_P);
    monoRight->setBoardSocket(dai::CameraBoardSocket::RIGHT);
    monoRight->setResolution(dai::MonoCameraProperties::SensorResolution::THE_720_P);

    try {
        auto calibData = device.readCalibration2();
        auto lensPosition = calibData.getLensPosition(dai::CameraBoardSocket::RGB);
        if (lensPosition) {
            camRgb->initialControl.setManualFocus(lensPosition);
        }
    }   catch (const std::exception &ex) {
            std::cout << ex.what() << std::endl;
            return 1;
    }

    bool lrcheck = true;
    bool subpixel = true;

    stereo->setDefaultProfilePreset(dai::node::StereoDepth::PresetMode::HIGH_ACCURACY);
    stereo->setLeftRightCheck(lrcheck);
    stereo->setSubpixel(subpixel);
    stereo->setDepthAlign(dai::CameraBoardSocket::RGB);

    // config
    dai::Point2f topLeft(0.4f, 0.4f);
    dai::Point2f bottomRight(0.6f, 0.6f);

    dai::SpatialLocationCalculatorConfigData config;
    config.depthThresholds.lowerThreshold = 100;
    config.depthThresholds.upperThreshold = 5000;
    config.roi = dai::Rect(topLeft, bottomRight);

    spatialDataCaulator->initialConfig.addROI(config);
    spatialDataCaulator->inputConfig.setWaitForMessage(false);


    auto xoutRgb = pipeline.create<dai::node::XLinkOut>();
    auto xoutDepth = pipeline.create<dai::node::XLinkOut>();
    auto xouSpatialData = pipeline.create<dai::node::XLinkOut>();
    auto xinspatialCalcConfig = pipeline.create<dai::node::XLinkIn>();

    xoutRgb->setStreamName("rgb");
    xoutDepth->setStreamName("depth");
    xouSpatialData->setStreamName("spatialData");
    xinspatialCalcConfig->setStreamName("spatialCalcConfig");


    // Linking
    camRgb->video.link(xoutRgb->input);
    monoLeft->out.link(stereo->left);
    monoRight->out.link(stereo->right);

    stereo->depth.link(spatialDataCaulator->inputDepth);
    spatialDataCaulator->passthroughDepth.link(xoutDepth->input);


    spatialDataCaulator->out.link(xouSpatialData->input);
    xinspatialCalcConfig->out.link(spatialDataCaulator->inputConfig);

    // Connect to device and start pipeline
    device.startPipeline(pipeline);


    // Output queue will be used to get the depth frames from the outputs defined above
    auto rgbQueue = device.getOutputQueue("rgb",8,false);
    auto depthQueue = device.getOutputQueue("depth", 8, false);
    auto spatialCalcQueue = device.getOutputQueue("spatialData", 8, false);
    auto spatialCalcConfigInQueue = device.getInputQueue("spatialCalcConfig");


    auto color = cv::Scalar(255,255,255);

    std::cout << "Use WASD keys to move ROI!" << std::endl;

    while (true) {
        auto inRgb = rgbQueue->get<dai::ImgFrame>();
        auto inDepth = depthQueue->get<dai::ImgFrame>();

        cv::Mat rgbFrame = inRgb->getCvFrame();
        cv::Mat depthFrame = inDepth->getCvFrame();

        cv::Mat depthFrameColor;
        cv::normalize(depthFrame, depthFrameColor, 255, 0, cv::NORM_INF, CV_8UC1);
        cv::equalizeHist(depthFrameColor, depthFrameColor);
        cv::applyColorMap(depthFrameColor, depthFrameColor, cv::COLORMAP_JET);

        auto spatialData = spatialCalcQueue->get<dai::SpatialLocationCalculatorData>()->getSpatialLocations();
        for(auto depthData : spatialData) {
            auto roi = depthData.config.roi;
            roi = roi.denormalize(depthFrameColor.cols, depthFrameColor.rows);
            auto xmin = (int)roi.topLeft().x;
            auto ymin = (int)roi.topLeft().y;
            auto xmax = (int)roi.bottomRight().x;
            auto ymax = (int)roi.bottomRight().y;

            auto depthMin = depthData.depthMin;
            auto depthMax = depthData.depthMax;

            cv::rectangle(depthFrameColor, cv::Rect(cv::Point(xmin, ymin), cv::Point(xmax, ymax)), color, cv::FONT_HERSHEY_SIMPLEX);
            std::stringstream depthX;
            depthX << "X: " << (int)depthData.spatialCoordinates.x << " mm";
            cv::putText(depthFrameColor, depthX.str(), cv::Point(xmin + 10, ymin + 20), cv::FONT_HERSHEY_TRIPLEX, 0.5, color);
            std::stringstream depthY;
            depthY << "Y: " << (int)depthData.spatialCoordinates.y << " mm";
            cv::putText(depthFrameColor, depthY.str(), cv::Point(xmin + 10, ymin + 35), cv::FONT_HERSHEY_TRIPLEX, 0.5, color);
            std::stringstream depthZ;
            depthZ << "Z: " << (int)depthData.spatialCoordinates.z << " mm";
            cv::putText(depthFrameColor, depthZ.str(), cv::Point(xmin + 10, ymin + 50), cv::FONT_HERSHEY_TRIPLEX, 0.5, color);

            cv::rectangle(rgbFrame, cv::Rect(cv::Point(xmin, ymin), cv::Point(xmax, ymax)), color, cv::FONT_HERSHEY_SIMPLEX);
            std::stringstream depthX_;
            depthX_ << "X: " << (int)depthData.spatialCoordinates.x << " mm";
            cv::putText(rgbFrame, depthX_.str(), cv::Point(xmin + 10, ymin + 20), cv::FONT_HERSHEY_TRIPLEX, 0.5, color);
            std::stringstream depthY_;
            depthY_ << "Y: " << (int)depthData.spatialCoordinates.y << " mm";
            cv::putText(rgbFrame, depthY_.str(), cv::Point(xmin + 10, ymin + 35), cv::FONT_HERSHEY_TRIPLEX, 0.5, color);
            std::stringstream depthZ_;
            depthZ_ << "Z: " << (int)depthData.spatialCoordinates.z << " mm";
            cv::putText(rgbFrame, depthZ_.str(), cv::Point(xmin + 10, ymin + 50), cv::FONT_HERSHEY_TRIPLEX, 0.5, color);
        }

        // Show the frame
        cv::imshow("rgb", rgbFrame);
        cv::imshow("depth", depthFrameColor);

        int key = cv::waitKey(1);
        switch(key) {
            case 'q':
                return 0;
            case 'w':
                if (topLeft.y - stepSize >= 0) {
                    topLeft.y -= stepSize;
                    bottomRight.y -= stepSize;
                    newConfig = true;
                }
                break;
            case 'a':
                if (topLeft.x - stepSize >= 0) {
                    topLeft.x -= stepSize;
                    bottomRight.x -= stepSize;
                    newConfig = true;
                }
                break;
            case 's':
                if (bottomRight.y + stepSize <= 1) {
                    topLeft.y += stepSize;
                    bottomRight.y += stepSize;
                    newConfig = true;
                }
                break;
            case 'd':
                if (bottomRight.x + stepSize <= 1) {
                    topLeft.x += stepSize;
                    bottomRight.x += stepSize;
                    newConfig = true;
                }
                break;
            default:
                break;
        }

        if(newConfig) {
            config.roi = dai::Rect(topLeft, bottomRight);
            dai::SpatialLocationCalculatorConfig cfg;
            cfg.addROI(config);
            spatialCalcConfigInQueue->send(cfg);
            newConfig = false;
        }
    }

    return 0;
}

#endif
效果图:

参考文章:

1. https://github.com/richard-xx/depthai_cpp_example/blob/main/examples/SpatialDetection/spatial_location_calculator.cpp

给定引用中未提及oak相机建立三维地图的相关内容,不过一般来说,使用oak相机建立三维地图可以按以下常规步骤进行: ### 相机初始化与配置 首先要对oak相机进行初始化,连接相机设备并配置相关参数,如分辨率、帧率等。示例代码(使用PythonDepthAI库)如下: ```python import depthai as dai # 创建管道 pipeline = dai.Pipeline() # 定义相机节点 cam_rgb = pipeline.createColorCamera() cam_rgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P) cam_rgb.setFps(30) # 定义输出节点 xout_rgb = pipeline.createXLinkOut() xout_rgb.setStreamName("rgb") cam_rgb.video.link(xout_rgb.input) ``` ### 数据采集 利用配置好的相机采集图像深度数据。代码继续如下: ```python # 连接设备并启动管道 with dai.Device(pipeline) as device: # 获取输出队列 q_rgb = device.getOutputQueue(name="rgb", maxSize=4, blocking=False) while True: # 获取RGB帧 in_rgb = q_rgb.get() frame = in_rgb.getCvFrame() # 这里可以添加深度数据采集的代码 ``` ### 特征提取与匹配 从采集到的图像中提取特征点,并在不同帧之间进行特征匹配,以确定相机的运动场景的结构。可以使用OpenCV中的特征提取器,如ORB、SIFT等。示例代码: ```python import cv2 # 初始化ORB特征提取器 orb = cv2.ORB_create() # 提取特征点描述符 kp1, des1 = orb.detectAndCompute(frame1, None) kp2, des2 = orb.detectAndCompute(frame2, None) # 创建BFMatcher对象 bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) # 匹配描述符 matches = bf.match(des1, des2) # 按距离排序 matches = sorted(matches, key=lambda x: x.distance) ``` ### 相机位姿估计 根据特征匹配结果,估计相机在不同时刻的位姿。可以使用OpenCV中的solvePnP函数。示例代码: ```python import numpy as np # 提取匹配的特征点 src_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2) # 相机内参矩阵 K = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]]) # 求解相机位姿 ret, rvec, tvec = cv2.solvePnP(object_points, src_pts, K, dist_coeffs) ``` ### 三维地图构建 根据相机的位姿深度数据,将二维图像中的点投影到三维空间中,构建三维地图。可以使用点云库(PCL)来处理可视化三维点云。示例代码: ```python import open3d as o3d # 创建点云对象 pcd = o3d.geometry.PointCloud() # 将二维图像点深度数据转换为三维点 points_3d = [] for u, v in zip(u_coords, v_coords): z = depth_map[v, u] x = (u - cx) * z / fx y = (v - cy) * z / fy points_3d.append([x, y, z]) # 设置点云的坐标 pcd.points = o3d.utility.Vector3dVector(np.array(points_3d)) # 可视化点云 o3d.visualization.draw_geometries([pcd]) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值