C# + halcon 联合编程示例
实现功能
1.加载图像
2.画直线,画圆,画矩形, 画椭圆 ROI,可以调整大小和位置
3.实现找边,找圆功能
效果
开发环境
Visual Studio 2022
.NET Framework 4.8
halcondotnet.dll
查看帮助文档
项目结构
DLL引用
要注意是 HALCON-17.12\dotnet35\halcondotnet.dll
界面控件
用System.Windows.Forms.Panel 控件来显示 图片
其他主要是按钮
代码
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.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
namespace CJH.Halcon.WinForms.App
{
public partial class Form1 : Form
{
private HSmartWindowControl hwControl;
private HWindow hw;
private HImage ho_Image;
private List<HDrawingObjectEx> drawObjs = new List<HDrawingObjectEx>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//创建Halcon控件对象,并添加到指定的容器中
hwControl = new HSmartWindowControl();
//var hwControlWpf = new HSmartWindowControlWPF();
hwControl.MouseWheel += HwControl_MouseWheel;
//通过Halcon控件获取对应Halcon窗口对象
hw = hwControl.HalconWindow;
//设置控件的填充方式
hwControl.Dock = DockStyle.Fill;
//把控件添加到显示区
hw_container.Controls.Add(hwControl);
}
/// <summary>
/// 鼠标滚轮移动时发生事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HwControl_MouseWheel(object sender, MouseEventArgs e)
{
hwControl.HSmartWindowControl_MouseWheel(sender, e);
}
/// <summary>
/// 加载图像
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnLoadImage_Click(object sender, EventArgs e)
{
var fileDialog = new OpenFileDialog();
fileDialog.Title = "打开图像资源";
fileDialog.Filter = "图像资源|*.png;*.jpg;*.bmp";
if (fileDialog.ShowDialog() == DialogResult.OK)
{
var filePath = fileDialog.FileName;
//创建halcon 图像对象
ho_Image = new HImage(filePath);
//把图像对象显示到Halcon窗口中
hw.DispObj(ho_Image);
//设置打开图像自动适应窗口的大小
hwControl.SetFullImagePart();
}
}
/// <summary>
/// 画直线
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnLine_Click(object sender, EventArgs e)
{
//drawObjs.Clear();
//定义绘制线的开始和结束坐标 起点XY- 终点XY
var lineTuple = new HTuple[] { 100, 300, 100, 100 };
//创建线的对象
var lineObj = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.LINE, lineTuple);
//注册线拖拽事件
lineObj.OnDrag(LineOnDragAction);
lineObj.OnResize(LineonResizeAction);
//保存线对象
drawObjs.Add(new HDrawingObjectEx()
{
HObj = lineObj,
HTuples = lineTuple
});
//把画出线放到Halcon窗口上面
hw.AttachDrawingObjectToWindow(lineObj);
}
/// <summary>
/// 拖拽(移动)
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void LineOnDragAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectData(drawid);
}
/// <summary>
/// 改变大小,长度
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void LineonResizeAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectData(drawid);
}
/// <summary>
/// 更新线拖拽或改变大小的方法
/// </summary>
/// <param name="drawid"></param>
/// <exception cref="NotImplementedException"></exception>
private void UpdateDrawingObjectData(HDrawingObject drawid)
{
//创建需要对象的属性元组
var attrTuple = new HTuple("row1", "column1", "row2", "column2");
//根据提供元组获取对应的属性值组元组
var valueTuple = drawid.GetDrawingObjectParams(attrTuple);
Debug.WriteLine($"row1:{valueTuple[0].D},column1:{valueTuple[1].D},row2:{valueTuple[2].D},column2:{valueTuple[3].D}");
//构建一个数组值组成的元组数组
var attrValues = new HTuple[] { valueTuple[0], valueTuple[1], valueTuple[2], valueTuple[3] };
//更新当前拖拽对像的属性数据
drawObjs[0].HTuples = attrValues;
}
/// <summary>
/// 直线抓边
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnLineBound_Click(object sender, EventArgs e)
{
//获取刚刚绘制直线对象的数据
var lineTuple = drawObjs[0].HTuples;
var hv_LineParam = new HTuple(lineTuple);
//清理绘制的直线对象
clearObject();
//创建计算测量句柄
HOperatorSet.CreateMetrologyModel(out HTuple hv_MetrologyHandle);
//句柄关联测试的图坐标位置
//设置测量对象图像的大小
//参数:
// MeasureHandle:输入测量模型的句柄;
// Width:输出图像宽;
// Height:输出图像高;
//HOperatorSet.SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);
//添加测量模型对象(此处是线)
//将测量对象添加到测量模型中
//算子参数:
// MeasureHandle:输入测量模型的句柄;
// Shape:输入要测量对象的类型;默认值:‘circle’,参考值:‘circle’圆,‘ellipse’椭圆,‘line’线,‘rectangle2’矩形,长方形;
// ShapeParam:要添加的测量对象的参数。
// MeasureLength1:输入垂直于边界的测量区域的一半长度(卡尺长度);默认值:20,参考值:10,20,30;最小增量:1.0;建议增量:10.0
// MeasureLength2:输入与边界相切的测量区域的一半长度(卡尺宽度);默认值:5,参考值:3,5,10;最小增量:1.0;建议增量:10.0
// MeasureSigma:输入用于平滑的高斯函数的sigma;默认值:1,参考值:0.4,0.6,0.8,1.0,1.5,2.0,3.0,4.0,5.0,7.0,10.0;最小增量:0.01;建议增量:0.1;限制:(0.4 <= MeasureSigma)&&(MeasureSigma <= 100)
// MeasureThreshold:输入测量阈值/最小边缘幅度;默认值:30,参考值:5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 90.0, 110.0;最小增量:0.5;建议增量:2;
// GenParamName:输入参数名称;参考: ‘distance_threshold’, ‘end_phi’, ‘instances_outside_measure_regions’, ‘max_num_iterations’, ‘measure_distance’, ‘measure_interpolation’, ‘measure_select’, ‘measure_transition’, ‘min_score’, ‘num_instances’, ‘num_measures’, ‘point_order’, ‘rand_seed’, ‘start_phi’;
// GenParamValue:输入参数值;参考:1, 2, 3, 4, 5, 10, 20, ‘all’, ‘true’, ‘false’, ‘first’, ‘last’, ‘positive’, ‘negative’, ‘uniform’, ‘nearest_neighbor’, ‘bilinear’, ‘bicubic’;
// Index:输出创建测量对象的索引值;
HOperatorSet.AddMetrologyObjectGeneric(hv_MetrologyHandle, "line", hv_LineParam,
50, 5, 1, 30, new HTuple(), new HTuple(), out HTuple hv_Index);
//为测量模型的测量对象设置参数 set_metrology_object_param
//根据需求设置测量的参数
//设置找线的方式(positive,negative,all)从黑到白,从白到黑
//算子参数:
// MeasureHandle:输入测量模型的句柄;
// Index:指定测量对象,为all时所有计量对象的参数都被设置(‘all’);
// GenParamName:输入参数名称;默认:‘num_instances’,参考:
// 'measure_length1':区域,垂直于边界的测量区域的一半长度
// 'measure_length2':区域,相切于边界的测量区域的一半长度
// 'measure_distance':区域,两个测量区域中心之间的距离
// 'num_measures':区域,测量区域数
// 'measure_sigma':测量,用于平滑的高斯函数的 Sigma
// 'measure_threshold':测量,最小边缘幅度阈值
// 'measure_select':测量,边缘端点的选择('last'、'first')
// 'measure_transition':测量,方向('all'、'negative'、 'positive')
// 'measure_interpolation':测量,插值类型
// 'min_score':拟合,最小分数
// 'num_instances':拟合,成功拟合实例的最大数量
// 'distance_threshold':拟合,距离阈值
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_transition",
"all");
//预期测量的区域个数
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "num_instances",
12);
//拟合数
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "num_instances",
6);
//高斯平滑系数,值越大,唯一的边缘越清晰
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_sigma",
5);
//区域,垂直与边界的测量区域的一半长度
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_length1",
80);
//区域,相切于边缘的测量区域的一半长度
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_length2",
10);
//最小边缘幅度越大,要求找到的边缘越锐利(灰度变换明显),反而不容易找到边缘
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_threshold",
20);
//测量双立方插入值,区别与bilinear双线性
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_interpolation",
"bicubic");
//取值 all,first,best,last
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_select",
"all");
//设置最小分数0.7
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "min_score",
0.7);
//开始找边缘
HOperatorSet.ApplyMetrologyModel(ho_Image, hv_MetrologyHandle);
//获取测量区域找到的边缘坐标集合
HOperatorSet.GetMetrologyObjectMeasures(out HObject ho_Contours, hv_MetrologyHandle,
"all", "all", out HTuple hv_Row, out HTuple hv_Column);
//设置卡尺颜色
HOperatorSet.SetColor(hw, "cyan");
//显示卡尺
HOperatorSet.DispObj(ho_Contours, hw);
//把找到的点通过十字叉来显示
//HOperatorSet.GenCrossContourXld(out HObject ho_Cross, hv_Row, hv_Column, 6, 0.785398);
//HOperatorSet.DispObj(ho_Cross, hw);
//得到线的起点坐标并显示出来
HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, 0, "all", "result_type",
"all_param", out HTuple hv_Parameter);
//获取计量模型的计量结果轮廓
HOperatorSet.GetMetrologyObjectResultContour(out HObject ho_Contour, hv_MetrologyHandle,
0, "all", 1.5);
//设置轮廓颜色
HOperatorSet.SetColor(hw, "green");
HOperatorSet.SetLineWidth(hw, 3);
//显示轮廓
HOperatorSet.DispObj(ho_Contour, hw);
//清除句柄
HOperatorSet.ClearMetrologyModel(hv_MetrologyHandle);
}
/// <summary>
/// 清理绘制的直线对象
/// </summary>
private void clearObject()
{
foreach (var item in drawObjs)
{
var hDrawingObject = item.HObj;
//把这个对象从Halcon窗口中移除
hw.DetachDrawingObjectFromWindow(hDrawingObject);
hDrawingObject.Dispose();
}
drawObjs.Clear();
}
/// <summary>
/// 找 圆
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnFindCircle_Click(object sender, EventArgs e)
{
//获取圆形对象的位置与半径
var circle = drawObjs[0].HTuples;
//创建测量模型
HOperatorSet.CreateMetrologyModel(out HTuple hv_MetrologyHandle);
//添加找圆工具,给定参数,显示过程卡尺
//50 卡尺长度
//5 卡尺宽度
HOperatorSet.AddMetrologyObjectCircleMeasure(hv_MetrologyHandle, circle[0].D, circle[1].D,
circle[2].D, 50, 5, 1, 30, new HTuple(), new HTuple(), out HTuple hv_Index);
HOperatorSet.GetMetrologyObjectModelContour(out HObject ho_Contour, hv_MetrologyHandle,
0, 1.5);
HOperatorSet.GetMetrologyObjectMeasures(out HObject ho_Contours, hv_MetrologyHandle,
"all", "all", out HTuple hv_Row1, out HTuple hv_Column1);
HOperatorSet.SetColor(hw, "cyan");
HOperatorSet.DispObj(ho_Contour, hw);
HOperatorSet.DispObj(ho_Contours, hw);
//执行找圆并显示结果
HOperatorSet.ApplyMetrologyModel(ho_Image, hv_MetrologyHandle);
HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, 0, "all", "result_type",
"all_param", out HTuple hv_Parameter);
HOperatorSet.GetMetrologyObjectResultContour(out HObject ho_Contour1, hv_MetrologyHandle,
0, "all", 1.5);
HOperatorSet.SetLineWidth(hw, 2);
HOperatorSet.SetColor(hw, "green");
HOperatorSet.DispObj(ho_Contour1, hw);
HOperatorSet.ClearMetrologyModel(hv_MetrologyHandle);
}
/// <summary>
/// 拖拽(移动)
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void circOnDragAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectDataCirc(drawid);
}
/// <summary>
/// 改变大小,长度
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void circResizeAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectDataCirc(drawid);
}
/// <summary>
/// (圆)更新线拖拽或改变大小的方法
/// </summary>
/// <param name="drawid"></param>
/// <exception cref="NotImplementedException"></exception>
private void UpdateDrawingObjectDataCirc(HDrawingObject drawid)
{
//创建需要对象的属性元组
var attrTuple = new HTuple("row", "column", "radius");
//根据提供元组获取对应的属性值组元组
var valueTuple = drawid.GetDrawingObjectParams(attrTuple);
Debug.WriteLine($"row:{valueTuple[0].D},column:{valueTuple[1].D},radius:{valueTuple[2].D}");
//构建一个数组值组成的元组数组
var attrValues = new HTuple[] { valueTuple[0], valueTuple[1], valueTuple[2] };
//更新当前拖拽对像的属性数据
drawObjs[0].HTuples = attrValues;
}
/// <summary>
/// 画圆
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCircle_Click(object sender, EventArgs e)
{
var circleHtuple = new HTuple[] { 100, 100, 100 };
var circleObj = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.CIRCLE, circleHtuple);
//注册线拖拽事件
circleObj.OnDrag(circOnDragAction);
circleObj.OnResize(circResizeAction);
//保存线对象
drawObjs.Add(new HDrawingObjectEx()
{
HObj = circleObj,
HTuples = circleHtuple
});
//把画出圆放到Halcon窗口上面
hw.AttachDrawingObjectToWindow(circleObj);
}
/// <summary>
/// 画矩形
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRectangle1_Click(object sender, EventArgs e)
{
var rectangle1Htuple = new HTuple[] { 100, 100, 200, 200 };
//矩形
var rectangle1Obj = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.RECTANGLE1, rectangle1Htuple);
//注册线拖拽事件
rectangle1Obj.OnDrag(rectangle1OnDragAction);
rectangle1Obj.OnResize(rectangle1ResizeAction);
//保存线对象
drawObjs.Add(new HDrawingObjectEx()
{
HObj = rectangle1Obj,
HTuples = rectangle1Htuple
});
//把画出圆放到Halcon窗口上面
hw.AttachDrawingObjectToWindow(rectangle1Obj);
}
/// <summary>
/// (矩形)拖拽(移动)
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void rectangle1OnDragAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectDataRectangle1(drawid);
}
/// <summary>
/// (矩形)改变大小,长度
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void rectangle1ResizeAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectDataRectangle1(drawid);
}
/// <summary>
/// (矩形)更新线拖拽或改变大小的方法
/// </summary>
/// <param name="drawid"></param>
/// <exception cref="NotImplementedException"></exception>
private void UpdateDrawingObjectDataRectangle1(HDrawingObject drawid)
{
//创建需要对象的属性元组
var attrTuple = new HTuple("row1", "column1", "row2", "column2");
//根据提供元组获取对应的属性值组元组
var valueTuple = drawid.GetDrawingObjectParams(attrTuple);
Debug.WriteLine($"row1:{valueTuple[0].D},column1:{valueTuple[1].D},row2:{valueTuple[2].D},column2:{valueTuple[3].D}");
//构建一个数组值组成的元组数组
var attrValues = new HTuple[] { valueTuple[0], valueTuple[1], valueTuple[2], valueTuple[3] };
//更新当前拖拽对像的属性数据
drawObjs[0].HTuples = attrValues;
}
/// <summary>
/// 画椭圆
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnEllipse_Click(object sender, EventArgs e)
{
var ellipseHtuple = new HTuple[] { 100, 100, 50, 50, 50 };
//椭圆
var ellipseObj = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.ELLIPSE, ellipseHtuple);
//注册线拖拽事件
ellipseObj.OnDrag(ellipseOnDragAction);
ellipseObj.OnResize(ellipseResizeAction);
//保存线对象
drawObjs.Add(new HDrawingObjectEx()
{
HObj = ellipseObj,
HTuples = ellipseHtuple
});
//把画出圆放到Halcon窗口上面
hw.AttachDrawingObjectToWindow(ellipseObj);
}
/// <summary>
/// (椭圆)拖拽(移动)
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void ellipseOnDragAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectDataEllipse(drawid);
}
/// <summary>
/// (椭圆)改变大小,长度
/// </summary>
/// <param name="drawid"></param>
/// <param name="window"></param>
/// <param name="type"></param>
private void ellipseResizeAction(HDrawingObject drawid, HWindow window, string type)
{
UpdateDrawingObjectDataEllipse(drawid);
}
/// <summary>
/// (椭圆)更新线拖拽或改变大小的方法
/// </summary>
/// <param name="drawid"></param>
/// <exception cref="NotImplementedException"></exception>
private void UpdateDrawingObjectDataEllipse(HDrawingObject drawid)
{
//创建需要对象的属性元组
//phi 以弧度表示的前半轴的方向
//radius1 前半轴
//radius2 后半轴
var attrTuple = new HTuple("row", "column", "phi", "radius1", "radius2");
//根据提供元组获取对应的属性值组元组
var valueTuple = drawid.GetDrawingObjectParams(attrTuple);
Debug.WriteLine($"row:{valueTuple[0].D},column:{valueTuple[1].D},phi:{valueTuple[2].D},radius1:{valueTuple[3].D},radius2:{valueTuple[4].D}");
//构建一个数组值组成的元组数组
var attrValues = new HTuple[] { valueTuple[0], valueTuple[1], valueTuple[2], valueTuple[3], valueTuple[4] };
//更新当前拖拽对像的属性数据
drawObjs[0].HTuples = attrValues;
}
}
/// <summary>
/// HDrawingObject 扩展类 ,主要包含拖拽对象和对象属性数据
/// </summary>
public class HDrawingObjectEx
{
public HDrawingObject HObj { get; set; }
public HTuple[] HTuples { get; set; }
}
}
项目源码下载地址
https://download.csdn.net/download/cjh16606260986/89497706
END