使用Visual Studio 2017和C#创建视频处理项目

在本文中,将探讨如何在Visual Studio2017中创建一个C#项目,该项目利用两个库来处理视频文件中的帧。将展示如何循环遍历这些帧,并进行一些基本的图像处理操作。请确保已经安装了Visual Studio 2017,并准备好了相应的库。

步骤1:从文件捕获视频

在进行任何处理之前,需要从视频文件中获取一帧。这可以通过使用VideoCapture类来轻松完成(许多教程提到了Capture类,但在最近的Emgu版本中已经不可用)。

请查看示例项目的Main方法:

private const string BackgroundFrameWindowName = "Background Frame"; private static Mat backgroundFrame = new Mat(); static void Main(string[] args) { string videoFile = @"PUT A PATH TO VIDEO FILE HERE!"; using (var capture = new VideoCapture(videoFile)) { if (capture.IsOpened) { backgroundFrame = capture.QueryFrame(); CvInvoke.Imshow(BackgroundFrameWindowName, backgroundFrame); VideoProcessingLoop(capture, backgroundFrame); } else { Console.WriteLine($"Unable to open {videoFile}"); } } }

VideoCapture类有四种构造函数版本。使用的重载版本接受一个string参数,即视频文件或视频流的路径。其他版本允许连接到摄像头。如果正确设计程序,从文件输入切换到网络摄像头可能就像改变new VideoCapture调用一样简单!

一旦创建了VideoCapture实例,可以通过访问IsOpened属性来确认是否成功打开(可能是路径错误或缺少编解码器)。

VideoCapture提供了几种获取帧的方法,但发现最方便的是调用QueryFrame方法。此方法返回Mat类实例(已经从第一部分知道了),并移动到下一帧。如果找不到下一帧,则返回null。可以利用这个事实轻松地遍历视频。

无人机检测项目基于找到背景帧和其他帧之间的差异。假设可以从视频中获取的第一帧作为背景,因此在创建VideoCapture对象后立即调用QueryFrame

backgroundFrame = capture.QueryFrame();

加载背景后,可以通过调用Imshow方法来检查它的外观(也知道它来自第一部分):

CvInvoke.Imshow(BackgroundFrameWindowName, backgroundFrame);

在视频中总是像减去帧一样容易找到(有意义的!)差异吗?不,不是的。首先,背景可能不是静态的(想象一下无人机在被风吹动的树前飞行,或者如果房间的光线发生了显著变化)。第二个挑战可能来自相机的移动。拥有固定的背景和相机位置使无人机检测任务对于初学者的OpenCV教程来说足够简单,而且并不完全不现实。视频检测/识别通常用于完全受控的环境,如工厂的一部分... OpenCV能够处理更复杂的场景 - 可以阅读有关背景减法技术和光流的更多信息...

知道可以使用QueryFrame获取单个帧图像(Mat实例)并移动到下一帧,知道QueryFrame如果无法继续则返回null。让利用这些知识构建一个遍历帧循环的方法:

private static void VideoProcessingLoop(VideoCapture capture, Mat backgroundFrame) { var stopwatch = new Stopwatch(); int frameNumber = 1; while (true) { Mat rawFrame = capture.QueryFrame(); if (rawFrame != null) { frameNumber++; stopwatch.Restart(); ProcessFrame(backgroundFrame, Threshold, ErodeIterations, DilateIterations); stopwatch.Stop(); WriteFrameInfo(stopwatch.ElapsedMilliseconds, frameNumber); ShowWindowsWithImageProcessingStages(); int key = CvInvoke.WaitKey(0); if (key == 27) Environment.Exit(0); } else { capture.SetCaptureProperty(CapProp.PosFrames, 0); frameNumber = 0; } } }

在每次循环迭代中,从视频文件中抓取一个帧。然后将其传递给ProcessFrame方法,该方法执行图像差异、噪声去除、轮廓检测和绘制(将在下一篇文章中详细讨论)...调用ProcessFrameSystem.Diagnostics.Stopwatch的使用所包围 - 这样,可以测量视频处理性能。笔记本电脑处理每个帧只需要大约1.5ms - 告诉过OpenCV很快!

如果QueryFrame返回null,则程序通过调用VideoCapture实例上的SetCaptureProperty方法返回到第一帧(视频将再次被处理)。

WriteFrameInfo在帧的左上角放置文本,包含有关其编号和处理时间的信息。ShowWindowsWithImageProcessingStages确保可以看到当前(原始)帧、背景帧、中间帧和最终帧在单独的窗口中...这两种方法将在下一篇文章中展示。

while循环将无限期地旋转,除非通过在显示帧的任何窗口中按下Escape键来停止程序执行(不是控制台窗口!)。如果将0作为WaitKey参数传递,则程序等待直到按下某个键。这让可以随时查看每个帧。如果向WaitKey传递其他数字,则程序将等待直到按下键或延迟到期。可能会使用它以指定的帧速率自动播放视频:

int fps = (int)capture.GetCaptureProperty(CapProp.Fps); int key = CvInvoke.WaitKey(1000 / fps);
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485