簡(jiǎn)介
本文的初衷是希望幫助那些有其它平臺(tái)視覺(jué)算法開(kāi)發(fā)經(jīng)驗(yàn)的人能快速轉(zhuǎn)入Halcon平臺(tái)下,通過(guò)文中的示例開(kāi)發(fā)者能快速了解一個(gè)Halcon項(xiàng)目開(kāi)發(fā)的基本步驟,讓開(kāi)發(fā)者能把精力完全集中到算法的開(kāi)發(fā)上面。
首先,你需要安裝Halcon,HALCON 18.11.0.1的安裝包會(huì)放在文章末尾。安裝包分開(kāi)發(fā)和運(yùn)行時(shí)兩個(gè)版本,運(yùn)行時(shí)版本一般用于生產(chǎn)環(huán)境。
注:開(kāi)發(fā)版本自帶運(yùn)行時(shí)可替代運(yùn)行時(shí)版本,但安裝的東西會(huì)比較多。
然后,你需要學(xué)會(huì)查看Halcon的幫助手冊(cè),這是很重要的一件事。
本文涉及到幫助文檔的主要章節(jié)如下:
原文 HALCON 18.11.0.1 / Programmer's Guide / Programming With HALCON/.NET 翻譯 HALCON 18.11.0.1/程序員指南/使用 HALCON/.NET 編程 原文 HALCON 18.11.0.1 / HALCON Operator Reference 翻譯 HALCON 18.11.0.1/ HALCON 運(yùn)算符參考
文中的示例是我第一次接觸Halcon時(shí)的學(xué)習(xí)測(cè)試用例,在電腦里面躺了一年,最近才有時(shí)間整理一下發(fā)出來(lái),希望能對(duì)你有所幫助。
注:運(yùn)行本文示例程序前至少安裝Halcon的運(yùn)行時(shí),否則Halcon的dll無(wú)法正常使用。
將 HALCON/.NET 添加到應(yīng)用程序
添加控件
右鍵單擊工具箱,然后選擇“選擇項(xiàng)”,彈出的對(duì)話框選擇“**.NET Framework組件”,單擊下面的“瀏覽”,導(dǎo)航到HALCON安裝目錄下的indotnet35(VS2008以下版本的選擇dotnet20) ,然后選擇halcondotnet.dll**。
完成上述操作后,HSmartWindowControl和HWindowControl控件就會(huì)出現(xiàn)在工具箱中,其中HWindowControl控件已經(jīng)過(guò)時(shí)官方不再推薦使用。
與HWindowControl相比,HSmartWindowControl控件具有以下幾個(gè)優(yōu)點(diǎn):
可以像任何其他控件一樣使用
提供預(yù)定義的鼠標(biāo)交互(移動(dòng)窗口內(nèi)容并使用鼠標(biāo)滾輪進(jìn)行縮放), 可以通過(guò)雙擊窗口來(lái)重置視圖
控件會(huì)自動(dòng)重新縮放,而不會(huì)閃爍
注:與HSmartWindowControlWPF 相反,HSmartWindowControl需要一個(gè)回調(diào)才能使用鼠標(biāo)滾輪進(jìn)行縮放。
引用dll
在HALCON安裝目錄下的**indotnet35**中,引用以下dll:
hdevenginedotnet.dll
halcondotnet.dll
注:使用HALCON XL開(kāi)發(fā)應(yīng)用程序時(shí),必須選擇以xl結(jié)尾的dll,hhdevelop xl適用于大分辨率的圖像(大于 32k x 32k )。
引用以下命名空間:
HalconDotNet:控件所在的命名空間
HalconType:Line、Rectangle2等數(shù)據(jù)類型所在的命名空間
調(diào)用Halcon算子
以ReadImage操作為例,函數(shù)原型如下:
staticvoidHOperatorSet.ReadImage(outHObjectimage,HTuplefileName) publicHImage(HTuplefileName) publicHImage(stringfileName) voidHImage.ReadImage(HTuplefileName) voidHImage.ReadImage(stringfileName)
注:這些內(nèi)容幫助手冊(cè)上都有,在文章開(kāi)頭列出來(lái)的章節(jié)。
在C#調(diào)用HALCON 算子有兩種選擇:函數(shù)式、對(duì)象式,前值通過(guò)HOperatorSet調(diào)用算子并通過(guò)out關(guān)鍵字傳入關(guān)鍵對(duì)象,后者直接在關(guān)鍵對(duì)象上調(diào)用對(duì)應(yīng)的方法。兩種方法完全等價(jià),C#是一門(mén)面向?qū)ο蟮恼Z(yǔ)言,建議使用對(duì)象式的方式調(diào)用算子會(huì)好一點(diǎn)。
程序示例
本示例只實(shí)現(xiàn)下面幾種關(guān)鍵功能:
加載、保存圖片
畫(huà)線、框并保存
抓邊算法、測(cè)寬算法
先新建一個(gè)Winform項(xiàng)目,界面設(shè)計(jì)如下:
注:項(xiàng)目的解決方案平臺(tái)不能使用AnyCPU,只能根據(jù)安裝的Halcon位數(shù)選擇x64或x86,我使用的是x64平臺(tái)。
HSmartWindowControl控件使用
將HSmartWindowControl控件拖入主界面即可,在窗體類里面定義一個(gè)HWindow類型的成員引用控件內(nèi)部的窗體,同時(shí)設(shè)置控件的回調(diào)函數(shù)(WPF則不需要)。
代碼如下:
//窗口實(shí)例 privateHWindowhwindow; publicForm1() { InitializeComponent(); hwindow=hSmartWindowControl1.HalconWindow;//初始化窗口變量 hSmartWindowControl1.MouseWheel+=HSmartWindow_MouseWheel; } //鼠標(biāo)滾輪回調(diào) privatevoidHSmartWindow_MouseWheel(objectsender,MouseEventArgse) { Pointpt=this.Location; MouseEventArgsnewe=newMouseEventArgs(e.Button,e.Clicks,e.X-pt.X,e.Y-pt.Y,e.Delta); hSmartWindowControl1.HSmartWindowControl_MouseWheel(sender,newe); }
加載、保存圖像
加載、保存圖像也比較簡(jiǎn)單,我們需要先定義一個(gè)HImage實(shí)例,然后按鈕單擊事件在該實(shí)例上調(diào)用對(duì)應(yīng)的算子,代碼如下:
//圖片變量 privateHImageimage=newHImage(); //加載圖片 privatevoidbutton_ReadImage_Click(objectsender,EventArgse) { stringimagePath="TestRead.bmp"; image.ReadImage(imagePath); hwindow.DispImage(image); //自動(dòng)適應(yīng)圖片(相當(dāng)于控件上面的雙擊操作) hwindow.SetPart(0,0,-2,-2); } //保存圖片 privatevoidbutton_WriteImage_Click(objectsender,EventArgse) { stringimagePath="TestWrite.bmp"; image.WriteImage("bmp",0,imagePath); hwindow.DispImage(image); }
上面代碼是從程序啟動(dòng)目下加載TestRead.bmp圖片,保存圖片到程序啟動(dòng)目下的TestWrite.bmp,實(shí)際路徑可以根據(jù)項(xiàng)目情況自己定義。
上面的圖片是自己生成的,不是生產(chǎn)環(huán)境下的產(chǎn)品圖片,僅用于程序演示。
擴(kuò)展:加載相機(jī)圖像
大部分項(xiàng)目都是從相機(jī)加載圖片,但這涉及到相機(jī)驅(qū)動(dòng)的一些知識(shí),全部介紹一邊會(huì)偏移文章主題。簡(jiǎn)單來(lái)說(shuō),加載相機(jī)圖像分兩步:
將相機(jī)圖像保存到內(nèi)存
將內(nèi)存中的圖像傳入Halcon
將相機(jī)圖像保存到內(nèi)存是相機(jī)驅(qū)動(dòng)的工作,下面只討論怎么將內(nèi)存中的圖像傳入Halcon,代碼如下:
privatevoidGenImageByPtr() { //這三個(gè)參數(shù)都可以通過(guò)相機(jī)驅(qū)動(dòng)得到 byte[]imageBuf=null;//圖像緩存數(shù)組 intwidth=0;//圖像寬度 intheigth=0;//圖像高度 //獲取內(nèi)存圖像中間的指針 IntPtrptr=Marshal.UnsafeAddrOfPinnedArrayElement(imageBuf,0); //加載內(nèi)存中的圖像 image.GenImage1("byte",width,heigth,ptr); hwindow.DispImage(image); }
這里只列一個(gè)簡(jiǎn)單的示例,類似的算子還有copy_image、gen_image3等。
畫(huà)線、畫(huà)框并保存
在圖像上畫(huà)線、框是機(jī)器視覺(jué)里面常見(jiàn)的需求,根據(jù)線、框確定算法搜索的區(qū)域和特征。
在窗體類中定義一個(gè)HDrawingObject對(duì)象并附加到現(xiàn)有窗口用于交互,同時(shí)定義好Line對(duì)象、Rectangle2對(duì)象用于保存繪圖的結(jié)果。
先在圖像窗口上面畫(huà)出線和框,然后再用鼠標(biāo)手動(dòng)調(diào)整大小、位置,代碼如下:
//繪圖對(duì)象 privateHDrawingObjectdrawingObject=newHDrawingObject(); //線ROI privateLineline=newLine(); //框ROI privateRectangle2rectangle2=newRectangle2(); privatevoidbutton_DrawLine_Click(objectsender,EventArgse) { drawingObject.CreateDrawingObjectLine(100,100,200,200); //將繪圖對(duì)象關(guān)聯(lián)到Halcon窗口 hwindow.AttachDrawingObjectToWindow(drawingObject); } privatevoidbutton_SaveLine_Click(objectsender,EventArgse) { HTupleparamName,param; paramName=newHTuple(newstring[]{"row1","column1","row2","column2"}); param=drawingObject.GetDrawingObjectParams(paramName); //保存參數(shù) line.SetValue(param.ToDArr()); paramName.Dispose(); param.Dispose(); //清除繪圖內(nèi)容 drawingObject.ClearDrawingObject(); } privatevoidbutton_DrawRect_Click(objectsender,EventArgse) { drawingObject.CreateDrawingObjectRectangle2(300,400,0,300,200); //將繪圖對(duì)象關(guān)聯(lián)到Halcon窗口 hwindow.AttachDrawingObjectToWindow(drawingObject); } privatevoidbutton_SaveRect_Click(objectsender,EventArgse) { HTupleparamName,param; paramName=newHTuple(newstring[]{"row","column","phi","length1","length2"}); param=drawingObject.GetDrawingObjectParams(paramName); //保存參數(shù) rectangle2.SetValue(param.ToDArr()); paramName.Dispose(); param.Dispose(); //清除繪圖內(nèi)容 drawingObject.ClearDrawingObject(); }
上面的paramName可以取以下值,里面包含了Line、Rectangle2類屬性名:
"color","column","column1","column2","end_angle","font","length1","length2","line_style", "line_width","phi","radius","radius1","radius2","row","row1","row2","start_angle","string","type"
檢測(cè)算法
用Halcon開(kāi)發(fā)檢測(cè)算法一般有兩種方法:
根據(jù)直接調(diào)用Halcon在對(duì)應(yīng)語(yǔ)言平臺(tái)下的算子接口
用Halcon自帶的腳本語(yǔ)言開(kāi)發(fā)算法然后轉(zhuǎn)成C#類
第一種自由度比較高,代碼看起來(lái)也比較簡(jiǎn)潔易懂,但上手比較困難。第二種更簡(jiǎn)單,但生成的類很難看,而且與程序集成的時(shí)候需要做一些改動(dòng)。兩種方法并不是絕對(duì)對(duì)立的,一般會(huì)先用Halcon驗(yàn)證算法,然后參考導(dǎo)出的C#類實(shí)現(xiàn)自己的檢測(cè)算法。
抓邊算法
2D測(cè)量模型
簡(jiǎn)述一下2D 測(cè)量的使用步驟:
創(chuàng)建測(cè)量模型并指定圖像大小:首先必須使用create_metrology_model創(chuàng)建測(cè)量模型,然后使用set_metrology_model_image_size指定測(cè)量結(jié)果所在的圖像的大小。
提供近似值:將測(cè)量對(duì)象添加到測(cè)量模型中,每個(gè)測(cè)量對(duì)象由圖像中相應(yīng)對(duì)象的近似形狀參數(shù)和控制測(cè)量的參數(shù)組成,控制測(cè)量的參數(shù)包括例如指定測(cè)量區(qū)域的尺寸和分布的參數(shù),測(cè)量對(duì)象有以下幾種:
圓:add_metrology_object_circle_measure
橢圓:add_metrology_object_ellipse_measure
矩形:add_metrology_object_rectangle2_measure
線:add_metrology_object_line_measure
使用一個(gè)運(yùn)算符創(chuàng)建不同形狀:add_metrology_object_generic
要直觀檢查定義的度量對(duì)象,可以使用運(yùn)算符get_metrology_object_model_contour訪問(wèn)其XLD輪廓。要直觀檢查創(chuàng)建的測(cè)量區(qū)域,可以使用運(yùn)算符get_metrology_object_measures訪問(wèn)其XLD輪廓。
修改模型參數(shù):如果已執(zhí)行相機(jī)校準(zhǔn),則可以使用set_metrology_model_param,沒(méi)有就忽略(本示例沒(méi)有使用)。
修改對(duì)象參數(shù):當(dāng)將測(cè)量對(duì)象添加到測(cè)量模型時(shí),可以設(shè)置許多參數(shù),之后還可以使用運(yùn)算符set_metrology_object_param修改其中的一些(本示例是在添加時(shí)設(shè)置的參數(shù),所以沒(méi)有此步驟)。
調(diào)整測(cè)量模型:在執(zhí)行下一次測(cè)量之前平移和旋轉(zhuǎn)測(cè)量模型,可以使用操作員align_metrology_model。通常使用基于形狀的匹配來(lái)獲得對(duì)準(zhǔn)參數(shù),相當(dāng)于測(cè)量前的位置就糾偏(本示例比較簡(jiǎn)單沒(méi)有此步驟)。
應(yīng)用測(cè)量:使用apply_metrology_model執(zhí)行測(cè)量過(guò)程。
訪問(wèn)結(jié)果:測(cè)量后,可以使用get_metrology_object_result訪問(wèn)結(jié)果,也可以使用get_metrology_object_measures獲取定位邊的行坐標(biāo)和列坐標(biāo)再進(jìn)一步處理(本示例使用前者)。
代碼實(shí)現(xiàn)
抓變算法的C#代碼如下:
privatevoidbutton_FindEdge_Click(objectsender,EventArgse) { //創(chuàng)建測(cè)量對(duì)象 HMetrologyModelhMetrologyModely=newHMetrologyModel(); //設(shè)置圖片大小 image.GetImageSize(outintwidth,outintheight); hMetrologyModely.SetMetrologyModelImageSize(width,height); //添加直線測(cè)量 doublemeasureLength1=30,measureLength2=30,measureSigma=1,measureThreshold=30; HTuplegenParamName=newHTuple(),genParamValue=newHTuple(); hMetrologyModely.AddMetrologyObjectLineMeasure(line.Row1,line.Column1,line.Row2,line.Column2,measureLength1,measureLength2,measureSigma,measureThreshold,genParamName,genParamValue); //執(zhí)行并獲取結(jié)果 hMetrologyModely.ApplyMetrologyModel(image); //獲取測(cè)量區(qū)域 HTuplemRow=newHTuple(),mCol=newHTuple(); HXLDContmContours=hMetrologyModely.GetMetrologyObjectMeasures("all","all",outmRow,outmCol);//檢測(cè)區(qū)域輪廓 HXLDContmmContours=hMetrologyModely.GetMetrologyObjectModelContour("all",1);//測(cè)量對(duì)象輪廓 //參數(shù)順序["row_begin","column_begin","row_end","column_end"] HTuplelineRet=hMetrologyModely.GetMetrologyObjectResult("all","all","result_type","all_param"); double[]retAry=lineRet.DArr; //打印結(jié)果 hwindow.SetLineWidth(2); hwindow.SetColor("green"); hwindow.DispLine(retAry[0],retAry[1],retAry[2],retAry[3]); hwindow.SetColor("blue"); hwindow.DispXld(mContours); hwindow.SetColor("yellow"); hwindow.DispXld(mmContours); //清空測(cè)量對(duì)象 hMetrologyModely.ClearMetrologyModel(); //清理對(duì)象 hMetrologyModely?.Dispose(); genParamName?.Dispose(); genParamValue?.Dispose(); mRow.Dispose(); mCol.Dispose(); mContours.Dispose(); mmContours.Dispose(); }
Halcon的代碼如下:
*讀取圖片 read_image (Image, 'D:/test.bmp') dev_get_window (WindowHandle) *畫(huà)線 Row1:=1218.79 Column1:=1002.95 Row2:=1242.07 Column2:=2786.18 *draw_line (WindowHandle, Row1, Column1, Row2, Column2) *gen_region_line (RegionLines, Row1, Column1, Row2, Column2) *創(chuàng)建測(cè)量幾何形狀所需的數(shù)據(jù)結(jié)構(gòu) create_metrology_model (MetrologyHandle) get_image_size (Image, Width, Height) set_metrology_model_image_size (MetrologyHandle, Width, Height) add_metrology_object_line_measure (MetrologyHandle, Row1, Column1, Row2, Column2, 100, 50, 1, 30, [], [], Index) apply_metrology_model (Image, MetrologyHandle) get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type','all_param', Parameter) get_metrology_object_measures(Contours, MetrologyHandle, 'all', 'all', Row, Column) get_metrology_object_model_contour (Contour, MetrologyHandle, 0, 1.5) *清空測(cè)量對(duì)象,否則會(huì)導(dǎo)致內(nèi)存泄露 clear_metrology_model (MetrologyHandle) *可視化 dev_clear_window () dev_display(Image) dev_set_color('green') dev_set_line_width(1) disp_line (WindowHandle, Parameter[0], Parameter[1], Parameter[2], Parameter[3]) dev_display (Contours) dev_display (Contour)
使用方法
直接在界面上點(diǎn)擊“打開(kāi)圖片”->“畫(huà)線ROI”(默認(rèn)位置我都調(diào)好了,你也可以自己調(diào)整大小、位置)->“抓邊”,過(guò)程如下:
測(cè)寬算法
測(cè)寬算法使用一維測(cè)量中的measure_pairs算子提取直邊對(duì),然后計(jì)算兩個(gè)直邊的距離。代碼太長(zhǎng)這里就不貼了,完整的項(xiàng)目源碼會(huì)在文章末尾給出。
需要注意,measure_pairs算子的搜索框必須和目標(biāo)邊緣完全垂直,否則寬度數(shù)據(jù)會(huì)不準(zhǔn)確,算子原理如下:
直接在界面上點(diǎn)擊“打開(kāi)圖片”->“畫(huà)框ROI”(默認(rèn)位置我都調(diào)好了,你也可以自己調(diào)整大小、位置)->“測(cè)寬”,過(guò)程如下:
上面的箭頭就是框的方向,測(cè)量邊必須與框的方向接近垂直否則會(huì)運(yùn)算失敗,實(shí)際項(xiàng)目中還是建議用2D測(cè)量單獨(dú)抓兩個(gè)邊來(lái)測(cè)寬度。
源碼里面顯示邊緣的DispEdgeMarker方法,是直接從measure_pairs算子示例里面導(dǎo)出轉(zhuǎn)C#的,所以風(fēng)格會(huì)比較奇怪。
審核編輯:湯梓紅
-
程序
+關(guān)注
關(guān)注
117文章
3787瀏覽量
81038 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3268瀏覽量
57704 -
視覺(jué)檢測(cè)
+關(guān)注
關(guān)注
2文章
377瀏覽量
19245 -
HALCON
+關(guān)注
關(guān)注
16文章
64瀏覽量
27222
原文標(biāo)題:C# 使用Halcon開(kāi)發(fā)視覺(jué)檢測(cè)程序
文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺(jué)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論