在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
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...