前言:
最近项目需求,在C#平台上调用外接USB摄像头,做一系列操作,其中包括视频录制,保存视频。
看起来简单的一个操作,但感觉还是有点复杂的,经过查询资料最终完成,所以有必要做个记录。
1、首先需要添加两个动态链接库引用:DShowNET.dll 和 ICameraDII.dll
2、直接上代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using System.Threading;
using OpenCvSharp.Flann;
using System.IO;
using ICameraDll.DirectX.Capture;
namespace UGV
{
public partial class Image_processing : Form
{
private Thread Image_processThread;
static string fileName = "D:\\sorfware\\C#project\\UGV2020-11-12\\UGV\\p";
Capture capture; //摄像头操作
Filters filters = new Filters(); //Filter集合
public Image_processing()
{
InitializeComponent();
}
private int GetffshowIndex()
{
FilterCollection videoCompressors = this.filters.VideoCompressors;
for (var i = 0; i < videoCompressors.Count; i++)
{
if ((videoCompressors[i] != null) && videoCompressors[i].Name.Equals("ffdshow video encoder"))
{
return i;
}
}
return -1;
}
private void CreateFilepath(string FilePath)
{
var dir = FilePath.Remove(FilePath.LastIndexOf("\\"));
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
}
//录制视频
private void Record_Video(object sender, EventArgs e)
{
//设置承载控件
Control videoControl = pictureBox1;
//设置文件路径
string filePath = "D:\\sorfware\\C#project\\UGV2020-11-12\\UGV\\";
string fileName = "test.mp4";
//检测摄像头是否被占用
if (capture != null)
{
capture.Stop();
capture.DisposeCapture();
}
//获取ffshow视频解码器索引
var ffshowIndex = GetffshowIndex();
if (ffshowIndex > 0)
{
var File = filePath + fileName;
CreateFilepath(File);
//这里0为电脑本机摄像头,后面按序为外接摄像头
capture = new Capture(new Filters().VideoInputDevices[1], null);
//设置承载控件
capture.PreviewWindow = videoControl;
//设置视频解码器
capture.VideoCompressor = filters.VideoCompressors[ffshowIndex];
//设置保存的文件路径和文件名
capture.Filename = File;
//设置帧
capture.FrameRate = 60;
//设置分辨率
capture.FrameSize = new System.Drawing.Size(1920, 1080);
//开始录制
capture.Start();
}
}
private void Run_cap()
{
var capture = new VideoCapture(0);
int sleepTime = (int)Math.Round(1000 / capture.Fps);
Mat image = new Mat();
Mat image1 = new Mat();
while (true)
{
capture.Read(image);
if (image.Empty())
break;
pictureBox1.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image);
Cv2.MedianBlur(image, image1, 5);
Cv2.Flip(image1, image1, FlipMode.XY); //翻转图片
image1 = image.CvtColor(ColorConversionCodes.BGR2GRAY);//灰度图片
//pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image1);
Cv2.Threshold(image1, image1, 155, 255, ThresholdTypes.BinaryInv);//二值化图片
//pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image1);
Cv2.Blur(image1, image1, new OpenCvSharp.Size(3, 3));//滤波
//pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image1);
//Cv2.Canny(image1, image1, 100, 200);//边缘检测
//pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image1);
OpenCvSharp.Point[][] contours;//获得轮廓
HierarchyIndex[] hierarchly;
Cv2.FindContours(image1, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));
//将结果画出并返回结果
Mat image2 = Mat.Zeros(image.Size(), image.Type());
double[] center = new double[2];
for (int i = 0; i < contours.Length; i++)
{
if (Cv2.ContourArea(contours[i]) > 1000) //去掉小轮廓
{
int num = 0;
Scalar color = new Scalar(0, 0, 255);
Cv2.DrawContours(image2, contours, i, color, 2, LineTypes.Link8, hierarchly);
for (int j = 0; j < contours[i].Length; j++)
{
num = j + 1;
int xx = contours[i][j].X;
int yy = contours[i][j].Y;
center[0] += xx;
center[1] += yy;
}
center[0] = center[0] / num;
center[1] = center[1] / num;
Console.WriteLine("X:" + center[0].ToString() + " Y:" + center[1].ToString());
Cv2.Circle(image2, (int)(center[0]), (int)(center[1]), 4, new Scalar(255, 0, 0), -1, LineTypes.Link8, 0);
}
}
pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image2);
Cv2.Threshold(image1, image1, 155, 255, ThresholdTypes.BinaryInv);//二值化图片
pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image1);
Cv2.WaitKey(sleepTime);
}
}
private void Stop_Record_Video(object sender, EventArgs e)
{
if (capture != null)
{
//停止录制
capture.Stop();
capture.DisposeCapture();
capture = null;
}
}
private void Image_Process(object sender, EventArgs e)
{
Image_processThread = new Thread(Run_cap);
if ((Image_processThread.ThreadState & ThreadState.AbortRequested) == 0)
{
Image_processThread.Start();
//button1.Text = "关闭摄像头";
}
else
{
Image_processThread.Abort();
//button1.Text = "打开摄像头";
}
}
}
}
3、界面以及效果图
- 目前简单的界面设计(还未完善)
- 录制视频界面
- 简单图像处理界面(后续很多功能未完成,需要继续添加完善)
- 可以看到录制视频成功了,且能够播放
总结:
虽然是个没多大技术含量的东西,但工程项目就是考一点点积累学习才能进步。
当然想要更深一层的进步,还需要深挖底层原理,这将是我后续学习目标。
评论已关闭