在C#中使用Halcon開發視覺檢測程式

来源:https://www.cnblogs.com/timefiles/archive/2022/11/27/16928651.html
-Advertisement-
Play Games

簡介 本文的初衷是希望幫助那些有其它平臺視覺演算法開發經驗的人能快速轉入Halcon平臺下,通過文中的示例開發者能快速瞭解一個Halcon項目開發的基本步驟,讓開發者能把精力完全集中到演算法的開發上面。 首先,你需要安裝Halcon,HALCON 18.11.0.1的安裝包會放在文章末尾。安裝包分開發和 ...


目錄

簡介

本文的初衷是希望幫助那些有其它平臺視覺演算法開發經驗的人能快速轉入Halcon平臺下,通過文中的示例開發者能快速瞭解一個Halcon項目開發的基本步驟,讓開發者能把精力完全集中到演算法的開發上面。

首先,你需要安裝HalconHALCON 18.11.0.1的安裝包會放在文章末尾。安裝包分開發和運行時兩個版本,運行時版本一般用於生產環境。
註:開發版本自帶運行時可替代運行時版本,但安裝的東西會比較多。

然後,你需要學會查看Halcon的幫助手冊,這是很重要的一件事

本文涉及到幫助文檔的主要章節如下:

原文 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 運算符參考

文中的示例是我第一次接觸Halcon時的學習測試用例,在電腦裡面躺了一年,最近才有時間整理一下發出來,希望能對你有所幫助。

註:運行本文示常式序前至少安裝Halcon的運行時,否則Halcon的dll無法正常使用

將 HALCON/.NET 添加到應用程式

添加控制項

右鍵單擊工具箱,然後選擇“選擇項”,彈出的對話框選擇“.NET Framework組件”,單擊下麵的“瀏覽”,導航到HALCON安裝目錄下的\bin\dotnet35(VS2008以下版本的選擇dotnet20) ,然後選擇halcondotnet.dll

完成上述操作後,HSmartWindowControl和HWindowControl控制項就會出現在工具箱中,其中HWindowControl控制項已經過時官方不再推薦使用。

與HWindowControl相比,HSmartWindowControl控制項具有以下幾個優點:

  • 可以像任何其他控制項一樣使用
  • 提供預定義的滑鼠交互(移動視窗內容並使用滑鼠滾輪進行縮放), 可以通過雙擊視窗來重置視圖
  • 控制項會自動重新縮放,而不會閃爍

註:與HSmartWindowControlWPF 相反,HSmartWindowControl需要一個回調才能使用滑鼠滾輪進行縮放

引用dll

在HALCON安裝目錄下的\bin\dotnet35中,引用以下dll:

  • hdevenginedotnet.dll
  • halcondotnet.dll

註:使用 HALCON XL 開發應用程式時,必須選擇以xl結尾的dll,hhdevelop xl適用於大解析度的圖像(大於 32k x 32k )。

引用以下命名空間:

  • HalconDotNet:控制項所在的命名空間
  • HalconTypeLineRectangle2等數據類型所在的命名空間

調用Halcon運算元

ReadImage操作為例,函數原型如下:

static void HOperatorSet.ReadImage(out HObject image, HTuple fileName)

public HImage(HTuple fileName)

public HImage(string fileName)

void HImage.ReadImage(HTuple fileName)

void HImage.ReadImage(string fileName)

註:這些內容幫助手冊上都有,在文章開頭列出來的章節。

在C#調用HALCON 運算元有兩種選擇:函數式對象式,前值通過HOperatorSet調用運算元並通過out關鍵字傳入關鍵對象,後者直接在關鍵對象上調用對應的方法。
兩種方法完全等價,C#是一門面向對象的語言,建議使用對象式的方式調用運算元會好一點。

程式示例

本示例只實現下麵幾種關鍵功能:

  • 載入、保存圖片
  • 畫線、框並保存
  • 抓邊演算法、測寬演算法

先新建一個Winform項目,界面設計如下:

註:項目的解決方案平臺不能使用AnyCPU,只能根據安裝的Halcon位數選擇x64x86,我使用的是x64平臺。

HSmartWindowControl控制項使用

將HSmartWindowControl控制項拖入主界面即可,在窗體類裡面定義一個HWindow類型的成員引用控制項內部的窗體,同時設置控制項的回調函數(WPF則不需要)。代碼如下:

//視窗實例
private HWindow hwindow;
       
public Form1()
{
    InitializeComponent();
    hwindow = hSmartWindowControl1.HalconWindow;//初始化視窗變數
    hSmartWindowControl1.MouseWheel += HSmartWindow_MouseWheel;
}

//滑鼠滾輪迴調
private void HSmartWindow_MouseWheel(object sender, MouseEventArgs e)
{
    Point pt = this.Location;
    MouseEventArgs newe = new MouseEventArgs(e.Button, e.Clicks, e.X - pt.X, e.Y - pt.Y, e.Delta);
    hSmartWindowControl1.HSmartWindowControl_MouseWheel(sender, newe);
}

載入、保存圖像

載入、保存圖像也比較簡單,我們需要先定義一個HImage實例,然後按鈕單擊事件在該實例上調用對應的運算元,代碼如下:

//圖片變數
private HImage image = new HImage();
//載入圖片
private void button_ReadImage_Click(object sender, EventArgs e)
{           
    string imagePath = "TestRead.bmp";
    image.ReadImage(imagePath);
    hwindow.DispImage(image);
    //自動適應圖片(相當於控制項上面的雙擊操作)
    hwindow.SetPart(0, 0, -2, -2);
}
//保存圖片
private void button_WriteImage_Click(object sender, EventArgs e)
{
    string imagePath = "TestWrite.bmp";
    image.WriteImage("bmp", 0, imagePath);
    hwindow.DispImage(image);
}

上面代碼是從程式啟動目下載入TestRead.bmp圖片,保存圖片到程式啟動目下的TestWrite.bmp,實際路徑可以根據項目情況自己定義。
上面的圖片是自己生成的,不是生產環境下的產品圖片,僅用於程式演示。

擴展:載入相機圖像

大部分項目都是從相機載入圖片,但這涉及到相機驅動的一些知識,全部介紹一邊會偏移文章主題。
簡單來說,載入相機圖像分兩步:

  • 將相機圖像保存到記憶體
  • 將記憶體中的圖像傳入Halcon

將相機圖像保存到記憶體是相機驅動的工作,下麵只討論怎麼將記憶體中的圖像傳入Halcon,代碼如下:

private void GenImageByPtr()
{
    //這三個參數都可以通過相機驅動得到
    byte[] imageBuf = null;   //圖像緩存數組
    int width = 0;            //圖像寬度
    int heigth = 0;           //圖像高度
    //獲取記憶體圖像中間的指針
    IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(imageBuf, 0);
    //載入記憶體中的圖像
    image.GenImage1("byte", width, heigth, ptr);
    hwindow.DispImage(image);
}

這裡只列一個簡單的示例,類似的運算元還有copy_imagegen_image3等。

畫線、畫框並保存

在圖像上畫線、框是機器視覺裡面常見的需求,根據線、框確定演算法搜索的區域和特征。
在窗體類中定義一個HDrawingObject對象並附加到現有視窗用於交互,同時定義好Line對象、Rectangle2對象用於保存繪圖的結果。
先在圖像視窗上面畫出線和框,然後再用滑鼠手動調整大小、位置,代碼如下:

//繪圖對象
private HDrawingObject drawingObject = new HDrawingObject();
//線ROI
private Line line = new Line();
//框ROI
private Rectangle2 rectangle2 = new Rectangle2();

private void button_DrawLine_Click(object sender, EventArgs e)
{
    drawingObject.CreateDrawingObjectLine(100, 100, 200, 200);
    //將繪圖對象關聯到Halcon視窗
    hwindow.AttachDrawingObjectToWindow(drawingObject);
}
private void button_SaveLine_Click(object sender, EventArgs e)
{
    HTuple paramName, param;            
    paramName = new HTuple(new string[] { "row1", "column1", "row2", "column2" });
    param = drawingObject.GetDrawingObjectParams(paramName);
    //保存參數
    line.SetValue(param.ToDArr());
    paramName.Dispose();
    param.Dispose();
    //清除繪圖內容
    drawingObject.ClearDrawingObject();           
}

private void button_DrawRect_Click(object sender, EventArgs e)
{
    drawingObject.CreateDrawingObjectRectangle2(300, 400, 0, 300, 200);
    //將繪圖對象關聯到Halcon視窗
    hwindow.AttachDrawingObjectToWindow(drawingObject);
}
private void button_SaveRect_Click(object sender, EventArgs e)
{
    HTuple paramName, param;
    paramName = new HTuple(new string[] { "row", "column", "phi", "length1", "length2" });
    param = drawingObject.GetDrawingObjectParams(paramName);
    //保存參數
    rectangle2.SetValue(param.ToDArr());
    paramName.Dispose();
    param.Dispose();
    //清除繪圖內容
    drawingObject.ClearDrawingObject();
}

上面的paramName可以取以下值,裡面包含了LineRectangle2類屬性名:

"color", "column", "column1", "column2", "end_angle", "font", "length1", "length2", "line_style", 
"line_width", "phi", "radius", "radius1", "radius2", "row", "row1", "row2", "start_angle", "string", "type"

檢測演算法

用Halcon開發檢測演算法一般有兩種方法:

  • 根據直接調用Halcon在對應語言平臺下的運算元介面
  • 用Halcon自帶的腳本語言開發演算法然後轉成C#類

第一種自由度比較高,代碼看起來也比較簡潔易懂,但上手比較困難。第二種更簡單,但生成的類很難看,而且與程式集成的時候需要做一些改動。
兩種方法並不是絕對對立的,一般會先用Halcon驗證演算法,然後參考導出的C#類實現自己的檢測演算法。

抓邊演算法

抓變演算法直接調用的是Halcon的C#運算元介面,裡面有用到2D 測量模型

2D測量模型

簡述一下2D 測量的使用步驟:

  • 創建測量模型並指定圖像大小:首先必須使用create_metrology_model創建測量模型,然後使用set_metrology_model_image_size指定測量結果所在的圖像的大小。

  • 提供近似值:將測量對象添加到測量模型中,每個測量對象由圖像中相應對象的近似形狀參數控制測量的參數組成,控制測量的參數包括例如指定測量區域的尺寸和分佈的參數,測量對象有以下幾種:

    • :add_metrology_object_circle_measure
    • 橢圓:add_metrology_object_ellipse_measure
    • 矩形:add_metrology_object_rectangle2_measure
    • :add_metrology_object_line_measure
    • 使用一個運算符創建不同形狀:add_metrology_object_generic

要直觀檢查定義的度量對象,可以使用運算符get_metrology_object_model_contour訪問其XLD輪廓。要直觀檢查創建的測量區域,可以使用運算符get_metrology_object_measures訪問其XLD輪廓。

  • 修改模型參數:如果已執行相機校準,則可以使用set_metrology_model_param,沒有就忽略(本示例沒有使用)。

  • 修改對象參數:當將測量對象添加到測量模型時,可以設置許多參數,之後還可以使用運算符set_metrology_object_param修改其中的一些(本示例是在添加時設置的參數,所以沒有此步驟)。

  • 調整測量模型:在執行下一次測量之前平移和旋轉測量模型,可以使用操作員align_metrology_model。通常使用基於形狀的匹配來獲得對準參數,相當於測量前的位置就糾偏(本示例比較簡單沒有此步驟)。

  • 應用測量:使用apply_metrology_model執行測量過程。

  • 訪問結果:測量後,可以使用get_metrology_object_result訪問結果,也可以使用get_metrology_object_measures獲取定位邊的行坐標和列坐標再進一步處理(本示例使用前者)。

代碼實現

抓變演算法的C#代碼如下:

private void button_FindEdge_Click(object sender, EventArgs e)
{
    //創建測量對象
    HMetrologyModel hMetrologyModely = new HMetrologyModel();
    //設置圖片大小            
    image.GetImageSize(out int width, out int height);
    hMetrologyModely.SetMetrologyModelImageSize(width, height);
    //添加直線測量
    double measureLength1= 30, measureLength2=30, measureSigma=1, measureThreshold=30;
    HTuple genParamName = new HTuple(), genParamValue = new HTuple();
    hMetrologyModely.AddMetrologyObjectLineMeasure(line.Row1, line.Column1,line.Row2, line.Column2, measureLength1, measureLength2, measureSigma, measureThreshold, genParamName, genParamValue);
    //執行並獲取結果
    hMetrologyModely.ApplyMetrologyModel(image);
    //獲取測量區域
    HTuple mRow = new HTuple(), mCol = new HTuple();
    HXLDCont mContours = hMetrologyModely.GetMetrologyObjectMeasures("all", "all", out mRow, out mCol); //檢測區域輪廓
    HXLDCont mmContours = hMetrologyModely.GetMetrologyObjectModelContour("all", 1);    //測量對象輪廓
    //參數順序 ["row_begin", "column_begin", "row_end", "column_end"]
    HTuple  lineRet =hMetrologyModely.GetMetrologyObjectResult("all", "all", "result_type", "all_param");
    double[] retAry = lineRet.DArr;
    //列印結果
    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);
    //清空測量對象
    hMetrologyModely.ClearMetrologyModel();
    //清理對象
    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)

*畫線
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)

*創建測量幾何形狀所需的數據結構
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)

*清空測量對象,否則會導致記憶體泄露
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)

使用方法

直接在界面上點擊“打開圖片”->“畫線ROI”(預設位置我都調好了,你也可以自己調整大小、位置)->“抓邊”,過程如下:

測寬演算法

測寬演算法使用一維測量中的measure_pairs運算元提取直邊對,然後計算兩個直邊的距離。代碼太長這裡就不貼了,完整的項目源碼會在文章末尾給出。
需要註意,measure_pairs運算元的搜索框必須和目標邊緣完全垂直,否則寬度數據會不准確,運算元原理如下:

直接在界面上點擊“打開圖片”->“畫框ROI”(預設位置我都調好了,你也可以自己調整大小、位置)->“測寬”,過程如下:

上面的箭頭就是框的方向,測量邊必須與框的方向接近垂直否則會運算失敗,實際項目中還是建議用2D測量單獨抓兩個邊來測寬度。
源碼裡面顯示邊緣的DispEdgeMarker方法,是直接從measure_pairs運算元示例裡面導出轉C#的,所以風格會比較奇怪。

附件


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.小結 1.使用二維數組來存儲表格 2.可以使用以下語法來聲明二維數組變數: 元素類型[ ] [ ]數組變數 3.可以使用以下語法來創建二維數組變數: new 元素類型 [行的個數][列的個數] 4.使用下麵的語法表示二維數組中的每個元素: 數組變數[行下標][列的個數] 5.可使用數組初始化語法 ...
  • 前言 本篇是c++總結的第二篇,關於c++的對象模型,在構造、拷貝虛函數上重點分析,也包含了c++11class的新用法和特性,如有不當,還請指教! c++三大特性 訪問許可權 ​ 在c++中通過public、protected、private三個關鍵字來控製成員變數和成員函數的訪問許可權,它們分別表示 ...
  • Spring 框架可以為 Java 應用程式開發提供全面的基礎設施支持,它是現在非常流行的 Java 開源框架,對於一個 Java 開發人員來說,熟練掌握 Spring 是必不可少的。 ...
  • 1. 查看Linux伺服器版本信息 # cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) 2. 禪道開源版安裝包下載 wget http://dl.cnezsoft.com/zentao/9.8.2/ZenTaoPMS.9.8. ...
  • 目錄 一.OpenGL 色階 1.Windows OpenGL ES 版本 2.Windows OpenGL 版本 二.OpenGL 色階 GLSL Shader 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 Ope ...
  • 我們都知道在Java編程中多線程的同步使用synchronized關鍵字來標識,那麼這個關鍵字在JVM底層到底是如何實現的呢。 我們先來思考一下如果我們自己實現的一個鎖該怎麼做呢: 首先肯定要有個標記記錄對象是否已經上鎖,執行同步代碼之前判斷這個標誌,如果對象已經上鎖線程就阻塞等待鎖的釋放。 其次要 ...
  • JZ7重建二叉樹 描述 給定節點數為 n 的二叉樹的前序遍歷和中序遍歷結果,請重建出該二叉樹並返回它的頭結點。 例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6} 提示: 1.vin.length == pre.length 2.pre 和 vin ...
  • 本文是對Datawhale的動手學數據分析課程的學習總結,記錄了整體的學習過程、答案以及個人感想,代碼較為詳細。 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...