勇哥项目中有下面这个拍照函数GrabOneImage()。
在其它十几台设备上面运行没发现有什么问题,但是最近发现有一台设备上长时间运行不到半小时,程序就报告崩溃。错误原因是内存不足。
public bool GrabOneImage(bool isDebug) { try { //如果未初始化,先初始化相机 if (acqHandle == null) { HTuple handle = new HTuple(); //初始化相机有时会报错,多初始化几次就成功了,这样搞不太好,有待解决 int num = 0; Again: try { HOperatorSet.OpenFramegrabber(new HTuple("GigEVision2"), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple("progressive"), new HTuple(-1), new HTuple("default"), new HTuple(-1), new HTuple("false"), new HTuple("default"), Work.Instance.cameraStr, new HTuple(0), new HTuple(-1), out handle); Work.acqHandle = handle; } catch { num++; if (num < 5) goto Again; } if (acqHandle == null) return false; HTuple minExposure, maxExposure, temp, curExposure; //HOperatorSet.GetFramegrabberParam(Work.acqHandle, "ExposureTimeAbs", out temp); HOperatorSet.SetFramegrabberParam(Work.acqHandle, "ExposureTimeAbs", Work.Instance.exposure); HOperatorSet.GetFramegrabberParam(Work.acqHandle, "ExposureTimeAbs", out curExposure);//"exposure" minExposure = 1000;// temp[0]; maxExposure = 100000; Frm_ImageAcq.Instance.tck_exposure.Minimum = 1000; Frm_ImageAcq.Instance.tck_exposure.Maximum = 200000; Frm_ImageAcq.Instance.tck_exposure.Value = (int)curExposure.D; Frm_ImageAcq.Instance.lbl_exposure.Text = curExposure.ToString(); Work.Instance.exposure = (int)curExposure.D; HOperatorSet.SetFramegrabberParam(Work.acqHandle, "ExposureTimeAbs", Work.Instance.exposure); } if(null!=inputImage) { inputImage.Dispose(); } HOperatorSet.GrabImage(out inputImage, acqHandle); if (isDebug) Frm_Main.Instance.hwc_imageWindow.HobjectToHimage(inputImage); else { DisplayAndFitImage(inputImage, produceWindow.HalconWindow); } return true; } catch (Exception ex) { //MessageBox.Show(ex.ToString()); return false; } }
下图是在崩溃时的屏幕截图。
其中句柄数正常时应该为600多个,现在有近1900个了。
内存占用1.5个G。而这台IPC总共才4G内存。
崩溃时,拍照函数中的halcon算子开始抛出异常。
为了对比,勇哥用halcon导入一段拍照的代码,整理了一下,写成一个小程序。
运行了20个小时,发现内存没涨,句柄也没持续增加,一切正常没死掉。
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 HalconDotNet; namespace WindowsFormsApplication1 { public partial class xiangji : Form { public xiangji() { InitializeComponent(); } HTuple hv_AcqHandle = null, newHandle=null,hv_Width = new HTuple(); HTuple hv_Height = new HTuple(); HObject ho_Image = null; private void button1_Click(object sender, EventArgs e) { HOperatorSet.OpenFramegrabber("GigEVision2", 0, 0, 0, 0, 0, 0, "progressive", -1, "default", -1, "false", "default", "a0bd1d0f6037_MachineVisionSzAcx_MVA3A20MG8onSzAcx", 0, -1, out hv_AcqHandle); MessageBox.Show("OK"); } private void button4_Click(object sender, EventArgs e) { grab(); } private void button3_Click(object sender, EventArgs e) { timer1.Start(); } private void timer1_Tick(object sender, EventArgs e) { grab(); } private void grab() { if (null != ho_Image) ho_Image.Dispose(); HOperatorSet.GrabImage(out ho_Image, hv_AcqHandle); HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height); HOperatorSet.SetPart(hWindowControl1.HalconWindow, 0, 0, hv_Height-1, hv_Width-1); HOperatorSet.DispObj(ho_Image, hWindowControl1.HalconWindow); if (null != ho_Image) ho_Image.Dispose(); } private void xiangji_Load(object sender, EventArgs e) { } } }
对比下两段程序,其实,问题就在于划线这里。
在halcon里,HObject变量在用之前与使用完之后,都要释放(Dispose)。
因为inputImage是个全局变量,不能用完后立刻Dispose,因此,勇哥写了两个函数
Get_inputImage() 读取inputImage,而Set_inputImage()用于给inputImage赋值。
改完后的代码如下:
HObject Get_inputImage() { return inputImage; } void Set_inputImage(HObject obj) { if (inputImage != null) inputImage.Dispose(); inputImage = obj.CopyObj(1, -1); //如果直接liveImage=obj是不可以的,因为当Dispose后全局变量变量也会被注销。 } /// <summary> /// 采图 /// </summary> public bool GrabOneImage(bool isDebug) { try { //如果未初始化,先初始化相机 if (acqHandle == null) { HTuple handle = new HTuple(); //初始化相机有时会报错,多初始化几次就成功了,这样搞不太好,有待解决 int num = 0; Again: try { HOperatorSet.OpenFramegrabber(new HTuple("GigEVision2"), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple(0), new HTuple("progressive"), new HTuple(-1), new HTuple("default"), new HTuple(-1), new HTuple("false"), new HTuple("default"), Work.Instance.cameraStr, new HTuple(0), new HTuple(-1), out handle); Work.acqHandle = handle; } catch { num++; if (num < 5) goto Again; } HTuple minExposure, maxExposure, temp, curExposure; //HOperatorSet.GetFramegrabberParam(Work.acqHandle, "ExposureTimeAbs", out temp); HOperatorSet.GetFramegrabberParam(Work.acqHandle, "ExposureTimeAbs", out curExposure);//"exposure" minExposure = 1000;// temp[0]; maxExposure = 100000; Frm_ImageAcq.Instance.tck_exposure.Minimum = 1000; Frm_ImageAcq.Instance.tck_exposure.Maximum = 800000; Frm_ImageAcq.Instance.tck_exposure.Value = (int)curExposure.D; Frm_ImageAcq.Instance.lbl_exposure.Text = curExposure.ToString(); Work.Instance.exposure = (int)curExposure.D; } HObject img=null; HOperatorSet.GrabImage(out img, acqHandle); Set_inputImage(img); if (isDebug) Frm_Main.Instance.hwc_imageWindow.HobjectToHimage(img); else { DisplayAndFitImage(img, produceWindow.HalconWindow); } if (null != img) img.Dispose(); return true; } catch (Exception ex) { MessageBox.Show(ex.ToString()); return false; } }
问题解决了!!
注: 这个问题的怪异之处是,这个GrabOneImage()函数,虽然之前的写法不严谨。但是在十几台设备上都没什么问题,偏偏在这一台问题机上出现内存和句柄的问题。
而且这些机器从操作系统到CCD型号、halcon版本均是一模一样,甚至IPC的配置都是一样的。
之前只是见过有设备的程序换了速度更慢或者更快的IPC就表现异常,这因为那个设备的程序中有多个线程协作的逻辑,这时会跟CPU有直接关系。
而本例勇哥只能叹一声,怪哉!
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

