勇哥项目中有下面这个拍照函数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
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路



















