接到新任务,用来监控3D打印机的摄像头,需要对其进行控制。之前我没有做过任何这方面的工作,很是挠头。不过有脚本和开源两个强大的工具,我也不是很害怕。
首先有人指明需要用到的库是OpenCV。CV是指Computer vision, 从名字就能判断这是专注于视频处理的库。很快我就找到了python的调用demo.并且成功的带动了手边的摄像头。http://opencv.org/安装后,就能在sources/samples/python/demo文件夹下面找到完整的demo程序。
不过这不能解决项目问题。我们的项目要求在.net环境下开发。所以很快,我就找到了成熟的.net平台下OpenCV解决方案,名叫EMGU;
同样的,EMGU也完整的demo例程。在EMGU3.1版本的安装路径下面\Solution\VS2013-2015文件夹中,就有摄像头的驱动例子:实现摄像头实时采样,只需要几行代码:
...
private static Capture _cameraCapture;
...
void run(){
try
{
_cameraCapture = new Capture();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return;
}
Application.Idle += ProcessFrame;
...
void ProcessFrame(object sender, EventArgs e)
{
Mat frame = _cameraCapture.QueryFrame();
}
通过Applicaiton.Idle+= ProcessFrame
的加载事件,非常优雅的实现了摄像头的驱动。
进一步,EMGU中有Websevice的例子。但是例子中传输的是一串字符串,采用的是net.tcp协议。我尝试传输p_w_picpath,结果在旁边电脑成功访问了我的摄像头,但是卡顿非常严重。(暂时分析不出来卡顿的原因)
host端代码:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using Emgu.CV;
namespace Webservice_Host
{
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("net.tcp://localhost:8082/ImageService");
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
//WSHttpBinding binding = new WSHttpBinding();
binding.MaxReceivedMessageSize = 2147483647;
ServiceHost host = new ServiceHost(typeof(ImageService));
ServiceBehaviorAttribute serviceBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
serviceBehavior.IncludeExceptionDetailInFaults = true;
// Create endpoint
host.AddServiceEndpoint(typeof(IImageService), binding, uri);
host.Open();
Console.WriteLine("Service is ready, press any key to terminate.");
Console.ReadKey();
host.Close();
}
}
}
ImageService.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
namespace Webservice_Host
{
public class ImageService : IImageService
{
public Image<Bgr, Byte> GrabFrame()
{
Capture _capture = new Capture();
Mat frame=new Mat();
//_capture.Retrieve(frame,0);
//Image<Bgr, Byte> img = frame.ToImage<Bgr, Byte>();
Image<Bgr, Byte> img = _capture.QueryFrame().ToImage<Bgr, Byte>();
if (_capture != null)
_capture.Dispose();
return img;
}
}
}
IImageService.cs
using System;
using System.Collections.Generic;
using System.Text;
using Emgu.CV;
using Emgu.CV.Structure;
using System.ServiceModel;
namespace Webservice_Host
{
[ServiceContract]
[XmlSerializerFormat]
public interface IImageService
{
[OperationContract(IsOneWay = false)]
Image<Bgr, Byte> GrabFrame();
}
}
client端代码:
//----------------------------------------------------------------------------
// Copyright (C) 2004-2016 by EMGU Corporation. All rights reserved.
//----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.Threading;
using Emgu.CV;
namespace Webservice_Client
{
public partial class Form1 : Form
{
private bool _started;
private Webservice_Host.IImageService _p_w_picpathGrabber;
private NetTcpBinding _binding;
private static Queue<IImage> p_w_picpathQ;
public Form1()
{
InitializeComponent();
_binding = new NetTcpBinding();
_binding.Security.Mode = SecurityMode.None;
_binding.MaxReceivedMessageSize = 2147483647;
Queue<IImage> p_w_picpathQ = new Queue<IImage>();
//System.Collections.Queue p_w_picpathQ= new System.Collections.Queue();
_started = false;
}
public bool Started
{
get { return _started; }
set
{
_started = value;
serviceUrlBox.Enabled = !_started;
if (!_started)
{
//stop grabing frames
//Application.Idle -= ProcessImage;
// System.Timers.Timer t =new System.Timers.Timer(1);
// t.Start();
// t.Elapsed+= ProcessImage;
}
else
{
//start to grab frames
_p_w_picpathGrabber = new ChannelFactory<Webservice_Host.IImageService>(
_binding,
new EndpointAddress(serviceUrlBox.Text)
).CreateChannel();
//System.Timers.Timer t =new System.Timers.Timer(50);
//t.Start();
////button2.Click += ProcessImage;
//t.Elapsed+= ProcessImage;
//// Application.Idle
Thread rx_p_w_picpath_thread = new Thread(new ThreadStart(get_p_w_picpath));
Thread show_p_w_picpath_thread = new Thread(new ThreadStart(show_p_w_picpath));
rx_p_w_picpath_thread.Start();
show_p_w_picpath_thread.Start();
}
}
}
private void get_p_w_picpath()
{
Queue<IImage> p_w_picpathQ = new Queue<IImage>();
while (true)
{
p_w_picpathQ.Enqueue(_p_w_picpathGrabber.GrabFrame());
}
}
private void show_p_w_picpath()
{
while (true) {
// if (p_w_picpathQ.Count>0&&p_w_picpathQ!=null)
// p_w_picpathBox1.Image=p_w_picpathQ.Dequeue();
}
}
private void ProcessImage(object sender, EventArgs e)
{
p_w_picpathBox1.Image = _p_w_picpathGrabber.GrabFrame();
}
private void button1_Click(object sender, EventArgs e)
{
Started = !Started;
if (Started == true)
button1.Text = "Stop";
else
button1.Text = "Start";
}
private void ReleaseResource()
{
Started = false;
}
private void button2_Click(object sender, EventArgs e)
{
}
}
}
IImageService
using System;
using System.Collections.Generic;
using System.Text;
using Emgu.CV;
using Emgu.CV.Structure;
using System.ServiceModel;
namespace Webservice_Host
{
[ServiceContract]
[XmlSerializerFormat]
public interface IImageService
{
[OperationContract(IsOneWay = false)]
Image<Bgr, Byte> GrabFrame();
}
}
到此为止,我对EMGU带摄像头的尝试就结束了。后面我采用EMGU做了两件事情,都是和网络摄像头有关:一是用ASP.NET用网页控制远程web摄像头拍照并传过来实时图像。二是将EMGU截图封装成为dll的方法,交给其他工程师使用。
总体而言,也可能是受制于我的编程功力,无法用EMGU来实现更复杂的摄像头访问应用。但是EMGU作为OpenCV在.net平台的封装,其项目重心用在了图像识别算法的封装而不是多媒体应用上:我们可以看到大量的例程进行图像识别等算法,调用起来非常方便。
而对于将摄像头转成流媒体源的工作,我找到了更加有效的框架,即微软自带的Media Foudation框架。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。