基于深度和运动信息相结合的方法更精确的识别出运动物体(python和C++实现)

对于基于深度图像进行分割的方法,当物体与周围深度相同时,仅利用深度信息很难识别出物体。这是因为深度信息无法提供颜色和纹理等其他视觉信息,物体边界在深度图像中不具有明显的差异或梯度。
为了解决这个问题,主要有以下一些方法:
1、结合彩色图像利用其他视觉特征:除了深度信息外,还可以使用彩色图像提供的颜色、梯度等信息。可以在深度边界不明显的区域采用基于颜色或梯度的边缘检测方法获取边界信息
2、利用深度边界信息和其他线索预测物体位置:虽然物体与周围深度相同,但其仍可能在其他方向上于周围不同,例如其轮廓形状不同。可以结合物体的3D轮廓线索和深度信息去预测其在当前视角下的大致位置和形状。
3、深度信息与运动信息相结合:当物体与周围在静止状态下深度相同时,可以采集一定时间范围内的图像序列,分析物体和场景的相对运动信息去区分物体。这样,一个移动物体可以通过与静止背景的相对运动区分出来。
4、利用学习的高级特征进行分割:可以利用卷积神经网络等方法,学习从深度图和彩色图中提取更高级的特征,这些特征可以在物体深度不明显的情况下表达物体的空间位置或边界信息,从而实现分割。
5、交互式方法获取额外信息,当自动分割方法无法有效识别物体时,可以设计一定的人机交互接口,让用户提供一定的额外信息帮助算法识别物体。如物体的大致轮廓或位置信息。

由于我本来就是要实现一个运动物体的识别,这里我采用深度信息与运动信息相结合的方法:运动信息可以很好地表达出物体与静止背景的区分,当物体与周围深度相同时,其运动信息可以成为重要的识别特征,实现物体的快速检测与分割。深度和运动信息都可以轻易达到实时效果,非常适用于我这个需要快速反应的视觉应用。其具体实现步骤如下:
1、从图像序列中计算相邻两帧的光流场,表达图像中的运动信息。光流场可以采用稠密匹配法计算获得,实习像素级的匹配和运动估计。
2、对第一帧深度图像应用Canny等边缘检测算法,得到图像中的深度轮廓,表达静止物体的结构信息
3、根据光流场与深度轮廓的一致性判断运动物体的位置:物体内部的光流矢量方向大致一致,而与物体边界深度轮廓垂直或有一定的夹角,这可以作为判断物体内外点的依据。
4、沿着深度轮廓提取出与光流场一致的轮廓点,连接成轮廓曲线,得到初步分割的物体轮廓。
5、沿着中值滤波等方法对物体轮廓对物体轮廓点进行平滑,得到较为连续的物体轮廓曲线,实现物体的初步分割。
6、在第二帧图像上根据分割的物体轮廓对物体内部点进行填充,得到物体的分割结果。
7、对物体的第三帧图像上的位置进行跟踪预测,在第三帧图像上搜索物体内部点,继续更新物体的深度轮廓和运动信息。
8、不断重复步3~7,实现对物体在图像序列中运动状态下的连续识别与精细分割。
9、根据物体在每一帧图像中的分割结果,可视化其运动轨迹和时间维的全貌。
下面给出一个简单的python和C++各实现椅子识别的版本,该简单代码实现了基于深度和运动信息的椅子识别与分割。
1、利用深度相机获取连续的预览图preview和深度图depth
2、记录首幅深度图作为静止背景depth_bg
3、计算两幅深度图像间的光流flow,表达运动信息。
4、在静止背景上检测深度轮廓contours
5、根据光流判断运动信息属于哪个深度轮廓,识别出椅子轮廓contour_chair
6、跟踪和更新椅子轮廓,实现精确分割
7、根据椅子轮廓在预览图上进行分割获得result
8、展示预览图和分割结果

import numpy as np 
import cv2
from depthai import DepthAI

# 创建管道
pipeline = DepthAI(2)   

# 创建设备
device = pipeline.create_device()

# 开始管道
device.start_pipeline()  

# 输出队列
preview_out = pipeline.get_output_queue("preview")
depth_out = pipeline.get_output_queue("depth")

while True:
    # 从预览输出中获取帧
    preview = preview_out.get()  
    preview_img = preview.getData()  

    # 从深度输出得到帧
    depth = depth_out.get() 
    depth_img = depth.getData()

    # 获取静态背景的深度帧
    if frame_cnt == 0: 
        depth_bg = depth_img 

    # 计算深度帧之间的光流
    flow = cv2.calcOpticalFlowFarneback(depth_bg, depth_img, None, 0.5, 3, 15, 3, 5, 1.2, 0)

    # 在深度背景上检测轮廓
    contours, _ = cv2.findContours(depth_bg, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  

    # 基于光流法识别椅子轮廓
    for contour in contours:
        rect = cv2.boundingRect(contour) 
        u, v = np.median(flow[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]], axis=(0, 1))
        if abs(u) > 5 or abs(v) > 5: 
            contour_chair = contour  

    # 跟踪和更新椅子的轮廓
    if contour_chair is not None: 
        ...

    # 基于椅子轮廓的分割结果
    mask = np.zeros(depth_bg.shape)
    cv2.fillPoly(mask, pts =[contour_chair], color=(255,255,255))
    result = cv2.bitwise_and(preview_img, preview_img, mask= mask)

    # 显示预览和结果
    cv2.imshow("Preview", preview_img)
    cv2.imshow("Result", result)

    key = cv2.waitKey(1)
    if key == ord('q'):
        break
#include 
#include 

using namespace cv;
using namespace std;

int main() 
{
    // 创建视频捕捉
    VideoCapture cap(0); 

    // 背景深度框架
    Mat depth_bg;

    while (true) {
        // 一帧一帧的捕捉
        Mat frame, depth;
        cap >> frame >> depth;  

        // 获取静态背景的深度帧
        if (depth_bg.empty()) 
            depth_bg = depth;  

        // 计算深度帧之间的光流
        Mat flow;
        calcOpticalFlowFarneback(depth_bg, depth, flow, 0.5, 3, 15, 3, 5, 1.2, 0);  

        // 检测轮廓
        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;
        findContours(depth_bg, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);   

        // 基于光流法识别椅子轮廓
        for (int i = 0; i < contours.size(); i++) {
            Rect rect = boundingRect(contours[i]);  
            double u, v;
            tie(u, v) = median(flow(rect.y, rect.y + rect.height,  
                                    rect.x, rect.x + rect.width)); 
            if (abs(u) > 5 || abs(v) > 5) {
                contour_chair = contours[i];
            }
        }  

        // 跟踪和更新椅子的轮廓
        if (!contour_chair.empty()) {
            ... 
        }

        // 基于椅子轮廓的分割结果
        Mat mask = Mat::zeros(depth_bg.size(), CV_8UC1);
        drawContours(mask, contour_chair, -1, Scalar(255,255,255), FILLED);  
        Mat result;
        bitwise_and(frame, frame, result, mask);

        // 显示输出图像
        imshow("Preview", frame);
        imshow("Result", result);

        // 按ESC退出
        char c = (char) waitKey(1);
        if (c == 27)
            break;
    }

    cap.release();
    destroyAllWindows(); 
}

你可能感兴趣的:(项目开发,python,c++,计算机视觉)