首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【目标跟踪】光流跟踪(python、c++代码)

【目标跟踪】光流跟踪(python、c++代码)

作者头像
读书猿
发布于 2024-02-05 07:25:24
发布于 2024-02-05 07:25:24
96105
代码可运行
举报
文章被收录于专栏:无人驾驶感知无人驾驶感知
运行总次数:5
代码可运行

前言

  1. 光流利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。
  2. 本文主要展示代码以及代码解释,对于相对应的原理,以后有机会再写(下次一定)。
  3. 本文所用数据源于网上开源数据。找不到数据的小伙伴可以私我拿数据。
  4. 文章提供 python、c++ 代码。python 代码可以直接跑通。c++ 代码集成一个 class ,可以在自己工程中使用。
  5. 效果图:

一、代码流程与思路

  1. 输入:上一帧图片、preImage 上一帧图片检测框、image 当前帧图片。 输出:当前帧光流预测框
  2. 特征点提取。对上一帧图片 preImage 提取目标框里的特征点,这里采取的是 fast 角点检测。
  3. preImage、image 光流跟踪、在 image 中找出对应的特征点。
  4. 由特征点对应关系可以得出当前帧的目标框。

二、python 代码

2.1 代码详解

(1) fast 角点检测

fast = cv2.FastFeatureDetector_create(threshold=9, nonmaxSuppression=True, type=cv2.FastFeatureDetector_TYPE_9_16)

  1. threshold:边缘轨迹点和中心点的差值阈值。
  2. nonmaxSuppression:是否进行非极大值抑制
  3. type:提供轨迹范围。我们这里是从圆周轨迹16个点,当9个满足条件,此判定圆心像素点为特征点

我们这里只对检测框里的像素做特征点检测

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def SelectPointByBox(img, det):
    top_x, top_y, bottom_x, bottom_y = [int(_) for _ in det[:4]]
    cutimg = img[max(0, top_y - 2):min(bottom_y + 2, 1080), max(0, top_x - 2):min(1920, bottom_x + 2)]
    fast = cv2.FastFeatureDetector_create(threshold=9, nonmaxSuppression=True, type=cv2.FastFeatureDetector_TYPE_9_16)
    kps = fast.detect(cutimg, 10)  # Ip-t < Ip < Ip+t
    kp = []
    for p in kps:
        t = []
        t.append(np.float32(p.pt[0] + top_x))
        t.append(np.float32(p.pt[1] + top_y))
        kp.append(np.array(t).reshape(1, 2))
    return np.array(kp)

(2) 追踪稀疏特征点

cv2.calcOpticalFlowPyrLK(preImgGray, gray, prePt, pt, **lkParms)

  1. preImgGray:前一帧图片灰度图。
  2. gray:当前帧图片灰度图
  3. prePt:前一帧图片的特征点
  4. pt:None

lkParms = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

  1. winSize: 每个金字塔级别上搜索窗口的大小
  2. maxLevel: 最大金字塔层数
  3. criteria:指定迭代搜索算法的终止条件,在指定的最大迭代次数 10 之后或搜索窗口移动小于 0.03
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def OpticalFlowLk(preImg, curImg, prePt, pt):
    lkParms = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
    gray = cv2.cvtColor(curImg, cv2.COLOR_BGR2GRAY)
    preImgGray = cv2.cvtColor(preImg, cv2.COLOR_BGR2GRAY)
    # nextPts:前一帧图像的特征点跟踪后的点  st:特征点是否找到,找到状态为1,否则为0  err:每个特征点的误差,即前一帧和当前帧中特征点的位置差异
    nextPts, st, err = cv2.calcOpticalFlowPyrLK(preImgGray, gray, prePt, pt, **lkParms)
    # print("p1", nextPts, "st", st, "err", err)
    goodNewPt = nextPts[st == 1]  # 光流跟踪后特征点
    goodOldPt = prePt[st == 1]  # 上一帧特征点
    return goodOldPt, goodNewPt

(3) 预测当前帧目标检测框

  1. 现在我们获取到了 prePt curPt pre_detect_box
  2. 由像素对应关系,我们可以求出 cur_detect_box
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def CalculateShift(prePt, curPt):
    x = curPt[:, 0] - prePt[:, 0]
    y = curPt[:, 1] - prePt[:, 1]
    avgX = np.mean(x)
    avgY = np.mean(y)
    return avgX, avgY


def get_box(ditection, prePt, curPt):
    d_x, d_y = CalculateShift(prePt, curPt)  # 计算偏移量
    box = [0] * 4
    box[0], box[2], box[1], box[3] = ditection[0] + d_x, ditection[2] + d_x, ditection[1] + d_y, ditection[3] + d_y
    return box
2.2 完整代码

代码可直接跑通

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import cv2
import os
import numpy as np


def GetImg(path, num):
    fn = os.path.join(path, 'img', '%06d.jpg' % (num))
    im = cv2.imread(fn)
    return im


def GetDetFrameRes(seq_dets, frame):
    detects = seq_dets[seq_dets[:, 0] == frame, 2:7]
    detects[:, 2:4] += detects[:, 0:2]  # convert to [x1,y1,w,h] to [x1,y1,x2,y2]
    return detects


def SelectPointByBox(img, det):
    top_x, top_y, bottom_x, bottom_y = [int(_) for _ in det[:4]]
    cutimg = img[max(0, top_y - 2):min(bottom_y + 2, 1080), max(0, top_x - 2):min(1920, bottom_x + 2)]
    fast = cv2.FastFeatureDetector_create(threshold=9, nonmaxSuppression=True, type=cv2.FastFeatureDetector_TYPE_9_16)
    kps = fast.detect(cutimg, 10)  # Ip-t < Ip < Ip+t
    kp = []
    for p in kps:
        t = []
        t.append(np.float32(p.pt[0] + top_x))
        t.append(np.float32(p.pt[1] + top_y))
        kp.append(np.array(t).reshape(1, 2))
    return np.array(kp)


def OpticalFlowLk(preImg, curImg, prePt, pt):
    lkParms = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
    gray = cv2.cvtColor(curImg, cv2.COLOR_BGR2GRAY)
    preImgGray = cv2.cvtColor(preImg, cv2.COLOR_BGR2GRAY)
    # nextPts:前一帧图像的特征点跟踪后的点    st:特征点是否找到,找到状态为1,否则为0     err:每个特征点的误差,即前一帧和当前帧中特征点的位置差异
    nextPts, st, err = cv2.calcOpticalFlowPyrLK(preImgGray, gray, prePt, pt, **lkParms)
    # print("p1", nextPts, "st", st, "err", err)
    goodNewPt = nextPts[st == 1]  # 光流跟踪后特征点
    goodOldPt = prePt[st == 1]  # 上一帧特征点
    return goodOldPt, goodNewPt


def CalculateShift(prePt, curPt):
    x = curPt[:, 0] - prePt[:, 0]
    y = curPt[:, 1] - prePt[:, 1]
    avgX = np.mean(x)
    avgY = np.mean(y)
    return avgX, avgY


def get_box(ditection, prePt, curPt):
    d_x, d_y = CalculateShift(prePt, curPt)  # 计算偏移量
    box = [0] * 4
    box[0], box[2], box[1], box[3] = ditection[0] + d_x, ditection[2] + d_x, ditection[1] + d_y, ditection[3] + d_y
    return box


def Test():
    pathroot = ".\\"
    resPath = pathroot + "det.txt"
    video_path = pathroot + "video.mp4"
    video = cv2.VideoWriter(video_path, cv2.VideoWriter_fourcc('m', 'p', '4', 'v'), 10, (1920, 1080))
    detRes = np.loadtxt(resPath, delimiter=',')
    preImg = GetImg(pathroot, 1)  # 初始化为000001.jpg   preImg:上一帧图片
    for num in range(2, int(max(detRes[:, 0]))):
        print(num)
        img = GetImg(pathroot, num)  # img:当前帧图片
        dets = GetDetFrameRes(detRes, num - 1)  # 上一帧图片的检测框
        drawImg = img.copy()
        for i in range(len(dets)):
            detect = dets[i]  # 上一帧图片的单个框
            boxKeyPt = SelectPointByBox(preImg, detect)  # 找在框里的关键点
            if (len(boxKeyPt) < 3):
                continue  # 框里关键点少于3 不做跟踪
            prePt, curPt = OpticalFlowLk(preImg, img, boxKeyPt, None)
            bbox = get_box(detect, prePt, curPt)
            if np.isnan(bbox[0]): continue
            for i in range(curPt.shape[0] - 1, -1, -1):
                c, d = curPt[i].ravel()
                if not (max(0, bbox[0] - 2) <= c <= min(1920, bbox[2] + 2) and
                        max(0, bbox[1] - 2) <= d <= min(1080, bbox[3] + 2)):
                    prePt = np.delete(prePt, i, 0)
                    curPt = np.delete(curPt, i, 0)
            new_b = get_box(detect, prePt, curPt)  # 最终框
            if np.isnan(new_b[0]): continue
            cv2.rectangle(drawImg, (int(new_b[0]), int(new_b[1])), (int(new_b[2]), int(new_b[3])), (96, 48, 176), 2)
            mask = np.zeros_like(preImg)
            color = np.random.randint(0, 255, (20000, 3))
            for i, (new, old) in enumerate(zip(prePt, curPt)):
                a, b = new.ravel()
                c, d = old.ravel()
                mask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), color[i].tolist(), 2)
                drawImg = cv2.circle(drawImg, (int(a), int(b)), 1, color[i].tolist(), -1)
            drawImg = cv2.add(drawImg, mask)

        cv2.imshow("img", drawImg)
        cv2.waitKey(10)
        preImg = img.copy()
        video.write(drawImg)
    video.release()


if __name__ == "__main__":
    Test()

三、c++ 代码

  1. Optical(std::vector<cv::Rect_> boxes, cv::Mat preImg, cv::Mat curImg) 构造函数
  2. void OpticalDeal(); 处理计算
  3. std::vector<cv::Rect_> GetBoxResult(); 获取结果

Optical.h 文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <vector>
#include "opencv2/opencv.hpp"
#include "opencv2/features2d.hpp"


class Optical
{
public:
    Optical(std::vector<cv::Rect_<float>> boxes, cv::Mat preImg, cv::Mat curImg)
    {
        mBoxes = boxes;
        mCurImg = curImg;
        mPreImg = preImg;
    }   
    void OpticalDeal();                                     // 计算
    std::vector<cv::Rect_<float>> GetBoxResult();           // 获取光流跟踪后得到的结果框 

private:
    std::vector<cv::Point2f> GetCornorPoint();              // fast检测关键点坐标
    cv::Rect_<float> GetExpBox(cv::Rect_<float> box);       // 获取比检测框大pixeParam像素的框
    void OpticalFlowLk(std::vector<cv::Point2f> prePt);     // 光流跟踪
    cv::Rect_<float> GetUpdateBox(cv::Rect_<float> box, std::vector<cv::Point2f> prePoints, std::vector<cv::Point2f> curPoints);    // 修正框
    void SelectPt(cv::Rect_<float> box, std::vector<cv::Point2f> &prePoints, std::vector<cv::Point2f> &curPoints);                  // 选取合适的关键点 过滤一部分关键点
    cv::Rect_<float> CorrectBox(cv::Rect_<float> box); 

private:
    int pixeParam = 2;                      // 关键点选取像素参数 多截取pixeParam像素
    int fastFeatureDetectParam = 10;        // fast关键点检测参数,参数越小,关键点检测越多
    int keyPointCountParam = 3;             // 检测框里关键点较少就不进行光流跟踪
    std::vector<int> mIndex = {0};          // 光流跟踪每个框关键点的索引位置 
    std::vector<cv::Rect_<float>> mBoxes;   // 检测框
    cv::Mat mPreImg;                        // 上一帧图
    cv::Mat mCurImg;                        // 当前图片
};  

Optical.cpp 文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "Optical.h"

std::vector<cv::Rect_<float>> Optical::GetBoxResult()
{
    return mBoxes;
}

void Optical::OpticalDeal()
{
    std::vector<cv::Point2f> fastKeyPoint = GetCornorPoint();   // fast检测的角点
    OpticalFlowLk(fastKeyPoint);                                // 光流跟踪 获取点与点匹配
}

std::vector<cv::Point2f> Optical::GetCornorPoint()
{   
    std::vector<cv::Point2f> res;
    cv::Ptr<cv::FastFeatureDetector> detector = cv::FastFeatureDetector::create(fastFeatureDetectParam);
    int num = 0;                                            // 计数多少个关键点 
    for (int i = 0; i < mBoxes.size(); ++i) {
        std::vector<cv::KeyPoint> keyPoints;
        cv::Rect_<float> newBox = GetExpBox(mBoxes[i]);
        cv::Mat image = mPreImg(newBox);                    // 截取检测框检测的图片
        detector->detect(image, keyPoints);
        num = num + keyPoints.size();
        mIndex.push_back(num);
        for (auto points:keyPoints) {
            points.pt = points.pt + cv::Point_<float>(newBox.x, newBox.y);
            res.push_back(points.pt);
        }
    }
    return res;
}

void Optical::OpticalFlowLk(std::vector<cv::Point2f> prePt)
{
    cv::Mat curImgGray, preImgGray;
    std::vector<uchar> status;
	std::vector<float> err;
    cv::cvtColor(mCurImg, curImgGray, cv::COLOR_RGBA2GRAY);     // 当前图片灰度
    cv::cvtColor(mPreImg, preImgGray, cv::COLOR_RGBA2GRAY);     // 上一帧图片灰度
    std::vector<cv::Point2f> pt;
    cv::calcOpticalFlowPyrLK(preImgGray, curImgGray, prePt, pt, status, err); 
    for (int i = 0; i < mIndex.size() - 1; ++i) {
        int leftIndex = mIndex[i], rightIndex = mIndex[i + 1];
        // 关键点太少不进行光流跟踪(1)
        if (rightIndex - leftIndex >= keyPointCountParam) {
            std::vector<cv::Point2f> preIndexPt(prePt.begin() + leftIndex, prePt.begin() + rightIndex);
            std::vector<cv::Point2f> indexPt(pt.begin() + leftIndex, pt.begin()+rightIndex);
            std::vector<uchar> indexStatus(status.begin() + leftIndex, status.begin()+rightIndex);
            int length = preIndexPt.size(); 
            for (int j = length - 1 ; j > -1; --j) {
                if (status[j] != 1) {
                    indexPt.erase(indexPt.begin() + i);
                    preIndexPt.erase(preIndexPt.begin() + j);
                }
            }
            // 跟踪到的关键点少不进行光流跟踪(2)
            if (preIndexPt.size() > keyPointCountParam) {
                cv::Rect_<float> newBox = GetUpdateBox(mBoxes[i], preIndexPt, indexPt);
                SelectPt(newBox, preIndexPt, indexPt);
                if (preIndexPt.size() > keyPointCountParam) {
                    mBoxes[i] = GetUpdateBox(mBoxes[i], preIndexPt, indexPt);
                }
            }
        }
    }
}

// expend pixeParam bounding box to optical track
cv::Rect_<float> Optical::GetExpBox(cv::Rect_<float> box) 
{
    cv::Rect_<float> newBox = box + cv::Point_<float>(-pixeParam, -pixeParam) + cv::Size_<float>(2 * pixeParam, 2 * pixeParam);
    return CorrectBox(newBox);
}

cv::Rect_<float> Optical::GetUpdateBox(cv::Rect_<float> box, std::vector<cv::Point2f> prePoints, std::vector<cv::Point2f> curPoints)
{
    float avgX = 0, avgY = 0;
    int length = prePoints.size();
    for (int i = 0; i < length; ++i) {
        avgX += curPoints[i].x - prePoints[i].x;
        avgY += curPoints[i].y - prePoints[i].y;
    }
    avgX = avgX / length;
    avgY = avgY / length;
    cv::Rect_<float> resBox = box + cv::Point_<float>(avgX, avgY);
    return CorrectBox(resBox);
}

void Optical::SelectPt(cv::Rect_<float> box, std::vector<cv::Point2f> &prePoints, std::vector<cv::Point2f> &curPoints)
{
    int length = prePoints.size();
    for (int i = length - 1 ; i >= 0; --i) {
        float x = curPoints[i].x, y = curPoints[i].y;
        if (x < (box.x - pixeParam) || x > (box.x + box.width + pixeParam) || y < (box.y - pixeParam) || y > (box.y + box.height + pixeParam)) {
            curPoints.erase(curPoints.begin() + i);
            prePoints.erase(prePoints.begin() + i);
        }
    }
}

// correct box when box beyond border
cv::Rect_<float> Optical::CorrectBox(cv::Rect_<float> box)
{
    int w = mPreImg.cols, h = mPreImg.rows;
    box.x = (box.x <= 0) ? 0 : box.x;
    box.y = (box.y <= 0) ? 0 : box.y;
    box.width = ((box.width + box.x) >= w - 1) ? w - box.x - 1 : box.width;
    box.height = ((box.height + box.y) >= h - 1) ? h - box.y - 1 : box.height;
    return box;
}

四、结果展示

由于上传限制,只上传 gif 压缩结果

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
跟踪算法(一)光流法跟踪
COPY FROM:http://blog.csdn.net/crzy_sparrow/article/details/7407604
全栈程序员站长
2022/09/15
1.4K0
干货 | OpenCV中KLT光流跟踪原理详解与代码演示
在视频移动对象跟踪中,稀疏光流跟踪是一种经典的对象跟踪算法,可以绘制运动对象的跟踪轨迹与运行方向,是一种简单、实时高效的跟踪算法,这个算法最早是有Bruce D. Lucas and Takeo Kanade两位作者提出来的,所以又被称为KLT。KLT算法工作有三个假设前提条件:
OpenCV学堂
2018/11/30
7.8K0
干货 | OpenCV中KLT光流跟踪原理详解与代码演示
【目标跟踪】提供一种简单跟踪测距方法(c++)
这部分代码就是整个跟踪代码的框架了,我已经对代码尽可能的做了简化。注释也算比较详细。
读书猿
2024/02/18
5230
【目标跟踪】提供一种简单跟踪测距方法(c++)
【目标跟踪】奇葩需求如何处理(二)
昨天突然接到一个需求,识别井盖且判断是否有井盖或无井盖。而且时间紧急,比赛突然加的需求,只给一天时间。一天时间用深度学习方法大概率是来不及了,采集数据标注数据训练模型都要花时间。
读书猿
2024/03/22
1890
【目标跟踪】奇葩需求如何处理(二)
SLAM程序阅读(第8讲 LK光流法)
细心的同学已经发现,小绿换了文章的封皮,因为有一些同学都觉得原来那张图比较捞,不沉稳也不正经…而更细心的同学也会发现,小绿连题目都改了,原来叫“解读”,现在叫“阅读”,这也是因为一些热心的同学在后台积极提问,然而小绿作为一个门徒,实在是有些束手无策,没法很透彻的解答同学们的问题…
小白学视觉
2019/10/24
1.4K0
海面漂浮物垃圾识别检测算法
海面漂浮物垃圾识别检测算法通过yolo系列网络框架模型算法,海面漂浮物垃圾识别检测算法一旦识别到海面的漂浮物垃圾,海面漂浮物垃圾识别检测算法立即发出预警信号。海面漂浮物垃圾识别检测算法目标检测架构分为两种,一种是two-stage,一种是one-stage,区别就在于 two-stage 有region proposal过程,类似于一种海选过程,网络会根据候选区域生成位置和类别,而one-stage直接从图片生成位置和类别
燧机科技
2023/09/22
5540
海面漂浮物垃圾识别检测算法
光流法测距
(1)亮度恒定,就是同一点随着时间的变化,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;
全栈程序员站长
2022/09/15
7060
【目标跟踪】相机运动补偿
Tracking-by-detection 成为 MOT 任务中最有效的范式。Tracking-by-detection 包含一个步骤检测步骤,然后是一个跟踪步骤。跟踪步骤通常由2个主要部分组成:
读书猿
2024/02/05
1.1K0
【目标跟踪】相机运动补偿
目标跟踪与定位——Introduction to motion
要随着时间变化来跟踪物体并检测动作: 方法之一是提取特定的特征 观察这些特征是怎么从一帧变化到下一帧的,这里可以用到光流法(optical flow)。
小飞侠xp
2018/10/12
1.2K0
目标跟踪与定位——Introduction to motion
OpenCV中的光流及视频特征点追踪
这篇博客将介绍光流的概念以及如何使用 Lucas-Kanade 方法估计光流,并演示如何使用 cv2.calcOpticalFlowPyrLK() 来跟踪视频中的特征点。
玖柒的小窝
2021/10/25
1.2K0
高翔Slambook第七讲代码解读(三角测量)
在前面几期中,小绿简单的解读了第七讲的几个程序,运行这些程序或调用这些程序包装成的函数可以实现:
小白学视觉
2019/10/24
2.5K0
高翔Slambook第七讲代码解读(三角测量)
PaddleOCR C++(三)---动态库返回识别结果及矩形位置
《PaddleOCR C++学习笔记(二)》尝试做图像的分割,结果都效果不明显,所以这篇我们从OCR识别这里来处理,将返回的识别字符和对应的识别矩形框都显示出来,用于区分识别的效果。
Vaccae
2021/07/30
2.4K1
PaddleOCR C++(三)---动态库返回识别结果及矩形位置
SLAM程序阅读(第8讲 稀疏直接法)
本次阅读的程序为第八章的第2个程序direct_sparse.cpp,该程序实现了稀疏直接法进行位姿变换的计算。
小白学视觉
2019/10/24
6740
OpenCV4.5.x DNN + YOLOv5 C++推理
点击上方蓝字关注我们 微信公众号:OpenCV学堂 关注获取更多计算机视觉与深度学习知识 引言 昨天修改了个OpenCV DNN支持部署YOLOv5,6.1版本的Python代码,今天重新转换为C++代码了!貌似帧率比之前涨了点!说明C++的确是比Python快点! 点击这里可以查看之前的推文: OpenCV4.5.4 直接支持YOLOv5 6.1版本模型推理 OpenC4 C++部署YOLOv5 我把测试代码封装成一个工具类了,可以直接用,方便大家(生手党)直接部署调用!保重一行代码都不用再写了! 0
OpenCV学堂
2022/03/10
3.1K0
【失败也分享】C++ OpenCV人脸Delaunay三角形提取及仿射变换的使用
最近这几篇OpenCV相关的文章都是与人脸有关,其实最主要是就是想做人脸替换的小试验,大概流程是:
Vaccae
2021/03/12
1.8K0
代码解读 | VINS 视觉前端
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
用户1150922
2019/09/06
1.3K0
[C++]使用yolov5的onnx模型结合onnxruntime和bytetrack实现目标追踪
yolov5框架:https://github.com/ultralytics/yolov5
云未归来
2025/07/17
1370
[C++]使用yolov5的onnx模型结合onnxruntime和bytetrack实现目标追踪
OpenCV+OpenGL 双目立体视觉三维重建
这篇文章主要为了研究双目立体视觉的最终目标——三维重建,系统的介绍了三维重建的整体步骤。双目立体视觉的整体流程包括:图像获取,摄像机标定,特征提取(稠密匹配中这一步可以省略),立体匹配,三维重建。我在做双目立体视觉问题时,主要关注的点是立体匹配,本文主要关注最后一个步骤三维重建中的:三角剖分和纹理贴图以及对应的OpenCV+OpenGL代码实现。
流川疯
2019/01/18
5.8K0
高翔Slambook第七讲代码解读(3d-2d位姿估计)
上回咱们读完了pose_estimation_2d2d.cpp这个文件,基本上明白了通过对极几何计算相机位姿变换的过程,简单地说就是:你给我两帧图像,我给你算个R、t。
小白学视觉
2019/10/24
1.8K0
python光流法算法学习「建议收藏」
光流法是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。 简单来说,光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”。光流的研究是利用图像序列中的像素强度数据的时域变化和相关性来确定各自像素位置的“运动”。研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。
全栈程序员站长
2022/09/15
1.8K0
相关推荐
跟踪算法(一)光流法跟踪
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档