合并使用gpu::FarnebackOpticalFlow计算的水平光流flowx 和垂直光流flowy

一、问题来源

近期在学习GPU加速。无意间看到OpenCV库中有用GPU来计算光流的类gpu::FarnebackOpticalFlow,CPU上的光流函数是calcOpticalFlowFarneback。经过测试,用GPU上的光流函数计光流类gpu::FarnebackOpticalFlow计算的速度远远比CPU上的函数calcOpticalFlowFarneback快,但是,遇到了一个问题,gpu::FarnebackOpticalFlow输出的结果是两个GpuMat:flowx和flowy,calcOpticalFlowFarneback函数输出的结果是一个Mat类型的flow,包含水平和垂直方向上的光流。到这里,我就不知道该怎么合并flowx和flowy。

二、问题的解决

百度了很久,没有找到资料,国外也去看了,也没有找到。于是打算自己测试,首先测试了flow,flowx和flowy的维数,发现三个得到维数都相同,然后我又查看了这三者的通道数,发现flow的通道是2,flowx和flowy的通道数是1;然后我拿flow的通道1的数据和flowx比对、拿flow的通道二的数据和flowy比较,发现两组数据完全相同,也就是说,将flowx和flowy合并,就可以得到flow!
接下来直接上代码。

	//头文件
	#include <opencv2/gpu/gpu.hpp>
	using namespace cv;
	
	///用GPU来完成光流计算
	gpu::GpuMat preGrayGpu(preGray);    //当前帧的灰度Mat
	gpu::GpuMat nextGrayGpu(nextGray);  //下一帧的灰度Mat
	gpu::GpuMat opfGpuX;                //水平方向的光流Mat
	gpu::GpuMat opfGpuY;                //垂直方向的光流Mat
	gpu::FarnebackOpticalFlow mOpticalFlow; 
	mOpticalFlow.winSize = 15;          //mOpticalFlow的应该和calcOpticalFlowFarneback对应的参数相同
	mOpticalFlow.numLevels = 3;
	mOpticalFlow.numIters = 3;
	mOpticalFlow(preGrayGpu,nextGrayGpu,opfGpuX,opfGpuY); //计算光流
	Mat flowX,flowY;
	opfGpuX.download(flowX);
	opfGpuY.download(flowY);

	///合并x,y方向的光流
	Mat flow;             //存储合并后的光流
	vector<Mat> srcOpfMat;
	srcOpfMat.push_back(flowX);
	srcOpfMat.push_back(flowY);
	merge(srcOpfMat,flow); //flow就是合并后的光流
在C#窗体中实现视频的稠密光流法跟踪,可以使用OpenCV库提供的光流跟踪算法。具体步骤如下: 1. 安装OpenCV库,可以在NuGet管理器中搜索和安装OpenCVSharp4包。 2. 在窗体中添加一个PictureBox控件,用于显示视频帧。 3. 创建一个VideoCapture对象,用于打开视频文件或者连接摄像头。 ```csharp using OpenCvSharp; VideoCapture capture = new VideoCapture("video.mp4"); // 打开视频文件 // VideoCapture capture = new VideoCapture(0); // 连接摄像头 ``` 4. 循环读取视频帧,并对每一帧进行稠密光流法跟踪。可以使用calcOpticalFlowFarneback方法实现光流跟踪,该方法会返回两个光流图像,分别表示X和Y方向的位移。 ```csharp Mat previousFrame = new Mat(); Mat currentFrame = new Mat(); Mat previousGray = new Mat(); Mat currentGray = new Mat(); Mat flowX = new Mat(); Mat flowY = new Mat(); // 读取第一帧 capture.Read(previousFrame); Cv2.CvtColor(previousFrame, previousGray, ColorConversionCodes.BGR2GRAY); while (true) { // 读取下一帧 capture.Read(currentFrame); if (currentFrame.Empty()) { break; } Cv2.CvtColor(currentFrame, currentGray, ColorConversionCodes.BGR2GRAY); // 计算光流 Cv2.CalcOpticalFlowFarneback(previousGray, currentGray, flowX, flowY, null, 0.5, 3, 15, 3, 5, 1.2, 0); // 可以在这里对光流图像进行进一步的处理和显示 // 更新上一帧 previousGray = currentGray.Clone(); } capture.Release(); ``` 5. 在每个视频帧上显示光流跟踪结果。可以使用Cv2.ArrowedLine方法绘制箭头表示光流的方向和强度。 ```csharp // 绘制光流箭头 for (int y = 0; y < currentFrame.Height; y += 10) { for (int x = 0; x < currentFrame.Width; x += 10) { var dx = (int)flowX.At<float>(y, x); var dy = (int)flowY.At<float>(y, x); Cv2.ArrowedLine(currentFrame, new Point(x, y), new Point(x + dx, y + dy), Scalar.Green, 1); } } // 在PictureBox中显示当前帧 var bitmap = BitmapConverter.ToBitmap(currentFrame); pictureBox.Image = bitmap; ``` 完整代码如下: ```csharp using System; using System.Windows.Forms; using OpenCvSharp; namespace VideoFlowTrack { public partial class MainForm : Form { private VideoCapture capture; private Mat previousFrame = new Mat(); private Mat currentFrame = new Mat(); private Mat previousGray = new Mat(); private Mat currentGray = new Mat(); private Mat flowX = new Mat(); private Mat flowY = new Mat(); public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { capture = new VideoCapture("video.mp4"); // capture = new VideoCapture(0); } private void timer1_Tick(object sender, EventArgs e) { capture.Read(currentFrame); if (currentFrame.Empty()) { timer1.Stop(); return; } Cv2.CvtColor(currentFrame, currentGray, ColorConversionCodes.BGR2GRAY); Cv2.CalcOpticalFlowFarneback(previousGray, currentGray, flowX, flowY, null, 0.5, 3, 15, 3, 5, 1.2, 0); for (int y = 0; y < currentFrame.Height; y += 10) { for (int x = 0; x < currentFrame.Width; x += 10) { var dx = (int)flowX.At<float>(y, x); var dy = (int)flowY.At<float>(y, x); Cv2.ArrowedLine(currentFrame, new Point(x, y), new Point(x + dx, y + dy), Scalar.Green, 1); } } var bitmap = BitmapConverter.ToBitmap(currentFrame); pictureBox1.Image = bitmap; previousGray = currentGray.Clone(); } private void button1_Click(object sender, EventArgs e) { capture.Read(previousFrame); Cv2.CvtColor(previousFrame, previousGray, ColorConversionCodes.BGR2GRAY); timer1.Start(); } } } ``` 其中,timer1是一个Windows Forms Timer控件,用于定时读取视频帧并更新显示。button1是一个按钮控件,用于开始播放视频。pictureBox1是一个PictureBox控件,用于显示视频帧和光流跟踪结果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值