勇哥说的这个话题的起因是追求极速的拍图速度。
机器ppm不达标的情况下,往往对视觉的处理速度有变态的要求,为了争取处理时间最短,几十毫秒也要争取。
halcon的接口是通用接口,其速度是比不上相机厂商自己相机配套的SDK的采图速度的。
下面程序运行后,500w的CCD拍图的时间(不算显示时间)达到惊人的32毫秒,如果用halcon接口,最快的我见过是180毫秒。
using Basler.Pylon; using HalconDotNet; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { private PixelDataConverter converter = new PixelDataConverter(); /// <summary> /// 相机ID /// </summary> public string UserID { get { return userID; } } private string userID = string.Empty; private Stopwatch sw = new Stopwatch(); private bool isOkGrab = false; private IntPtr latestFrameAddress = IntPtr.Zero; public HObject Image { get { return image; } } private HObject image = null; static Version Sfnc2_0_0 = new Version(2, 0, 0); private Camera camera = null; HTuple handle; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { var f1=BaslerCameraInit(); if(f1) { MessageBox.Show( Open().ToString()); } } /// <summary> /// 实例化第一个找到的相机 /// </summary> public bool BaslerCameraInit() { try { camera = new Camera(); camera.StreamGrabber.ImageGrabbed -= StreamGrabber_ImageGrabbed; camera.StreamGrabber.ImageGrabbed+=StreamGrabber_ImageGrabbed; return true; } catch (Exception ex) { return false; //NotifyG.Error(ex.ToString()); } } /// <summary> /// 根据相机UserID实例化相机 /// </summary> /// <param name="UserID"></param> public bool BaslerCameraInit(string userID) { try { // 枚举相机列表 List<ICameraInfo> allCameraInfos = CameraFinder.Enumerate(); foreach (ICameraInfo cameraInfo in allCameraInfos) { if (userID == cameraInfo[CameraInfoKey.UserDefinedName]) { this.userID = userID; camera = new Camera(cameraInfo); camera.StreamGrabber.ImageGrabbed -= StreamGrabber_ImageGrabbed; camera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; } } if (camera == null) { //NotifyG.Error("未识别到UserID为“" + UserID + "”的相机!"); return false; } return true; } catch (Exception ex) { return false; //NotifyG.Error(ex.ToString()); } } void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e) { try { // Acquire the image from the camera. Only show the latest image. The camera may acquire images faster than the images can be displayed. // Get the grab result. IGrabResult grabResult = e.GrabResult; // Check if the image can be displayed. if (grabResult.IsValid) { //grabTime = sw.ElapsedMilliseconds; //if (eventComputeGrabTime != null) eventComputeGrabTime(grabTime); //Reduce the number of displayed images to a reasonable amount if the camera is acquiring images very fast. // **** 降低显示帧率,减少CPU占用率 **** // //if (!stopWatch.IsRunning || stopWatch.ElapsedMilliseconds > 33) { //stopWatch.Restart(); // 判断是否是黑白图片格式 if (grabResult.PixelTypeValue == PixelType.Mono8) { //allocate the m_stream_size amount of bytes in non-managed environment if (latestFrameAddress == IntPtr.Zero) { latestFrameAddress = Marshal.AllocHGlobal((Int32)grabResult.PayloadSize); } converter.OutputPixelFormat = PixelType.Mono8; converter.Convert(latestFrameAddress, grabResult.PayloadSize, grabResult); HOperatorSet.GenEmptyObj(out image); image.Dispose(); // 转换为Halcon图像显示 HOperatorSet.GenImage1(out image, "byte", grabResult.Width, grabResult.Height, latestFrameAddress); HOperatorSet.SetPart(handle, 0, 0, grabResult.Height - 1, grabResult.Width - 1); } else if (grabResult.PixelTypeValue == PixelType.BayerBG8 || grabResult.PixelTypeValue == PixelType.BayerGB8 || grabResult.PixelTypeValue == PixelType.BayerRG8 || grabResult.PixelTypeValue == PixelType.YUV422packed) { int imageWidth = grabResult.Width - 1; int imageHeight = grabResult.Height - 1; HOperatorSet.SetPart(handle, 0, 0, imageHeight, imageWidth); int payloadSize = imageWidth * imageHeight; //allocate the m_stream_size amount of bytes in non-managed environment if (latestFrameAddress == IntPtr.Zero) { latestFrameAddress = Marshal.AllocHGlobal((Int32)(3 * payloadSize)); } converter.OutputPixelFormat = PixelType.RGB8packed; // 根据下面halcon转换的色彩格式bgr converter.Parameters[PLPixelDataConverter.InconvertibleEdgeHandling].SetValue("Clip"); converter.Convert(latestFrameAddress, 3 * payloadSize, grabResult); HOperatorSet.GenImageInterleaved(out image, latestFrameAddress, "bgr", (HTuple)imageWidth, (HTuple)imageHeight, -1, "byte", (HTuple)imageWidth, (HTuple)imageHeight, 0, 0, -1, 0); } else { //NotifyG.Error(DeviceName + "拍照失败,相机图像格式设置"); return; } isOkGrab = true; //MessageBox.Show(isOkGrab.ToString()); // 抛出图像处理事件 //if (EventGrab != null) EventGrab(this, new CameraGrabEventArgs(image)); } } } catch (Exception ex) { //MessageBox.Show(ex.ToString()); return; } finally { // Dispose the grab result if needed for returning it to the grab loop. e.DisposeGrabResultIfClone(); } } /// <summary> /// 打开相机 /// </summary> public bool Open() { try { if (camera.IsOpen) camera.Close(); Thread.Sleep(200); camera.Open(); var imageWidth = camera.Parameters[PLCamera.Width].GetValue(); // 获取图像宽 var imageHeight = camera.Parameters[PLCamera.Height].GetValue(); // 获取图像高 GetMinMaxExposureTime(); GetMinMaxGain(); camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.SingleFrame); //NotifyG.Debug(DeviceName + "打开相机成功:" + userID); } catch (Exception ex) { MessageBox.Show(ex.ToString()); return false; } return true; } /// <summary> /// 关闭相机,释放相关资源 /// </summary> public new bool Close() { try { camera.Close(); camera.Dispose(); if (Image != null) { Image.Dispose(); } if (latestFrameAddress != null) { Marshal.FreeHGlobal(latestFrameAddress); latestFrameAddress = IntPtr.Zero; } //NotifyG.Debug(DeviceName + "关闭相机成功:" + userID); } catch (Exception ex) { MessageBox.Show(ex.ToString()); return false; } return true; } /// <summary> /// 单张采集 /// </summary> public bool GrabImage() { try { isOkGrab = false; sw.Restart(); if (camera.StreamGrabber.IsGrabbing) { //NotifyG.Error("相机当前正处于采集状态!"); return false; } else { camera.StreamGrabber.Start(1, GrabStrategy.LatestImages, GrabLoop.ProvidedByStreamGrabber); //while (!isOkGrab) //{ // if (sw.ElapsedMilliseconds > 2000) { isOkGrab = false; return false; } // Thread.Sleep(1); //} //NotifyG.Debug(DeviceName + "拍照成功:" + sw.ElapsedMilliseconds); return true; } } catch (Exception ex) { MessageBox.Show(ex.ToString()); return false; } return true; } /// <summary> /// 开始连续采集 /// </summary> public bool StartGrabbing() { try { if (camera.StreamGrabber.IsGrabbing) { //NotifyG.Error("相机当前正处于采集状态!"); return false; } else { camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous); camera.StreamGrabber.Start(GrabStrategy.LatestImages, GrabLoop.ProvidedByStreamGrabber); return true; } } catch (Exception ex) { //NotifyG.Error(DeviceName + ex.ToString()); return false; } } /// <summary> /// 停止连续采集 /// </summary> public bool StopGrabbing() { try { if (camera.StreamGrabber.IsGrabbing) { camera.StreamGrabber.Stop(); } } catch (Exception ex) { //NotifyG.Error(DeviceName + ex.ToString()); } return true; } /// <summary> /// 获取最小最大曝光时间 /// </summary> public void GetMinMaxExposureTime() { try { if (camera.GetSfncVersion() < Sfnc2_0_0) { var minExposureTime = camera.Parameters[PLCamera.ExposureTimeRaw].GetMinimum(); var maxExposureTime = camera.Parameters[PLCamera.ExposureTimeRaw].GetMaximum(); } else { var minExposureTime = (long)camera.Parameters[PLUsbCamera.ExposureTime].GetMinimum(); var maxExposureTime = (long)camera.Parameters[PLUsbCamera.ExposureTime].GetMaximum(); } } catch (Exception ex) { } } /// <summary> /// 获取最小最大增益 /// </summary> public void GetMinMaxGain() { try { if (camera.GetSfncVersion() < Sfnc2_0_0) { var minGain = camera.Parameters[PLCamera.GainRaw].GetMinimum(); var maxGain = camera.Parameters[PLCamera.GainRaw].GetMaximum(); } else { var minGain = (long)camera.Parameters[PLUsbCamera.Gain].GetMinimum(); var maxGain = (long)camera.Parameters[PLUsbCamera.Gain].GetMaximum(); } } catch (Exception ex) { //NotifyG.Error(DeviceName + ex.ToString()); } } private void button2_Click(object sender, EventArgs e) { Stopwatch sw1 = new Stopwatch(); sw1.Start(); var f1 = GrabImage(); sw1.Stop(); MessageBox.Show(string.Format("grab time:{0}",sw1.ElapsedMilliseconds)); //if(f1) //{ // if (null != Image) // HOperatorSet.DispObj(Image, hWindowControl1.Handle); //} } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (null != camera && camera.IsOpen) Close(); } private void button6_Click(object sender, EventArgs e) { try { if (null != Image && Image.IsInitialized()) { //HOperatorSet.WriteImage(Image, "bmp", 0, "d:\\123.bmp"); HOperatorSet.DispObj(Image, handle); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void Form1_Load(object sender, EventArgs e) { handle = hWindowControl1.HalconWindow; } private void button3_Click(object sender, EventArgs e) { timer1.Start(); StartGrabbing(); } private void button4_Click(object sender, EventArgs e) { timer1.Stop(); StopGrabbing(); } private void timer1_Tick(object sender, EventArgs e) { button6_Click(null, null); } } }
另外勇哥说一个问题:
当这个程序被强行在进程中关闭后,你会发现再启动程序就初始化相机失败。
这是因为相机的句柄没有被关闭。上面的演示例程中,关闭句柄被放在了form窗口正常关闭的时候。
你重启电脑可以解决这个问题,或者你也可以等个几分钟,再启动程序也可以连上相机。
这是因为相机内部自己会超时复位,但是这个超时具体是几分钟勇哥也没统计过。
下面附上常见工业相机的SDK开发资料网址:
Basler相机
Basler pylon相机软件套装是一款包含易于使用的SDK、驱动程序和工具的软件套装,您可通过Windows、Linux PC或Mac来操作任何一款Basler相机。pylon采用最新GenICam技术,可无限制访问最新型号的相机并使用相关功能。
https://www.baslerweb.com/cn/sales-support/downloads/software-downloads/
MvCameraControl海康相机
https://www.hikrobotics.com/vision/visionlist.htm
https://www.hikrobotics.com/service/soft.htm
机器视觉工业相机客户端MVS V3.1.0
软件版本:MVS3.1.0 build20181229
TIS映美精工业相机,映美精IC Imageing Control.net
https://www.theimagingsource.com/support/downloads-for-windows/
Software Development Kits (SDKs)
IC Imaging Control .NET Component for C#, VB.NET, C++ Class Library for C++ projects
ic_setup_3.4.0.2744.exe
Teledyne DALSA
Sapera LT SDK是一款图像采集与控制软件的开发工具包(SDK),用于Teledyne DALSA相机与采集卡。Sapera LT支持从相机与采集卡中采集图像,依据的标准包括GigE Vision;CameraLink与CameraLink HS。GigE Vision是一种基于千兆以太网通信协议开发的相机接口标准。
https://www.teledynedalsa.com/en/products/imaging/vision-software/sapera-lt/
www.lustervision.com/dalsa-linea/
http://51camera.com.cn/show-34-10-1.html
大恒相机
http://www.daheng-imaging.com/
Point Grey相机
FlyCapture SDK是加拿大Point Grey(灰点)公司开发的功能丰富,最稳定的软件套件。
https://www.flir.com/products/flycapture-sdk
https://www.flir.com/iis/machine-vision/
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

