四.工件位置檢測演算法

我們希望得到模組右下角第一個插座中的最右側的插針位置P(m,n)及該插座相對於夾具的角度a。如圖31所示。

採用HALCON機器視覺軟體及C#語言檢測工件位置的方法 (之四)

圖31 插針座標與工件的夾角

因為插針有一定的長度,且鏡頭有變形,直接檢測插針前端面的位置偏差較大;且插針前端面的面積小、形狀一致性不好,不容易檢測。

經分析,插座底部塑膠基座的形狀特徵明顯,採用形狀匹配函式檢測插座底部影象,間接檢測插針位置檢測,試驗證明成功率高。

為提高檢測精度和可靠性,採用形狀匹配函式檢測三個特徵影象的位置,並用其中2個位置座標計算插針座標P和工件夾角a。這樣比僅檢測一個特徵影象的位置和轉角的方法可靠。

1。 偏移量(offset)的設定與計算

採用HALCON機器視覺軟體及C#語言檢測工件位置的方法 (之四)

圖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)

及:

採用HALCON機器視覺軟體及C#語言檢測工件位置的方法 (之四)

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);

disp_message(hv_ExpDefaultWinHandle, “Load a old template press LEFT key, Set a new template press middle key”, “window”, 12, 12, “black”, “true”);

//draw a rectangle to select region of testing。

HOperatorSet。DispRectangle1(hv_ExpDefaultWinHandle, 320, 250, 630, 750);

// 掃描滑鼠按鍵

{

// 不使用該方法,程式略。

}

}

// 滑鼠中鍵按下,設定新的形狀模板

if ((int)(new HTuple(hv_Button。TupleEqual(2))) != 0)

{

disp_message(hv_ExpDefaultWinHandle, “draw rectangle for shape model。 ”,

“window”, 12, 12, “black”, “true”);

HOperatorSet。DrawRectangle1(hv_ExpDefaultWinHandle, out hv_Row1, out

hv_Column1, out hv_Row2, out hv_Column2);

ho_Rectangle。Dispose();

HOperatorSet。GenRectangle1(out ho_Rectangle, hv_Row1, hv_Column1, hv_Row2,

hv_Column2);

ho_ImageReduced。Dispose();

HOperatorSet。ReduceDomain(ho_Image, ho_Rectangle, out ho_ImageReduced);

HOperatorSet。WriteImage(ho_ImageReduced, “png”, 0, “D:/Vision/MySample/MyShapeMatch/Image006。png”);

}

// 滑鼠左鍵按下,讀取硬碟中已有的形狀模板

if ((int)(new HTuple(hv_Button。TupleEqual(1))) != 0)

{

disp_message(hv_ExpDefaultWinHandle, “Load a old template ”,

“window”, 12, 12, “black”, “true”);

ho_ImageReduced。Dispose();

HOperatorSet。ReadImage(out ho_ImageReduced, “Image006。png”);

}

// 生成一個待檢測的小區域,被檢測區域的影象名為Mask

ho_Rectangle。Dispose();

HOperatorSet。GenRectangle1(out ho_Rectangle, 320, 250, 630, 750);

ho_Mask。Dispose();

HOperatorSet。ReduceDomain(ho_Image, ho_Rectangle, out ho_Mask);

// 生成形狀模板、形狀匹配

HOperatorSet。CreateShapeModel(ho_ImageReduced, “auto”, (new

HTuple(-45))。TupleRad() , (new HTuple(90))。TupleRad(), “auto”, “auto”, “use_polarity”, “auto”, “auto”, out hv_ModelID);

HOperatorSet。CountSeconds(out hv_S1);

HOperatorSet。FindShapeModel(ho_Mask, hv_ModelID, (new HTuple(-45))。TupleRad()

, (new HTuple(90))。TupleRad(), 0。5, 3, 0。0, “least_squares”, 0, 0。5, out hv_Row,

out hv_Column, out hv_Angle, out hv_Score);

HOperatorSet。CountSeconds(out hv_S2);

hv_Runtime = (hv_S2-hv_S1)*1000;

// 顯示匹配結果

HOperatorSet。DispRectangle1(hv_ExpDefaultWinHandle, 320, 250, 630, 750);

dev_display_shape_matching_results(hv_ModelID, “green”, hv_Row, hv_Column,

hv_Angle, 1, 1, 0);

ho_Cross。Dispose();

HOperatorSet。GenCrossContourXld(out ho_Cross, hv_Row, hv_Column, 26, (new HTuple(45))。TupleRad() );

HOperatorSet。SetColor(hv_ExpDefaultWinHandle, “red”);

HOperatorSet。DispObj(ho_Cross, hv_ExpDefaultWinHandle);

hv_y0 = hv_Row[0];

hv_y1 = hv_Row[1];

hv_x0 = hv_Column[0];

hv_x1 = hv_Column[1];

HOperatorSet。DispLine(hv_ExpDefaultWinHandle, hv_y0, hv_x0, hv_y1,

hv_x1);

disp_message(hv_ExpDefaultWinHandle, ((new HTuple(hv_Score。TupleLength())+“ shapes located in ”)+(hv_Runtime。TupleString( “。1f”)))+“ ms ”,

“window”, 12, 12, “black”, “true”);

HOperatorSet。ClearShapeModel(hv_ModelID);

HOperatorSet。CloseFramegrabber(hv_AcqHandle);

}

catch (HalconException

HDevExpDefaultException)

{

ho_Image。Dispose();

ho_Rectangle。Dispose();

ho_ImageReduced。Dispose();

ho_Mask。Dispose();

ho_Cross。Dispose();

throw HDevExpDefaultException;

}

ho_Image。Dispose();

ho_Rectangle。Dispose();

ho_ImageReduced。Dispose();

ho_Mask。Dispose();

ho_Cross。Dispose();

}

public void InitHalcon()

{

// Default settings used in HDevelop

HOperatorSet。SetSystem(“do_low_error”, “false”);

}

public void RunHalcon(HTuple Window)

{

hv_ExpDefaultWinHandle = Window;

action();

}

}

1)將匯出的C#程式碼整理編寫幾個功能獨立的方法

如本文第二節“HALCON與C#混合程式設計的方法”所述,在Program。cs程式中編寫類HDevelopExport;然後在其中根據匯出的C#程式碼編寫以下幾個方法:halcon初始化InitHalcon();攝像頭初始化InitCamera(HTuple Window);採集影象、顯示影象GrabAndDisplay();設定模板SetTemplate();從檔案中讀取模板ReadTemplate();模板匹配MatchTemplate();顯示偏移點位置DisplayOffset();顯示計算角度,劃線DisplayLine();關閉相機CloseCamera()。

形狀匹配函式的引數設定與本文三。5。節的相同。

Program。cs程式如下所示:

using System;

using System。Collections。Generic;

using System。Linq;

using System。Windows。Forms;

using HalconDotNet;

namespace MatchMyTemplate

{

public partial class HDevelopExport

{

// 定義變數

public HTuple hv_ExpDefaultWinHandle;

HObject ho_Image, ho_Rectangle, ho_ImageReduced;

HObject ho_ModelContours;

HObject ho_Mask;

HTuple hv_AcqHandle;

HTuple hv_S1, hv_S2;

HTuple hv_Width, hv_Height;

HTuple hv_ModelID, hv_Row, hv_Column;

HTuple hv_Row1, hv_Column1, hv_Row2, hv_Column2;

HTuple hv_Angle, hv_Score, hv_Runtime;

HTuple hv_R;

public double[] Px;

public double[] Py;

public int ResultN;

public double usedTime;

public double Cx,Cy;

public double Fx,Fy;

public double Cr = 9;

public void InitHalcon() // 初始化halcon

{

HOperatorSet。SetSystem(“do_low_error”, “false”);

}

public void InitCamera(HTuple Window) // 攝像頭初始化

{

hv_ExpDefaultWinHandle = Window;

HOperatorSet。GenEmptyObj(out ho_Image); // 生ho_Image資料區

// Grabbing images from a Daheng USB 2。0 camera

HOperatorSet。CloseAllFramegrabbers();

HOperatorSet。OpenFramegrabber(“DahengCAM”, 1, 1, 0, 0, 0, 0, “default”, -1, “default”,-1, “default”, “default”, “default”, -1, -1, out hv_AcqHandle);

//open camera with default settings

}

public void GrabAndDisplay() // 採集影象、顯示影象

{

ho_Image。Dispose(); // 清除ho_Image中的資料

HOperatorSet。GrabImage(out ho_Image, hv_AcqHandle); // 採集影象

HOperatorSet。GetImageSize(ho_Image, out hv_Width, out hv_Height); // 獲取圖片的尺寸

HOperatorSet。SetPart(hv_ExpDefaultWinHandle, 0, 0, hv_Height - 1, hv_Width - 1);

HOperatorSet。DispObj(ho_Image, hv_ExpDefaultWinHandle);

// 顯示ho_Image中的圖片

HOperatorSet。SetDraw(hv_ExpDefaultWinHandle,“margin”); // 填充模式為只畫框

HOperatorSet。SetColor(hv_ExpDefaultWinHandle,“red”); // 畫線顏色紅

HOperatorSet。DispRectangle1(hv_ExpDefaultWinHandle,320, 250, 630, 750);

}

public void SetTemplate() // 設定模板

{

MessageBox。Show(“在紅框中按下滑鼠左鍵畫方框選模板,按右鍵結束”);

HOperatorSet。DrawRectangle1(hv_ExpDefaultWinHandle,

out hv_Row1, out hv_Column1, out hv_Row2, out hv_Column2);

HOperatorSet。GenRectangle1(out ho_Rectangle, hv_Row1, hv_Column1, hv_Row2,

hv_Column2);

HOperatorSet。ReduceDomain(ho_Image, ho_Rectangle, out ho_ImageReduced);

HOperatorSet。WriteImage(ho_ImageReduced, “png”, 0, “D:/Vision/MySample/ShapeMatch/Image005。png”);

MessageBox。Show(“模板已儲存”);

}

public void CloseCamera() // 關閉相機

{

HOperatorSet。CloseFramegrabber(hv_AcqHandle);

}

public void ReadTemplate() // 從檔案中讀取模板

{

HOperatorSet。GenEmptyObj(out ho_ImageReduced);

ho_ImageReduced。Dispose();

HOperatorSet。ReadImage(out ho_ImageReduced, “D:/Vision/MySample/ShapeMatch/Image005。png”);

}

public void MatchTemplate() // 模板匹配

{

int i,j;

double temp;

HOperatorSet。GenRectangle1(out ho_Rectangle, 320, 250, 630, 750);

HOperatorSet。ReduceDomain(ho_Image, ho_Rectangle, out ho_Mask);

//Reduce image range

HOperatorSet。CreateShapeModel(ho_ImageReduced, “auto”, (new HTuple(-45))。TupleRad() ,(new HTuple(90))。TupleRad(),

“auto”, “auto”,“use_polarity”, “auto”, “auto”,out hv_ModelID);

HOperatorSet。CountSeconds(out hv_S1); // Match start

HOperatorSet。FindShapeModel(ho_Mask,hv_ModelID, (new HTuple(-45))。TupleRad()

,(new HTuple(90))。TupleRad(),0。5, 3, 0。0, “ least_squares ”, 0,0。5, out hv_Row,

out hv_Column, outhv_Angle, out hv_Score);

HOperatorSet。CountSeconds(out hv_S2); // Match stop

hv_Runtime = (hv_S2 - hv_S1) * 1000;

usedTime = hv_Runtime;

ResultN = new HTuple(hv_Row。TupleLength());

// 獲取匹配結果個數

if (ResultN >1)

{

Px = new double[ResultN];

Py = new double[ResultN];

hv_R = new HTuple(); //HTuple變數初始化

for (i = 0; i < ResultN; i++)

{

Py[i] = hv_Row[i]; // 將搜尋結果的中心座標讀出

Px[i] = hv_Column[i];

Aa[i] = hv_Angle[i];

hv_R[i] = 8; //設定圓半徑

}

for (i = 0; i < ResultN; i++) // 從大到小排序

{

for (j = i + 1; j < ResultN; j++)

{

if (Px[i] < Px[j])

{

temp = Px[i];

Px[i] = Px[j];

Px[j] = temp;

temp = Py[i];

Py[i] = Py[j];

Py[j] = temp;

temp = Aa[i];

Aa[i] = Aa[j];

Aa[j] = temp;

}

}

}

HOperatorSet。SetColor(hv_ExpDefaultWinHandle,“red”); // 顯示匹配結果位置

HOperatorSet。DispCircle(hv_ExpDefaultWinHandle,hv_Row, hv_Column, hv_R);

HOperatorSet。ClearShapeModel(hv_ModelID);

Cy = Py[0]+ 10; // offset的初始值

Cx = Px[0]+ 60;

}

else

{

MessageBox。Show(“匹配失敗!?”);

}

}

public void DisplayOffset() // 顯示偏移點位置

{

HOperatorSet。SetColor(hv_ExpDefaultWinHandle, “red”);

HOperatorSet。DispObj(ho_Image,hv_ExpDefaultWinHandle);

HOperatorSet。DispCircle(hv_ExpDefaultWinHandle,hv_Row, hv_Column, hv_R);

HOperatorSet。DispLine(hv_ExpDefaultWinHandle,hv_Row[0], hv_Column[0], hv_Row[1], hv_Column[1]);

HOperatorSet。SetColor(hv_ExpDefaultWinHandle,“yellow”);

HOperatorSet。DispCircle(hv_ExpDefaultWinHandle,Cy, Cx, Cr);

}

public void DisplayLine() //顯示計算角度,劃線

{

HOperatorSet。SetColor(hv_ExpDefaultWinHandle, “yellow”);

HOperatorSet。DispLine(hv_ExpDefaultWinHandle, Cy, Cx, Fy, Fx);

}

}

static class Program

{

static void Main()

{

Application。EnableVisualStyles();

Application。SetCompatibleTextRenderingDefault(false);

Application。Run(new Form1());

}

}

}

2)設計窗體及程式碼

設計窗體如圖33所示。Form1。cs程式程式碼如下:

using System;

using System。Collections。Generic;

using System。ComponentModel;

using System。Data;

using System。Drawing;

using System。Linq;

using System。Text;

using System。Windows。Forms;

namespace MatchMyTemplate

{

public partial class Form1 : Form

{

HDevelopExport hd = new HDevelopExport();

public double Lam,

theta;

public Form1()

{

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e) // 開啟相機

{

hd。InitCamera(hWindowControl1。HalconWindow); // 攝像頭初始化

timer1。Enabled = true; // 開始定時拍照顯示

textBox1。Text = “”;

textBox1。Refresh();

}

private void timer1_Tick(object sender, EventArgs e) // 定時拍照、顯示

{

hd。GrabAndDisplay();

}

private void button3_Click(object sender, EventArgs e) // 關閉相機

{

imer1。Enabled = false;

}

private void Form1_FormClosed(object sender, FormClosedEventArgs e) // 關閉窗體

{

timer1。Enabled = false; // 停止拍照

hd。CloseCamera();

}

private void button2_Click(object sender, EventArgs e) // 影象匹配、計算2點距離

{

int j, m;

double d;

double[] x;

double[] y;

timer1。Enabled = false; // 停止拍照

hd。MatchTemplate(); // 影象匹配

button2。Visible = false;

m = hd。ResultN;

x = new double[m];

y = new double[m];

for (j = 0; j < m; j++) // 獲取匹配座標

{

x[j] = hd。Px[j];

y[j] = hd。Py[j];

}

textBox1。Text = “匹配時間:” + hd。usedTime。ToString(“#####。##”)

+ “ ms” + “\r\n” + “\r\n”;

for (j = 0; j < m; j++)

{

if (j < m - 1) // 計算2點距離

{

d = (y[j + 1] - y[j]) *(y[j + 1] - y[j]) + (x[j + 1] - x[j]) * (x[j + 1] - x[j]);

d = Math。Sqrt(d);

d = 0。0485 * d;

textBox1。Text =textBox1。Text + “d(” + Convert。ToString(j + 1) + “)

= ” + d。ToString(“#####。##”)+ “mm” + “\r\n”;

}

textBox1。Text = textBox1。Text +“x(”+ Convert。ToString(j + 1) + “) = ” + Convert。ToString(x[j])+“ y(” + Convert。ToString(j+ 1) + “) = ” + Convert。ToString(y[j]) + “\r\n”+ “\r\n”;

}

}

private void button5_Click(object sender, EventArgs e) // 讀模板

{

hd。ReadTemplate();

button2。Visible = true;

}

private void button4_Click(object sender, EventArgs e) // 設定模板

{

timer1。Enabled = false; // 停止拍照

hd。SetTemplate();

}

private void Form1_Load(object sender, EventArgs e) // 載入窗體

{

button2。Visible = false;

}

private void button7_Click(object sender, EventArgs e) // 計算偏移點位置

{

double a, b, c, d, m, n, k1, k2;

a = hd。Px[0];

b = hd。Py[0];

c = hd。Px[1];

d = hd。Py[1];

m = hd。Cx;

n = hd。Cy;

k1 = (b - n) / (a - m);

k2 = (d - b) / (c - a);

Lam = Math。Sqrt((b - n) * (b - n) +(a - m) * (a - m));

theta = Math。Atan((k1 - k2) / (1 + k1* k2));

}

private void button8_Click(object sender, EventArgs e) // 偏移點上移

{

hd。Cy = hd。Cy - 1;

hd。DisplayOffset();

}

private void button9_Click(object sender, EventArgs e) // 偏移點下移

{

hd。Cy = hd。Cy + 1;

hd。DisplayOffset();

}

private void button10_Click(object sender, EventArgs e) // 偏移點左移

{

hd。Cx = hd。Cx - 1;

hd。DisplayOffset();

}

private void button11_Click(object sender, EventArgs e) // 偏移點右移

{

hd。Cx = hd。Cx + 1;

hd。DisplayOffset();

}

private void button6_Click(object sender, EventArgs e) // 計算、顯示插針位置和夾角

{

double a, b, c, d, m, n;

double alpha, beta;

a = hd。Px[0];

b = hd。Py[0];

c = hd。Px[1];

d = hd。Py[1];

alpha = Math。Atan((d - b) / (c - a));

beta = theta + alpha ;

m = a + Lam * Math。Cos(beta);

n = b + Lam * Math。Sin(beta);

textBox1。Text = textBox1。Text + “ m = ” + Convert。ToString(m) + “\r\n” + “

n = ” + Convert。ToString(n) + “\r\n” + “alpha = ” + Convert。ToString(alpha)

+ “\r\n” + “ theta = ” + Convert。ToString(theta)+ “\r\n” + “ beta = ” + Convert。ToString(beta);

hd。Cx = m;

hd。Cy = n;

hd。Fx = m-600*Math。Cos(alpha); // 計算夾角斜線的終點座標

hd。Fy = n-600*Math。Sin(alpha);

hd。DisplayOffset(); // 顯示插針位置

hd。DisplayLine(); // 顯示工件夾角

}

}

}

1。 實驗結果

如圖33所示,首先點選“Camera On”鍵,開啟相機,再點選“Set template”鍵,設定模板,模板影象如圖34所示。

採用HALCON機器視覺軟體及C#語言檢測工件位置的方法 (之四)

圖33 Form外觀及模板設定 圖34 模板影象

如果已經設定好模板,則點選“Load template”鍵,讀取模板影象。然後,點選“Match”鍵開始匹配。

點選“adjust offset”區域中的四個按鍵,可以調整偏移點,如圖35中的黃色圓點所示。將黃色圓點移動至最右邊的插針位置上。點選“Set offset”計算偏移點的引數q、L。參見公式(1)、(2)。

採用HALCON機器視覺軟體及C#語言檢測工件位置的方法 (之四)

圖35 插針位置檢測結果

之後,開始檢查插針位置及夾角。

關閉相機,然後再開啟相機。將模組任意擺放,但右下角最右側的4個插針必須在紅色框內,如圖33所示。

點選“Load template”鍵,再點選“Match”鍵,再點選“Display target”鍵,檢測結果顯示如圖35所示。

圖35中3個紅色點是3個匹配結果的中心點。匹配時間為13毫秒左右。

經標定,1個畫素為0。0485毫米。2個插針之間的公稱距離為5毫米。檢測資料表明:位置誤差小於1個畫素。最右側插針位置由黃點標註,其座標是由公式(4)計算而得。實驗表明檢測精度令人滿意。

由於顯示影象的窗體座標y軸方向朝下,匹配結果的轉角a方向定義與一般直角座標相反。所以轉角a為正時,計算得出的夾角alpha為負。夾角alpha是由公式(3)計算得出,和匹配函式給出的旋轉角a(1)~a(3)有一定的偏差。但圖35中的黃色線是根據alpha計算畫出,顯然,其精度更高。

五.小結

HALCON軟體功能十分強大,使用比較簡單;但沒有中文說明書,讀英語文件較費時間。由HALCON程式匯出的C#程式碼,不能直接使用,只能參考。希望本文能對想學習、使用機器視覺位置檢測的工程師有些幫助。

六.參考文獻

[1] MVTec Software GmbH, HALCON Solution Guide II-B。 München,Germany, 2010。

[2] 李衛平,左力。 運動控制系統原理與應用。 武漢:華中科技大學出版社,2013。

[3] 孫國棟,趙大興。機器視覺檢測理論與演算法。 北京:科學出版社,2015。

[4] 孫正。 數字影象處理與識別。 北京:機械工業出版社,2016。