机器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();
///
/// 相机ID
///
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());
}
}
///
/// 实例化第一个找到的相机
///
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());
}
}
///
/// 根据相机UserID实例化相机
///
///
public bool BaslerCameraInit(string userID)
{
try
{
// 枚举相机列表
List 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();
}
}
///
/// 打开相机
///
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;
}
///
/// 关闭相机,释放相关资源
///
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;
}
///
/// 单张采集
///
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;
}
///
/// 开始连续采集
///
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;
}
}
///
/// 停止连续采集
///
public bool StopGrabbing()
{
try
{
if (camera.StreamGrabber.IsGrabbing)
{
camera.StreamGrabber.Stop();
}
}
catch (Exception ex)
{
//NotifyG.Error(DeviceName + ex.ToString());
}
return true;
}
///
/// 获取最小最大曝光时间
///
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)
{
}
}
///
/// 获取最小最大增益
///
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技术,可无限制访问最新型号的相机并使用相关功能。
Basler – 德国工业相机_工业镜头_工业光源_线材等视觉组件提供商
机器视觉软件及工业相机软件下载 - pylon, ToF 等 | Basler
MvCameraControl海康相机
海康机器人Hikrobot-官方网站
海康机器人Hikrobot-官方网站
机器视觉工业相机客户端MVS V3.1.0
软件版本:MVS3.1.0 build20181229
TIS映美精工业相机,映美精IC Imageing Control.net
Machine vision software and drivers for Microsoft Windows
https://www.theimagingsource.com/support/downloads-for-windows/software-development-kits-sdks/icimagingcontrol/
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是一种基于千兆以太网通信协议开发的相机接口标准。
Sapera LT | Teledyne DALSA
www.lustervision.com/dalsa-linea/
Sapera LT SDK - 软件 - 志强视觉科技
大恒相机
大恒图像-专业的机器视觉核心部件及解决方案供应商
Point Grey相机
FlyCapture SDK是加拿大Point Grey(灰点)公司开发的功能丰富,最稳定的软件套件。
FlyCapture SDK | Teledyne FLIR
Machine Vision – Area Scan Cameras | Teledyne FLIR