【OpenCv光流法进行运动目标检测】

news2024/11/25 6:35:20

opencv系列文章目录

文章目录

  • opencv系列文章目录
  • 前言
  • 一、光流法是什么?
  • 二、光流法实例
    • 1.C的
    • 2.C++版本
    • 3.python版本
  • 总结


前言

随着计算机视觉技术的迅猛发展,运动目标检测在图像处理领域中扮演着至关重要的角色。在现实世界中,我们常常需要追踪视频中的运动目标,例如交通摄像头中的车辆、安防监控中的行人,甚至是自动驾驶领域中的车辆和行人。为了实现高效准确的运动目标检测,研究者们提出了各种各样的方法。

在众多运动目标检测方法中,光流法(Optical Flow)是一种经典且有效的技术。光流法通过追踪图像中像素点的运动轨迹,可以帮助我们实时了解运动目标的位置和速度信息。它不仅在实时性上具有优势,还在处理各种环境和运动类型下都表现出色。


一、光流法是什么?

光流法(Optical Flow)是计算机视觉领域中一种经典的技术,用于描述图像序列中像素点在时间上的运动轨迹。光流法的基本思想源于图像中的像素在相邻帧之间随时间的变化,通过检测像素点的移动,我们可以获得关于场景中物体运动的重要信息。这种技术在目标跟踪、运动分析、视觉导航等领域得到广泛应用。

光流法的基本假设是,相邻帧之间相邻像素的灰度值在短时间内基本保持不变。根据这个假设,光流法通过分析图像序列中相邻帧之间的灰度值变化,推断出像素点的运动信息。它可以帮助我们了解运动目标的速度、方向和轨迹,甚至可以用于运动目标的跟踪和分割。

在实际应用中,光流法的算法有多种。其中,Lucas-Kanade方法是最常见的一种,它假设了图像中的运动是局部的,即在图像上某一点附近的像素具有相似的运动。该方法通过计算像素点周围区域的梯度和时间上的灰度变化,求解一个线性方程组,从而估计出光流向量。另外,Horn-Schunck方法则假设了整幅图像的运动是平滑的,并且在整个图像上求解一个全局的光流场。

光流法的应用非常广泛。在视频压缩中,光流信息可以用于帧内预测,提高压缩效率。在自动驾驶领域,光流法可以用于车辆和行人的运动轨迹预测,帮助车辆规划路径。在医学图像分析中,光流法可以用于心脏和血流的运动分析,帮助医生诊断心脏疾病。

总的来说,光流法作为一种经典的计算机视觉技术,为我们提供了探测运动目标、分析动态场景的重要手段。它的应用不仅帮助我们更好地理解图像序列中的运动信息,也推动了计算机视觉领域的发展。
几种光流估计算法的简介

1) 基于梯度的方法

基于梯度的方法又称为微分法,它是利用时变图像灰度(或其滤波形式)的时空微分(即时空梯度函数)来计算像素的速度矢量。

由于计算简单和较好的结果,该方法得到了广泛应用和研究。典型的代表是Horn-Schunck算法与Lucas-Kanade(LK)算法。

Horn-Schunck算法在光流基本约束方程的基础上附加了全局平滑假设,假设在整个图像上光流的变化是光滑的,即物体运动矢量是平滑的或只是缓慢变化的。

基于此思想,大量的改进算法不断提出。Nagel采用有条件的平滑约束,即通过加权矩阵的控制对梯度进行不同平滑处理;Black和Anandan针对多运动的估计问题,提出了分段平滑的方法。

  1. 基于匹配的方法

基于匹配的光流计算方法包括基于特征和区域的两种。

基于特征的方法不断地对目标主要特征进行定位和跟踪,对目标大的运动和亮度变化具有鲁棒性。存在的问题是光流通常很稀疏,而且特征提取和精确匹配也十分困难。

基于区域的方法先对类似的区域进行定位,然后通过相似区域的位移计算光流。这种方法在视频编码中得到了广泛的应用。然而,它计算的光流仍不稠密。另外,这两种方法估计亚像素精度的光流也有困难,计算量很大。

3)基于能量的方法

基于能量的方法又称为基于频率的方法,在使用该类方法的过程中,要获得均匀流场的准确的速度估计,就必须对输入的图像进行时空滤波处理,即对时间和空间的整合,但是这样会降低光流的时间和空间分辨率。基于频率的方法往往会涉及大量的计算,另外,要进行可靠性评价也比较困难。

4)基于相位的方法

基于相位的方法是由Fleet和Jepson提出的,Fleet和Jepson最先提出将相位信息用于光流计算的思想。当我们计算光流的时候,相比亮度信息,图像的相位信息更加可靠,所以利用相位信息获得的光流场具有更好的鲁棒性。基于相位的光流算法的优点是:对图像序列的适用范围较宽,而且速度估计比较精确,但也存在着一些问题:第一,基于相位的模型有一定的合理性,但是有较高的时间复杂性;第二,基于相位的方法通过两帧图像就可以计算出光流,但如果要提高估计精度,就需要花费一定的时间;第三,基于相位的光流计算法对图像序列的时间混叠是比较敏感的。

5)神经动力学方法

神经动力学方法是利用神经网络建立的视觉运动感知的神经动力学模型,它是对生物视觉系统功能与结构比较直接的模拟。

尽管光流计算的神经动力学方法还很不成熟,然而对它的研究却具有极其深远的意义。随着生物视觉研究的不断深入,神经方法无疑会不断完善,也许光流计算乃至计算机视觉的根本出路就在于神经机制的引入。神经网络方法是光流技术的一个发展方向。

3.稠密光流与稀疏光流

除了根据原理的不同来区分光流法外,还可以根据所形成的光流场中二维矢量的疏密程度将光流法分为稠密光流与稀疏光流两种。

二、光流法实例

1.C的

设置参数放到C#版本里面,效果好像没有C++效果来的明显,可能是一些参数的设置导致的。

代码如下(示例):

using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Windows.Forms;

namespace WindowsFormsApp
{
    public partial class Form1 : Form
    {
        // 当前图片
        public Mat gray = new Mat();      
        // 预测图片
        public Mat gray_prev = new Mat();
        // point1为特征点的原来位置,point2为特征点的新位置
        public Point2f[] points1;
        public Point2f[] points2;
        // 初始化跟踪点的位置
        public Point2f[] initial;
        // 检测的最大特征数
        public int maxCount = 500;         
        // 特征检测的等级
        public double qLevel = 0.01;       
        // 两特征点之间的最小距离
        public double minDist = 10.0;     
        // 跟踪特征的状态,特征的流发现为1,否则为0
        public byte[] status;       
        public float[] err;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var capture = new VideoCapture(@"1.avi");
            // 计算帧率
            int sleepTime = (int)Math.Round(1000 / capture.Fps);
      
            // 声明实例 Mat类
            Mat image = new Mat();
            // 进入读取视频每镇的循环
            while (true)
            {
                capture.Read(image);
                //判断是否还有没有视频图像 
                if (image.Empty())
                    break;

                Mat result = tracking(image);

                // 在pictureBox1中显示效果图
                pictureBox1.Image = BitmapConverter.ToBitmap(result);
                Cv2.WaitKey(sleepTime);
            }
        }

        //--------------------------------------
        // function: tracking
        // brief: 跟踪
        // parameter: frame 输入的视频帧
        //            output 有跟踪结果的视频帧
        // return: void
        //--------------------------------------
        public Mat tracking(Mat frame)
        {
            Mat output = new Mat();
            Cv2.CvtColor(frame, gray, ColorConversionCodes.BGR2GRAY);
            frame.CopyTo(output);

            // 添加特征点
            if (addNewPoints())
            {
                // 只用这个好像也没啥区别
                points1 = Cv2.GoodFeaturesToTrack(gray, maxCount, qLevel, minDist, new Mat(), 10, true, 0.04);
                initial = points1;

                 像素级检测特征点
                //Point2f[] po = Cv2.GoodFeaturesToTrack(gray, maxCount, qLevel, minDist, new Mat(), 3, true, 0.04);
                 亚像素级检测
                //points1 = Cv2.CornerSubPix(gray, po, new Size(5, 5), new Size(-1, -1), new TermCriteria());
            }
            if (gray_prev.Empty())
            {
                gray.CopyTo(gray_prev);
            }

           //光流金字塔,输出图二的特征点
            points2 = new Point2f[points1.Length];
            Cv2.CalcOpticalFlowPyrLK(gray_prev, gray, points1, ref points2, out status, out err);

            // 去掉一些不好的特征点
            int k = 0;
            for (int i = 0; i < points2.Length; i++)
            {
                if (acceptTrackedPoint(i))
                {
                    initial[k] = initial[i];
                    points2[k++] = points2[i];
                }
            }

            // 显示特征点和运动轨迹
            for (int i = 0; i < k; i++)
            {
                Cv2.Line(output, (Point)initial[i], (Point)points2[i],new Scalar(0, 0, 255));
                Cv2.Circle(output, (Point)points2[i], 3,new Scalar(0, 255, 0), -1);
            }

            // 把当前跟踪结果作为下一此参考
            Swap(ref points2, ref points1);
            Swap(ref gray_prev, ref gray);
            return output;
        }

        static void Swap<T>(ref T a, ref T b)
        {
            T t = a;
            a = b;
            b = t;
        }

        //-------------------------------------
        // function: addNewPoints
        // brief: 检测新点是否应该被添加
        // parameter:
        // return: 是否被添加标志
        //-------------------------------------
        public bool addNewPoints()
        {
            if (points1 == null) return true;

            // 这个实际上是限制了点数,最好别开
            //return  points1.Length <= 10;
            //System.Diagnostics.Debug.WriteLine(points1.Length);
            return true;
        }

        //--------------------------------------
        // function: acceptTrackedPoint
        // brief: 决定哪些跟踪点被接受
        // parameter:
        // return:
        //-------------------------------------
        bool acceptTrackedPoint(int i)
        {
            return status[i] == 1 && ((Math.Abs(points1[i].X - points2[i].X) + Math.Abs(points1[i].Y - points2[i].Y)) > 5);
        }
    }
}

这段代码是一个基于OpenCVSharp的C#程序,实现了光流法(Optical Flow)在视频中的运动目标跟踪。下面对代码进行逐行解释:

using OpenCvSharp; 和 using OpenCvSharp.Extensions;:导入OpenCVSharp库的命名空间,该库是OpenCV的C#封装。

public partial class Form1 : Form:定义一个名为Form1的Windows窗体类,该类继承自基类Form。

类中声明了一系列变量,如gray和gray_prev是用于存储灰度图像的Mat对象,points1和points2是特征点的原始和新位置,initial是特征点的初始位置,status和err是用于存储光流算法的状态和误差的数组。

public Form1():构造函数,初始化窗体。

private void button1_Click(object sender, EventArgs e):按钮点击事件的处理函数,该函数实现了视频的读取和光流法运动目标跟踪。

    var capture = new VideoCapture(@"1.avi");:打开名为"1.avi"的视频文件。

    Mat image = new Mat();:创建一个Mat对象用于存储视频帧。

    while (true):无限循环,用于处理视频的每一帧。

    capture.Read(image);:读取视频的一帧。

    Mat result = tracking(image);:调用tracking函数进行运动目标跟踪。

    pictureBox1.Image = BitmapConverter.ToBitmap(result);:将跟踪结果显示在Windows窗体中。

public Mat tracking(Mat frame):跟踪函数,接受一个视频帧作为输入,返回一个Mat对象,其中包含了运动目标的跟踪结果。

    Cv2.CvtColor(frame, gray, ColorConversionCodes.BGR2GRAY);:将彩色图像转换为灰度图像。

    addNewPoints():检测是否需要添加新的特征点。

    Cv2.CalcOpticalFlowPyrLK(gray_prev, gray, points1, ref points2, out status, out err);:使用Lucas-Kanade光流法计算特征点的新位置。

    acceptTrackedPoint(int i):根据状态和位置信息,决定哪些跟踪点被接受。

    将跟踪结果画在output图像上,返回output。

    Swap(ref points2, ref points1); 和 Swap(ref gray_prev, ref gray);:交换points2和points1、gray_prev和gray的引用。

总的来说,这段代码实现了一个简单的视频运动目标跟踪系统。它使用Lucas-Kanade光流法计算特征点的运动轨迹,将跟踪结果实时显示在Windows窗体中。需要注意的是,该代码仅实现了基本的光流跟踪功能,实际应用中可能需要更多的优化和改进,例如处理光照变化、遮挡等问题。

2.C++版本

代码如下(示例):

#include <opencv2/video/video.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

void tracking(Mat& frame, Mat& output);
bool addNewPoints();
bool acceptTrackedPoint(int i);

string window_name = "optical flow tracking";
Mat gray;	    // 当前图片
Mat gray_prev;	// 预测图片
vector<Point2f> points[2];	// point0为特征点的原来位置,point1为特征点的新位置
vector<Point2f> initial;	// 初始化跟踪点的位置
vector<Point2f> features;	// 检测的特征
int maxCount = 500;	        // 检测的最大特征数
double qLevel = 0.01;	    // 特征检测的等级
double minDist = 10.0;	    // 两特征点之间的最小距离
vector<uchar> status;	    // 跟踪特征的状态,特征的流发现为1,否则为0
vector<float> err;

int main()
{
	Mat frame;
	Mat result;
	VideoCapture capture("1.avi");

	if (capture.isOpened())	// 摄像头读取文件开关
	{
		capture >> frame;
		imshow(window_name, frame);
		waitKey(0);
		while (true)
		{
			capture >> frame;
			if (frame.empty()) break;
			tracking(frame, result);
			imshow(window_name, result);
			
			if ((char)waitKey(50) == 27)
			{
				break;
			}
		}
	}
	return 0;
}

//--------------------------------------
// function: tracking
// brief: 跟踪
// parameter: frame	输入的视频帧
//			  output 有跟踪结果的视频帧
// return: void
//--------------------------------------
void tracking(Mat& frame, Mat& output)
{
	//此句代码的OpenCV3版为:
	cvtColor(frame, gray, COLOR_BGR2GRAY);
	//此句代码的OpenCV2版为:
	//cvtColor(frame, gray, CV_BGR2GRAY);
	frame.copyTo(output);
	// 添加特征点
	if (addNewPoints())
	{
		goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);
		points[0].insert(points[0].end(), features.begin(), features.end());
		initial.insert(initial.end(), features.begin(), features.end());
	}
	if (gray_prev.empty())
	{
		gray.copyTo(gray_prev);
	}
	// l-k光流法运动估计
	calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);
	// 去掉一些不好的特征点
	int k = 0;
	for (size_t i = 0; i < points[1].size(); i++)
	{
		if (acceptTrackedPoint(i))
		{
			initial[k] = initial[i];
			points[1][k++] = points[1][i];
		}
	}
	points[1].resize(k);
	initial.resize(k);
	// 显示特征点和运动轨迹
	for (size_t i = 0; i < points[1].size(); i++)
	{
		line(output, initial[i], points[1][i], Scalar(0, 0, 255));
		circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);
	}

	// 把当前跟踪结果作为下一此参考
	swap(points[1], points[0]);
	swap(gray_prev, gray);
}

//-------------------------------------
// function: addNewPoints
// brief: 检测新点是否应该被添加
// parameter:
// return: 是否被添加标志
//-------------------------------------
bool addNewPoints()
{
	return points[0].size() <= 10;
}

//--------------------------------------
// function: acceptTrackedPoint
// brief: 决定哪些跟踪点被接受
// parameter:
// return:
//-------------------------------------
bool acceptTrackedPoint(int i)
{
	return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
}
VideoCapture capture("1.avi");:打开名为"1.avi"的视频文件。
while (true):无限循环,用于处理视频的每一帧。
cvtColor(frame, gray, COLOR_BGR2GRAY);:将彩色图像转换为灰度图像。
goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);:检测图像中的好的特征点。
calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);:使用Lucas-Kanade光流法计算特征点的新位置。
line(output, initial[i], points[1][i], Scalar(0, 0, 255)); 和 circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);:绘制特征点的轨迹和新位置。
swap(points[1], points[0]); 和 swap(gray_prev, gray);:交换points[1]和points[0]、gray_prev和gray的引用,为下一帧的计算做准备。

这段代码实现了基于Lucas-Kanade光流法的简单目标跟踪系统。在每一帧图像中,它通过检测特征点,并使用光流法计算特征点的运动轨迹,然后在图像上绘制特征点的运动路径,从而实现了目标的跟踪。

3.python版本

import cv2
import numpy as np

# 初始化全局变量
gray_prev = None  # 上一帧的灰度图像
points1 = None    # 上一帧的特征点
points2 = None    # 当前帧的特征点
st = None         # 特征点的状态

# 判断特征点是否应该被接受
def acceptTrackedPoint(a, b, c):
    return (c == 1) and ((abs(a[0][0] - b[0][0]) - abs(a[0][1] - b[0][1])) > 2)

# 交换两个变量的值
def swap(a, b):
    return b, a

# 跟踪函数
def tracking(frame):
    global gray_prev, points1, points2, st

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 将彩色图像转换为灰度图像
    output = frame.copy()

    # 添加特征点
    if gray_prev is None:
        gray_prev = gray.copy()
    else:
        # 计算光流
        points2, st, err = cv2.calcOpticalFlowPyrLK(gray_prev, gray, points1, None)

        # 去掉一些不好的特征点
        k = 0
        for i in range(points2.size):
            if i >= st.size:
                break
            if acceptTrackedPoint(points1[i], points2[i], st[i]):
                points1[k] = points1[i]
                points2[k] = points2[i]
                k += 1

        points1 = points1[:k]
        points2 = points2[:k]

        # 显示特征点和运动轨迹
        for (new, old) in zip(points2, points1):
            a, b = new.ravel()
            c, d = old.ravel()
            output = cv2.line(output, (int(a), int(b)), (int(c), int(d)), (0, 0, 255), 1)
            output = cv2.circle(output, (int(c), int(d)), 3, (0, 255, 0), -1)

        # 把当前跟踪结果作为下一次参考
        points1, points2 = swap(points1, points2)
        gray_prev, gray = swap(gray_prev, gray)

    return output

if __name__ == "__main__":
    # 打开视频文件
    video = cv2.VideoCapture('1.avi')
    fps = video.get(cv2.CAP_PROP_FPS)  # 获取视频帧率
    success = True

    while success:
        success, frame = video.read()  # 读取视频帧
        if not success:
            break
        result = tracking(frame)  # 进行目标跟踪
        cv2.imshow('result', result)  # 显示结果
        cv2.waitKey(int(1000 / int(fps)))  # 设置延迟时间,使播放速度与视频原始帧率一致

    video.release()  # 释放视频文件
    cv2.destroyAllWindows()  # 关闭所有窗口

这段代码通过光流法实现了视频中运动目标的跟踪。它使用Lucas-Kanade光流法来估计特征点的运动轨迹。首先,它将视频的每一帧转换为灰度图像。然后,它利用光流法计算相邻两帧之间的特征点的运动。接着,通过acceptTrackedPoint函数筛选出好的特征点,并将它们连接起来形成运动轨迹。最终,它在原始视频帧上绘制了特征点的运动轨迹,并通过窗口展示结果。整个过程实现了对视频中运动目标的简单跟踪。

import numpy as np
import cv2

# 打开默认摄像头(通常是编号为0的摄像头)
cap = cv2.VideoCapture(0)

# ShiTomasi角点检测的参数
feature_params = dict(maxCorners=100,  # 最多返回的角点数
                      qualityLevel=0.3,  # 角点的质量水平
                      minDistance=7,      # 角点之间的最小距离
                      blockSize=7)        # 计算角点检测时的窗口大小

# 光流法参数
lk_params = dict(winSize=(15, 15),       # 搜索窗口的大小
                 maxLevel=2,             # 金字塔的最大层数
                 criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))  # 迭代终止条件

# 随机生成100个颜色,用于绘制跟踪点的轨迹
color = np.random.randint(0, 255, (100, 3))

# 读取视频的第一帧
ret, old_frame = cap.read()
# 将第一帧转换为灰度图像
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# 使用ShiTomasi角点检测方法找到角点
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# 创建一个和视频帧大小相同的黑色掩码图片
mask = np.zeros_like(old_frame)

while True:
    # 读取视频帧
    ret, frame = cap.read()
    # 将当前帧转换为灰度图像
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # 计算光流以获取点的新位置
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
    # 选择good points(即成功跟踪的点)
    good_new = p1[st == 1]
    good_old = p0[st == 1]
    # 绘制跟踪框和跟踪点的轨迹
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a, b = new.ravel()  # 获取新点的坐标
        c, d = old.ravel()  # 获取旧点的坐标
        # 在掩码图片上绘制轨迹
        mask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), color[i].tolist(), 2)
        # 在当前帧上绘制跟踪点
        frame = cv2.circle(frame, (int(a), int(b)), 5, color[i].tolist(), -1)
    # 将轨迹绘制到当前帧上
    img = cv2.add(frame, mask)
    # 显示带有跟踪点轨迹的当前帧
    cv2.imshow('frame', img)
    # 按下ESC键退出循环
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
    # 更新旧帧和旧点
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)

# 关闭所有窗口,释放摄像头
cv2.destroyAllWindows()
cap.release()

上述代码实现了一个基于光流法的实时目标跟踪系统。该系统使用了OpenCV的光流法函数来追踪视频帧中的角点。下面是代码的主要步骤和功能总结:

摄像头初始化: 代码使用OpenCV的VideoCapture类初始化摄像头,获取视频帧。

角点检测: 使用ShiTomasi角点检测方法在视频的第一帧中找到特征点(角点),这些点将作为跟踪的起始点。

光流估计: 利用Lucas-Kanade光流法(cv2.calcOpticalFlowPyrLK函数)计算特征点在下一帧中的位置。

特征点筛选: 根据光流法的输出,筛选出成功跟踪的特征点。

绘制跟踪结果: 将跟踪点绘制在当前视频帧上,并用线连接跟踪点的轨迹,形成了目标的运动轨迹。

循环处理: 通过循环不断读取视频帧,进行光流法跟踪,并在每一帧上绘制跟踪点的轨迹。

用户退出: 当用户按下ESC键时,程序退出循环,关闭窗口,释放摄像头资源。

这段代码演示了光流法在实时视频中的应用,能够捕捉目标在连续帧之间的运动轨迹,具有实时性和动态性。在这个例子中,代码使用Lucas-Kanade光流法实现了简单的目标跟踪,可以通过调整检测参数、光流法参数以及绘制效果来适应不同的场景和需求。

总结

提示:这里对文章进行总结:

光流法(Optical Flow)是一种计算图像中像素运动的技术。它基于图像序列中相邻帧之间像素灰度值的变化,通过分析这些变化,推断出像素在图像中的运动情况。光流法常被用于运动目标跟踪、视频压缩、图像稠密匹配等计算机视觉领域的任务。以下是光流法的使用总结和原理介绍:
使用总结:

目标跟踪: 光流法可以用于实时目标跟踪,通过追踪图像中的特征点,了解目标在视频帧之间的运动轨迹。

动作分析: 在视频分析中,光流法可用于分析人体、车辆等物体的运动轨迹和动作,从而实现动作识别、行为分析等应用。

图像稠密匹配: 光流法可以用于计算两幅图像之间的稠密匹配,即找到两幅图像中每个像素的对应点,通常在立体视觉和结构运动恢复中应用广泛。

运动估计: 光流法用于估计图像序列中物体的运动速度和方向,这对于视频压缩和运动估计相关研究非常重要。

原理介绍:

光流法基于以下假设和原理:

空间一致性假设: 在图像的局部区域内,相邻像素的运动是一致的。这意味着,相邻像素的灰度值变化是由相同的运动引起的。

亮度恒定假设(Brightness Constancy Assumption): 在短时间内,运动物体的像素灰度值保持不变。这意味着,同一物体上的像素在不同帧之间的灰度值保持恒定,变化的灰度值是由于光照变化或阴影引起的。

基于上述假设,光流法通常使用以下步骤进行计算:

构建光流约束方程: 通过亮度恒定假设,可以得到一个描述相邻帧像素之间关系的方程。光流方程可以通过对图像中每个像素应用亮度恒定假设得到。

求解光流方程: 光流方程通常是一个局部的非线性方程组。常见的求解方法有Lucas-Kanade方法、Horn-Schunck方法等。这些方法通过最小化误差函数或优化约束条件来求解像素的运动速度。

稠密光流与稀疏光流: 光流法可以得到稠密光流和稀疏光流。稠密光流计算图像中所有像素的运动信息,而稀疏光流只计算选定像素点的运动信息。

总的来说,光流法是一种基于局部运动假设的计算图像运动的方法。然而,它对光照变化和遮挡等情况敏感,因此在实际应用中,通常需要结合其他方法来处理复杂场景。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1090725.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JDK21要来了,协程对Java带来什么

目录 前言 协程是什么 多线程有什么问题&#xff1f; 协程的线程模型 Reactor模型 使用协程后 RPC并发 IO阻塞 网络IO 磁盘IO epoll为什么不支持磁盘io&#xff1f; Kotlin与Go的协程 Go 使用 Go的协程调度(GPM模型) Kotlin 使用 Kotlin协程调度 阿里Wisp协程…

Linux程序调试工具使用整理

Linux程序调试工具使用整理 GDB调试入门 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许&#xff0c;各位比较喜欢那种图形界面方式的&#xff0c;像VC、BCB等IDE的调试&#xff0c;但如果你是在 UNIX平台下做软件&#xff0c;你会发现GDB这个调试工具有比VC、…

万界星空科技可视化数字大屏应用场景及作用

一、MES系统大屏显示&#xff1a;实时监控生产数据的关键 随着制造业的发展&#xff0c;现代企业越来越依赖于高效的生产管理系统来保证生产效率和质量。其中&#xff0c;MES系统数据大屏显示成为了监控生产数据的关键工具。通过实时监控和显示生产数据&#xff0c;企业能够及…

智能网关在校园能耗监测系统中的应用介绍

安科瑞 崔丽洁 摘要&#xff1a;国家提出了全社会节能减排的战略举措&#xff0c;节约型校园的建设是实现这一举措的重要内容。为了对校园能耗实行量化管理、实时监测&#xff0c;需要建立一个完善的监管体系校园节能监管体系。而节能监管体系的核心是能耗监测平台&#xff0c;…

解决react集成typescript报错:找不到名称“div“之类的错误

现象&#xff1a; 原因&#xff1a;Typescript 不希望在 Typescript 文件中看到 JSX元素。 解决此问题的最简单方法是将文件后缀从 .ts 重命名为 .tsx 。

【学习笔记】DTM分布式事务

分布式事务是什么 本文的分布式事务指的是DTM下的分布式事务。 分布式事务有两类&#xff0c;这里指的是跨数据库、跨服务的分布式事务。 分布式事务指事务的发起者、资源及资源管理器和事务协调者分别位于分布式系统的不同节点之上。 CAP理论 C&#xff08;一致性&#x…

【UVM 验证平台打印时间单位控制】

UVM 验证平台打印时间单位控制 UVM 具有丰富的打印功能&#xff0c;打印信息会包含时间/打印位置等信息&#xff0c;根据打印时间可以方便的在波形上找到错误点。默认打印时间单位时fs&#xff0c;由于单位太小会导致打印信息上的时间信息比较长&#xff0c;不方便查看与查找。…

实现Element Select选择器滚动加载

<template><el-selectpopper-class"more-tag-data"v-model"tagId"filterableplaceholder"请选择"focus"focusTag"><el-optionv-for"(item, index) in taskTagLists":key"index":label"item.n…

软件开发无人天车智能控制系统智能库存管理单元解决方案

天车&#xff08;行吊 起重机&#xff09;智控系统在自动控制的基础上&#xff0c;添加了基于智能控制、数据分析存储等尖端技术研发出的各类算法&#xff0c;赋予天车更“聪明”的任务执行及决策制定能力。智控系统能够根据获取的数据和预设的任务需求&#xff0c;通过智能决策…

ftp发布服务器

ftp工具 发布测试 第一步&#xff1a;下载FileZilla 第二部建立站点 连接成功之后可以看到文件了 项目打包后上传 远程站点里的文件删除 左边本地站点上传。over

淘天集团大模型应用十大挑战命题发布

以AI人工智能为代表的新技术正在成为全球商业发展的新动能。淘天集团从去年开始&#xff0c;就已经在AI重点领域&#xff0c;展开和高校的一系列深入合作。 近期&#xff0c;淘天集团集合基础模型和电商应用场景的具体问题&#xff0c;面向高校师生和全社会发布大模型应用十大挑…

【算法-贪心】分数背包问题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

Redis 图形化界面下载及使用超详细教程(带安装包)! redis windows下客户端下载

redis图形化界面的压缩包&#xff0c;直接解压缩即可&#xff0c;双击 rdm.exe 即可运行 打开后是这样子&#xff1a; 我已经连接过本地的redis数据库&#xff0c;所以左边有个localhost&#xff0c;你的可能是空白的&#xff0c;正常&#xff01; 1、连接本地Redis服务器 这…

uniapp-vue3-标签选择器wo-tag

采用uniapp-vue3实现, 是一款支持高度自定义的标签选择器组件&#xff0c;支持H5、微信小程序&#xff08;其他小程序未测试过&#xff0c;可自行尝试&#xff09; 可到插件市场下载尝试&#xff1a; https://ext.dcloud.net.cn/plugin?id14960 使用示例 <template>&…

设计模式03———包装器模式 c#

首先我们打开一个项目 在这个初始界面我们需要做一些准备工作 创建基础通用包 创建一个Plane 重置后 缩放100倍 加一个颜色 &#xff08;个人喜好&#xff09;调节渐变色 可更改同种颜色的色调 &#xff08;个人喜好&#xff09; 调节天空盒 准备工作做完后 接下我们做【…

晨控CK-GW06系列网关与汇川可编程控制器MOSBUSTCP通讯手册

晨控CK-GW06系列网关与汇川可编程控制器MOSBUSTCP通讯手册 晨控CK-GW06系列是支持标准工业通讯协议 MODBUSTCP 的网关控制器,方便用户集成到PLC等控制系统中。本控制器提供了网络 POE 供电和直流电源供电两种方式&#xff0c;确保用户在使用无 POE 供电功能的交换机时可采用外…

统信UOS1060设置自动关机02

原文链接&#xff1a;统信UOS1060设置自动关机02 hello&#xff0c;大家好啊&#xff0c;今天继续给大家介绍一篇如何在统信UOS 1060上实现自动关机的文章&#xff0c;本篇文章采用创建系统服务&#xff08;Systemd&#xff09;的方式。 你可以创建一个systemd服务来在特定时间…

Golang 接口(interface)最佳实践

引用类型&#xff1a;指针、slice切片、map、管道chan、interface等都是引用类型&#xff0c;在作为函数参数的时候进行修改会影响到原有的数据。 实现对Hero结构体切片的排序&#xff1a;sort.Sort&#xff08;data Interface&#xff09; Interface里面有三个方法可以实现&a…

sts搭建springboot

sts搭建springboot 需要的软件 Apache-maven-3.3.9.rar 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1xgj Spring-tool-suite-4-4.20.0.RELEASE-e4.29.0-win32.win32.x86_64.self-extracting.jar 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;p…

【数据结构】算法、时间复杂度和空间复杂度详解 ------ 算法篇

文章目录 &#x1f4cb;前言一. ⛳️算法的定义二. ⛳️算法的特性2.1 输入输出2.2 输入输出2.3 有穷性2.4 确定性2.5 可行性 三. ⛳️算法设计要求3.1 正确性3.2 可读性3.2 健壮性3.3 时间效率高和存储量低 四. ⛳️算法效率的度量方法4.1 事后统计方法4.2 事前分析估算方法 五…