opencv算法和界面配合,刚入职的时候尝试过,利用的MFC,调试起来很痛苦。
后来基本都没怎么用界面,DOS的黑窗口,opencv自带的显示界面及滑动条凑合着调试用。
最近有点时间,刚好双十一在一个视觉群里看到了一个讲C#调用opencv的dll的课程,鉴于群主也是那门课的讲师,在平时解答群员的问题的时候很细心,能力也很强,因此有了这篇文章。
根据相机不同动态调用相机默认的属性设置页
目前所做的工作是跑通老师的框架,能够把opencv的处理结果显示在C#界面中。整体自己学习调试了几天,老师的ini文件有些默认参数,托管dll和显示界面间的关联不是那么强,也就是一边调节滑动条,opencv算法改变参数,界面上又显示结果。目前dll算是写死参数,然后呈现结果,这个还有待自己进一步学习加强。
// 注意注释掉Form1.Designer.cs中的Dispose函数
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 System.Threading;
using System.Runtime.InteropServices; // Marshal
using System.Drawing.Imaging;// PixelFormat.Format24bppRgb
using System.IO;// MemoryStream
using System.Diagnostics; // Process.GetCurrentProcess().Kill();
using GOClrDll;
using DirectShowLib;
namespace Yake2_WFormsApp_opencamera
{
public partial class Form1 : Form
{
#region 成员变量
[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern int OleCreatePropertyFrame(
IntPtr hwndOwner,
int x,
int y,
[MarshalAs(UnmanagedType.LPWStr)] string lpszCaption,
int cObjects,
[MarshalAs(UnmanagedType.Interface, ArraySubType = UnmanagedType.IUnknown)]
ref object ppUnk,
int cPages,
IntPtr lpPageClsID,
int lcid,
int dwReserved,
IntPtr lpvReserved);
IBaseFilter theDevice = null;
Thread threadMain;
private Capture cam;
IntPtr m_ip = IntPtr.Zero;
GOClrClass client = new GOClrClass();
INIFileHelper inifilehelper = new INIFileHelper("./GOConfig");
bool b_take_picture;
#endregion
private void ThreadRun()
{
while (true)
{
if (m_ip != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(m_ip);
m_ip = IntPtr.Zero;
}
if (cam == null)
continue;//必须的异常处理
// capture image
try
{
m_ip = cam.Click();
}
catch
{
continue;//继续下图采集显示
}
Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
//// If the image is upsidedown
b.RotateFlip(RotateFlipType.RotateNoneFlipY);
MemoryStream ms = new MemoryStream();
b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] bytes = ms.GetBuffer();
// 这里才是真正调用GOClr托管代码里面的opencv处理函数
Bitmap bitmap = client.ImageProcess(bytes);
if (bitmap == null)
continue;
// 调用CLR的黑白处理
Bitmap bitmap2 = client.ImageProcess2(bytes);
Bitmap bitmap_canny = client.ImageProcess_Canny(bytes);
if (bitmap2 == null)
continue;
if (b_take_picture == true)
{
b_take_picture = false;//不重复取景
if (b == null)
{
System.Windows.Forms.MessageBox.Show("CLR图像获取错误!");
}
else
{
string strPath;
strPath = System.Windows.Forms.Application.StartupPath;
b.Save(strPath + "/" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
//bitmap.Save(strPath + "/" + DateTime.Now.ToString("yyyyMMdd_HHmm") + "1.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
//bitmap2.Save(strPath + "/" + DateTime.Now.ToString("yyyyMMdd_HHmm") + "2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
//显示结果
try
{
picPreview.Image = b;
pictureBox1.Image = bitmap2;
//pictureBox1.Image = bitmap;
picCanny.Image = bitmap_canny;
}
catch
{
continue;
}
//施放资源
b.Dispose();
//bitmap.Dispose();
}
}
public Form1()
{
InitializeComponent();
//开启线程
if (threadMain == null)
{
this.threadMain = new Thread(this.ThreadRun);
}
this.threadMain.IsBackground = true;//程序退出的时候,主动退出线程
this.threadMain.Start();
//构造摄像头数据
foreach (DsDevice ds in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))
{
comboBox1.Items.Add(ds.Name);
}
//初始化摄像头
InitVideoDevice();
//读取数据库
//string strtmp = inifilehelper.IniReadValue("视频采集", "摄像头序号");
//int itmp = Convert.ToInt32(strtmp);
//if (itmp > comboBox1.Items.Count)
//{
// itmp = 0;
//}
//if (comboBox1.Items.Count > 0)
//{
// comboBox1.SelectedIndex = itmp;
//}
// 选择摄像头
}
// 选择摄像头
public void InitVideoDevice()
{
if (cam != null)
cam.Dispose();
//读取参数
string strTmp = inifilehelper.IniReadValue("视频采集", "摄像头序号");
int VIDEODEVICE = Convert.ToInt32(strTmp); // zero based index of video capture device to use
const int VIDEOWIDTH = 640;// 是用默认(最大)分辨率
const int VIDEOHEIGHT = 480; // Depends on video device caps
//int VIDEOWIDTH = cam.Width;// 是用默认(最大)分辨率
//int VIDEOHEIGHT = cam.Height; // Depends on video device caps
const int VIDEOBITSPERPIXEL = 24; // BitsPerPixel values determined by device
try
{
cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, picPreview);
//this.ThreadRun();
}
catch
{
MessageBox.Show("摄像头打开错误,尝试以640*480分辨率进行打开");
//toolStripStatusLabel1.Text = "摄像头打开错误,尝试以640*480分辨率进行打开";
cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, picPreview);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
if (m_ip != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(m_ip);
m_ip = IntPtr.Zero;
}
this.threadMain.Abort();
}
#region helper函数
// 相机参数设置界面
private void DisplayPropertyPage(IBaseFilter dev)
{
//Get the ISpecifyPropertyPages for the filter
ISpecifyPropertyPages pProp = dev as ISpecifyPropertyPages;
int hr = 0;
if (pProp == null)
{
//If the filter doesn't implement ISpecifyPropertyPages, try displaying IAMVfwCompressDialogs instead!
IAMVfwCompressDialogs compressDialog = dev as IAMVfwCompressDialogs;
if (compressDialog != null)
{
hr = compressDialog.ShowDialog(VfwCompressDialogs.Config, IntPtr.Zero);
DsError.ThrowExceptionForHR(hr);
}
else
{
System.Windows.Forms.MessageBox.Show("Item has no property page", "No Property Page", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
return;
}
//Get the name of the filter from the FilterInfo struct
FilterInfo filterInfo;
hr = dev.QueryFilterInfo(out filterInfo);
DsError.ThrowExceptionForHR(hr);
// Get the propertypages from the property bag
DsCAUUID caGUID;
hr = pProp.GetPages(out caGUID);
DsError.ThrowExceptionForHR(hr);
//Create and display the OlePropertyFrame
object oDevice = (object)dev;
hr = OleCreatePropertyFrame(this.Handle, 0, 0, filterInfo.achName, 1, ref oDevice, caGUID.cElems, caGUID.pElems, 0, 0, IntPtr.Zero);
DsError.ThrowExceptionForHR(hr);
Marshal.ReleaseComObject(oDevice);
if (filterInfo.pGraph != null)
{
Marshal.ReleaseComObject(filterInfo.pGraph);
}
// Release COM objects
Marshal.FreeCoTaskMem(caGUID.pElems);
}
// 视频设备与名字显示
private IBaseFilter CreateFilter(Guid category, string friendlyname)
{
object source = null;
Guid iid = typeof(IBaseFilter).GUID;
foreach (DsDevice device in DsDevice.GetDevicesOfCat(category))
{
if (device.Name.CompareTo(friendlyname) == 0)
{
device.Mon.BindToObject(null, null, ref iid, out source);
break;
}
}
return (IBaseFilter)source;
}
#endregion
private void button1_Click(object sender, EventArgs e)
{
DisplayPropertyPage(theDevice);
}
private void btnEnd_Click(object sender, EventArgs e)
{
if (DialogResult.Yes == System.Windows.Forms.MessageBox.Show("确认退出?", "提示", MessageBoxButtons.YesNo))
{
this.threadMain.Abort();
Process.GetCurrentProcess().Kill();// 完全退出
//this.Close();
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
int itmp = comboBox1.SelectedIndex;
inifilehelper.IniWriteValue("视频采集", "摄像头序号", itmp.ToString());
//选择视频设备
InitVideoDevice();
//生成配套的视频控制界面
if (theDevice != null)
{
Marshal.ReleaseComObject(theDevice);
theDevice = null;
}
//Create the filter for the selected video input device
string devicepath = comboBox1.SelectedItem.ToString();
theDevice = CreateFilter(FilterCategory.VideoInputDevice, devicepath);
}
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
cam.Dispose();
if (m_ip != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(m_ip);
m_ip = IntPtr.Zero;
}
//主动退出线程
this.threadMain.Abort();
}
private void btnCapture_Click(object sender, EventArgs e)
{
if (b_take_picture == false)
b_take_picture = true;
}
private void Form1_Load(object sender, EventArgs e)
{
//构造摄像头数据
//foreach (DsDevice ds in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))
//{
// comboBox1.Items.Add(ds.Name);
//}
string strTmp = inifilehelper.IniReadValue("视频采集", "摄像头序号");
//comboBox1.Text = comboBox1.SelectedItem.ToString();
comboBox1.Text = strTmp;
//string devicepath = comboBox1.SelectedItem.ToString();
//theDevice = CreateFilter(FilterCategory.VideoInputDevice, devicepath);
}
}
}
致谢:
http://edu.51cto.com/course/15717.html
https://github.com/jsxyhelu/GOGPY