项目实现了基于OpenCvSharp和其它组件实现了摄像头或相机的读取,并在列表中显示出来并可以截图保存,还可以在画面中心绘制十字准星、ROI区域,还可对画面进行左右和上下的翻转,并且十字准星、ROI区域、左右翻转和上下翻转等功能支持关闭保存功能,便于下次调用。
1.1引用using OpenCvSharp;using OpenCvSharp.Extensions;
1.2将Picturebox、Label、Button、checkbox等控件进行布局、改名、调整形状和字体,形成如下界面:
2.1初始化变量
private static VideoCapture my_VideoCapture;//摄像头设备
private static bool Vopen_flag; //视频打开关闭状态
Thread Video_thread; //视频播放线程
private int VideoCapture_id = 0;//摄像头设备号,默认0,可根据下拉框调整
private bool Collimator_flag ;//十字准星标识符
private bool ROI_flag ;//ROI区域标识符
private bool FlipX_flag;//左右翻转标识符
private bool FlipY_flag;//上下翻转标识符
2.2摄像头(相机)设备列表的读取
2.2.1摄像头(相机)设备列表扫描函数
private void Camera_devices_load()
{
// comboBox1.Items.Add(SerialPort_Name[i]);
comboBox1.Items.Clear();//清楚列表
foreach (var i in EnumDevices.Devices)
{
//打印设备名称
comboBox1.Items.Add(i);
}
if (comboBox1.Items.Count == 0)
{
MessageBox.Show("没有搜索到摄像头,请检查连线是否有问题" );
}
else
{
comboBox1.SelectedIndex = 0;//默认移动第一个
}
}
2.2.2 枚举视频设备类
public class EnumDevices
{
///
/// 枚举视频设备
///
public static IEnumerable<string> Devices
{
get
{
IMoniker[] monikers = new IMoniker[5];
var devEnum = Activator.CreateInstance(Type.GetTypeFromCLSID(SystemDeviceEnum)) as ICreateDevEnum;
IEnumMoniker moniker;
if (devEnum.CreateClassEnumerator(VideoInputDevice, out moniker, 0) == 0)
{
while (true)
{
int hr = moniker.Next(1, monikers, IntPtr.Zero);
if (hr != 0 || monikers[0] == null)
break;
yield return GetName(monikers[0]);
foreach (var i in monikers)
{
if (i != null)
Marshal.ReleaseComObject(i);
}
}
Marshal.ReleaseComObject(moniker);
}
Marshal.ReleaseComObject(devEnum);
}
}
///
/// 获取设备名称
///
///
///
static string GetName(IMoniker moniker)
{
IPropertyBag property;
object value;
object temp = null;
try
{
Guid guid = typeof(IPropertyBag).GUID;
moniker.BindToStorage(null, null, ref guid, out temp);
property = temp as IPropertyBag;
int hr = property.Read("FriendlyName", out value, null);
Marshal.ThrowExceptionForHR(hr);
return value as string;
}
catch (Exception)
{
return null;
}
finally
{
if (temp != null)
{
Marshal.ReleaseComObject(temp);
}
}
}
static readonly Guid SystemDeviceEnum = new Guid(0x62BE5D10, 0x60EB, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
static readonly Guid VideoInputDevice = new Guid(0x860BB310, 0x5D01, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
[Flags]
enum CDef
{
None = 0x0,
ClassDefault = 0x1,
BypassClassManager = 0x2,
ClassLegacy = 0x4,
MeritAboveDoNotUse = 0x8,
DevmonCMGRDevice = 0x10,
DevmonDMO = 0x20,
DevmonPNPDevice = 0x40,
DevmonFilter = 0x80,
DevmonSelectiveMask = 0xF0
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("3127CA40-446E-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IErrorLog
{
[PreserveSig]
int AddError([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In] System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo);
}
[ComImport]
[Localizable(false)]
[SuppressUnmanagedCodeSecurity]
[Guid("55272A00-42CB-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyBag
{
[PreserveSig]
int Read([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [MarshalAs(UnmanagedType.Struct)] out object pVar, [In] IErrorLog pErrorLog);
[PreserveSig]
int Write([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In][MarshalAs(UnmanagedType.Struct)] ref object pVar);
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("29840822-5B84-11D0-BD3B-00A0C911CE86")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICreateDevEnum
{
[PreserveSig]
int CreateClassEnumerator([In][MarshalAs(UnmanagedType.LPStruct)] Guid pType, out IEnumMoniker ppEnumMoniker, [In] CDef dwFlags);
}
}
private void button2_Click(object sender, EventArgs e)
{
Camera_devices_load();
}
if (!Vopen_flag)
{
try
{
my_VideoCapture = new VideoCapture(VideoCapture_id);
/* my_VideoCapture.Set(VideoCaptureProperties.FrameWidth, 1920);//宽度
my_VideoCapture.Set(VideoCaptureProperties.FrameHeight, 1080);//高度
my_VideoCapture.Set(VideoCaptureProperties.Fps,60);//高度 */
/* my_VideoCapture.Set(VideoCaptureProperties.FrameWidth, 640);//宽度
my_VideoCapture.Set(VideoCaptureProperties.FrameHeight, 360);//高度
my_VideoCapture.Set(VideoCaptureProperties.Fps,260);//高度 */
}
catch (Exception ex)
{
MessageBox.Show("OpenCV方式打开摄像头异常:" + ex.ToString());
return;
}
if (my_VideoCapture.IsOpened())
{
Vopen_flag = true;
Video_thread = new Thread(Play_Video);
Video_thread.Start();
pictureBox1.Image = null;
button1.Text = "关闭摄像头";
}
}
else
{
Vopen_flag = false;
Video_thread.Abort();
my_VideoCapture.Release();
button1.Text = "打开摄像头";
}
开启一个新线程
private void Play_Video()
{
while (Vopen_flag)
{
Mat v_mat = new Mat();
my_VideoCapture.Read(v_mat);
int sleepTime = (int)Math.Round(1000 / my_VideoCapture.Fps);
Cv2.WaitKey(sleepTime);
if (v_mat.Empty())
{
break;
}
if (FlipY_flag) Cv2.Flip(v_mat, v_mat, OpenCvSharp.FlipMode.X); //上下翻转
if (FlipX_flag) Cv2.Flip(v_mat, v_mat, OpenCvSharp.FlipMode.Y); //左右翻转
if (Collimator_flag) //画准星
{
Cv2.Line(v_mat, new OpenCvSharp.Point(v_mat.Cols / 2, v_mat.Rows / 2 + 35), new OpenCvSharp.Point(v_mat.Cols / 2, v_mat.Rows / 2 + 15), new Scalar(0, 0, 255), 2, LineTypes.Link8);
Cv2.Line(v_mat, new OpenCvSharp.Point(v_mat.Cols / 2, v_mat.Rows / 2 - 35), new OpenCvSharp.Point(v_mat.Cols / 2, v_mat.Rows / 2 - 15), new Scalar(0, 0, 255), 2, LineTypes.Link8);
Cv2.Line(v_mat, new OpenCvSharp.Point(v_mat.Cols / 2 + 35, v_mat.Rows / 2), new OpenCvSharp.Point(v_mat.Cols / 2 + 15, v_mat.Rows / 2), new Scalar(0, 0, 255), 2, LineTypes.Link8);
Cv2.Line(v_mat, new OpenCvSharp.Point(v_mat.Cols / 2 - 35, v_mat.Rows / 2), new OpenCvSharp.Point(v_mat.Cols / 2 - 15, v_mat.Rows / 2), new Scalar(0, 0, 255), 2, LineTypes.Link8);
}
if (ROI_flag) //画ROI
{
int V_width = v_mat.Width;
int V_height = v_mat.Height;
int start_x = v_mat.Width / 4;
int start_y = v_mat.Height / 4;
OpenCvSharp.Point strat_point = new OpenCvSharp.Point(v_mat.Width / 2, v_mat.Height / 2);
Rect ROI_rect = new Rect(start_x, start_y, V_width / 2, V_height / 2);
Mat srcImg = new Mat(v_mat, ROI_rect).Clone();
Cv2.Rectangle(v_mat, ROI_rect, new Scalar(255, 255, 0), 2);
}
this.pictureBox1.Invoke(new Action(() =>
{
pictureBox1.Image = BitmapConverter.ToBitmap(v_mat);//在 pictureBox1上显示
}));
v_mat.Release();//释放内存
}
}
private void button3_Click(object sender, EventArgs e)
{
SaveFileDialog saveImageDialog = new SaveFileDialog();
saveImageDialog.Title = "图片保存";
saveImageDialog.Filter = "jpg图片|*.JPG|gif图片|*.GIF|png图片|*.PNG|jpeg图片|*.JPEG|BMP图片|*.BMP";//文件类型过滤,只可选择图片的类型
saveImageDialog.FilterIndex = 1;//设置默认文件类型显示顺序
saveImageDialog.FileName = "图片保存"; //设置默认文件名,可为空
saveImageDialog.RestoreDirectory = true; //OpenFileDialog与SaveFileDialog都有RestoreDirectory属性,这个属性默认是false,打开一个文件后,那么系统默认目录就会指向刚才打开的文件。如果设为true就会使用系统默认目录
if (saveImageDialog.ShowDialog() == DialogResult.OK)
{
string fileName = saveImageDialog.FileName.ToString();
if (fileName != "" && fileName != null)
{
string fileExtName = fileName.Substring(fileName.LastIndexOf(".") + 1).ToString();
System.Drawing.Imaging.ImageFormat imgformat = null;
if (fileExtName != "")
{
switch (fileExtName)
{
case "jpg":
imgformat = System.Drawing.Imaging.ImageFormat.Jpeg;
break;
case "png":
imgformat = System.Drawing.Imaging.ImageFormat.Png;
break;
case "gif":
imgformat = System.Drawing.Imaging.ImageFormat.Gif;
break;
case "bmp":
imgformat = System.Drawing.Imaging.ImageFormat.Bmp;
break;
default:
imgformat = System.Drawing.Imaging.ImageFormat.Jpeg;
break;
}
try
{
MessageBox.Show("保存路径:" + fileName, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
pictureBox1.Image.Save(fileName, imgformat);
}
catch
{
MessageBox.Show("图片保存失败!");
}
}
}
}
}
2.5 其它功能
2.5.1 功能存储,在Settings.settings中建立以下变量。
并在Form1中添加Camer_flag_load()函数,进行初始化。
private void Camer_flag_load()
{
//初始化十字准星标识符
Collimator_flag = Properties.Settings.Default.Collimator_flag;
if (Collimator_flag) checkBox1.Checked = true;
else checkBox1.Checked = false;
//初始化ROI区域标识符
ROI_flag = Properties.Settings.Default.ROI_flag;
if (ROI_flag) checkBox2.Checked = true;
else checkBox2.Checked = false;
//初始化十字准星标识符
FlipX_flag = Properties.Settings.Default.FlipX_flag;
if (FlipX_flag) checkBox3.Checked = true;
else checkBox3.Checked = false;
//初始化ROI区域标识符
FlipY_flag = Properties.Settings.Default.FlipY_flag;
if (FlipY_flag) checkBox4.Checked = true;
else checkBox4.Checked = false;
}
2.5.2 具体功能实现
放置在Play_Video()函数中。
源代码:https://download.csdn.net/download/sunsoldeir1/87324867