在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
  • 前言 當別人做大數據用Java、Python的時候,我使用.NET做大數據、數據挖掘,這確實是值得一說的事。 寫的並不全面,但都是實際工作中的內容。 .NET在大數據項目中,可以做什麼? 寫腳本(使用控制台程式+頂級語句) 寫工具(使用Winform) 寫介面、寫服務 使用C#寫代碼的優點是什麼? ...
  • 前言 本文寫給想學C#的朋友,目的是以儘快的速度入門 C#好學嗎? 對於這個問題,我以前的回答是:好學!但仔細想想,不是這麼回事,對於新手來說,C#沒有那麼好學。 反而學Java還要容易一些,學Java Web就行了,就是SpringBoot那一套。 但是C#方向比較多,你是學控制台程式、WebAP ...
  • 某一日晚上上線,測試同學在回歸項目黃金流程時,有一個工單項目介面報JSF序列化錯誤,馬上升級對應的client包版本,編譯部署後錯誤消失。 線上問題是解決了,但是作為程式員要瞭解問題發生的原因和本質。但這都是為什麼呢? ...
  • 本文介紹基於Python語言中TensorFlow的Keras介面,實現深度神經網路回歸的方法。 1 寫在前面 前期一篇文章Python TensorFlow深度學習回歸代碼:DNNRegressor詳細介紹了基於TensorFlow tf.estimator介面的深度學習網路;而在TensorFl ...
  • 前段時間因業務需要完成了一個工作流組件的編碼工作。藉著這個機會跟大家分享一下整個創作過程,希望大家喜歡,組件暫且命名為"easyFlowable"。 接下來的文章我將從什麼是工作流、為什麼要自研這個工作流組件、架構設計三個維度跟大家來做個整體介紹。 ...
  • 1 簡介 我們之前使用了dapr的本地托管模式,但在生產中我們一般使用Kubernetes托管,本文介紹如何在GKE(GCP Kubernetes)安裝dapr。 相關文章: dapr本地托管的服務調用體驗與Java SDK的Spring Boot整合 dapr入門與本地托管模式嘗試 2 安裝GKE ...
  • 摘要:在jvm中有很多的參數可以進行設置,這樣可以讓jvm在各種環境中都能夠高效的運行。絕大部分的參數保持預設即可。 本文分享自華為雲社區《為什麼需要對jvm進行優化,jvm運行參數之標準參數》,作者:共飲一杯無。 我們為什麼要對jvm做優化? 在本地開發環境中我們很少會遇到需要對jvm進行優化的需 ...
  • 背景 我們的業務共使用11台(阿裡雲)伺服器,使用SpringcloudAlibaba構建微服務集群,共計60個微服務,全部註冊在同一個Nacos集群 流量轉發路徑: nginx->spring-gateway->業務微服務 使用的版本如下: spring-boot.version:2.2.5.RE ...
  • 基於php+webuploader的大文件分片上傳,帶進度條,支持斷點續傳(刷新、關閉頁面、重新上傳、網路中斷等情況)。文件上傳前先檢測該文件是否已上傳,如果已上傳提示“文件已存在”,如果未上傳則直接上傳。視頻上傳時會根據設定的參數(分片大小、分片數量)進行上傳,上傳過程中會在目標文件夾中生成一個臨 ...
  • 基於php大文件分片上傳至七牛雲,使用的是七牛雲js-sdk V2版本,引入js文件,配置簡單,可以暫停,暫停後支持斷點續傳(刷新、關閉頁面、重新上傳、網路中斷等情況),可以配置分片大小和分片數量,官方文檔https://developer.qiniu.com/kodo/6889/javascrip ...