四.工件位置检测算法
我们希望得到模块右下角第一个插座中的最右侧的插针位置P(m,n)及该插座相对于夹具的角度a。如图31所示。图31 插针坐标与工件的夹角
因为插针有一定的长度,且镜头有变形,直接检测插针前端面的位置偏差较大;且插针前端面的面积小、形状一致性不好,不容易检测。
经分析,插座底部塑料基座的形状特征明显,采用形状匹配函数检测插座底部图像,间接检测插针位置检测,试验证明成功率高。
为提高检测精度和可靠性,采用形状匹配函数检测三个特征图像的位置,并用其中2个位置坐标计算插针坐标P和工件夹角a。这样比仅检测一个特征图像的位置和转角的方法可靠。
1. 偏移量(offset)的设置与计算图32 插针位置的偏移量
如图32所示,点A、C为最右边的2个检测结果的中心坐标。P点是最右侧的插针位置。
1)设置偏移量
已知:a, b, c, d, m, n
求:q, L
由:k1 = (n - b) / (m - a)
k2 = (b - d) / (a - c)
得:q = arctan( (k1 – k2) / (1 + k1 X k2) ) (1)
及:
q、L是相对于插座的尺寸,与工件夹角a无关。
因此,选取好模板、进行一次匹配后,只需手动设置一次插针位置P(m,n);之后,进行插针位置检测时,用A点、C点的坐标及q、L,即可求出P和a。
2)计算偏移量
已知:a, b, c, d, q, L
求:a, m, n
a = arctan((b - d) / (a - c)) (3)
b = q + a
m = a + L X cos(b) (4)
n = b + L X sin(b)
1. C#程序设计
1)将HDevelop的程序My_shape_match导出C#代码如下:
//
// File generated by HDevelop for HALCON/DOTNET (C#) Version 10.0
//
// This file is intended to be used with the HDevelopTemplate or
// HDevelopTemplateWPF projects located under %HALCONEXAMPLES%\c#
using System;
using HalconDotNet;
public partial class HDevelopExport
{
public HTuple hv_ExpDefaultWinHandle;
// Procedures
// External procedures
// Chapter: Matching / Shape-Based
// Short Description: Display the results of Shape-Based Matching.
public void dev_display_shape_matching_results (HTuple hv_ModelID, HTuple hv_Color, HTuple hv_Row, HTuple hv_Column, HTuple hv_Angle, HTuple hv_ScaleR, HTuple hv_ScaleC, HTuple hv_Model)
{
// 该方法的功能是:显示形状匹配的结果。
// 对应于HDevelop中的函数dev_display_shape_matching_results()
// 不使用该方法,程序略。
}
// Chapter: Graphics / Text
// Short Description: This procedure writes a
text message.
public void disp_message (HTuple hv_WindowHandle, HTuple hv_String, HTuple hv_CoordSystem, HTuple hv_Row, HTuple hv_Column, HTuple
hv_Color, HTuple hv_Box)
{
// 该方法的功能是:在窗体中显示文本信息。
// 对应于HDevelop中的函数disp_message()
// 不使用该方法,程序略。
}
// Main procedure
private void action()
{
HSystem sys = new HSystem();
// Local iconic variables
HObject ho_Image=null, ho_Rectangle=null,
ho_ImageReduced=null;
HObject ho_Mask, ho_Cross;
// Local control variables
HTuple hv_Error = null;
HTuple hv_AcqHandle, hv_WindowID=new HTuple();
HTuple hv_Button, hv_R=new HTuple(), hv_C=new HTuple();
HTuple hv_Row1=new HTuple(), hv_Column1=new HTuple(), hv_Row2=new HTuple();
HTuple hv_Column2=new HTuple(), hv_ModelID,
hv_S1, hv_Row;
HTuple hv_Column, hv_Angle, hv_Score, hv_S2, hv_Runtime;
HTuple hv_y0, hv_y1, hv_x0, hv_x1;
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_Rectangle);
HOperatorSet.GenEmptyObj(out ho_ImageReduced);
HOperatorSet.GenEmptyObj(out ho_Mask);
HOperatorSet.GenEmptyObj(out ho_Cross);
try
{
HOperatorSet.CloseAllFramegrabbers();
//open camera with default settings:
HOperatorSet.OpenFramegrabber("DahengCAM", 1, 1, 0, 0, 0, 0,
"default", -1, "default", -1, "default", "default", "default", -1, -1, out
hv_AcqHandle);
//open a window
//dev_close_window(...);
//dev_open_window(...);
//Define the region fill mode as margin
HOperatorSet.SetDraw(hv_ExpDefaultWinHandle, "margin");
hv_Button = 0;
while ((int)(new HTuple(hv_Button.TupleEqual(0))) != 0)
{
// Grabbing images from a Daheng USB 2.0 camera
ho_Image.Dispose();
HOperatorSet.GrabImage(out ho_Image, hv_AcqHandle);
HOperatorSet.DispObj(ho_Image, hv_ExpDefaultWinHandle);