2021年3月6日 星期六

Halcon HDrawingObject 研究小記

簡單的使用

 HDrawingObject從Halcon12就有了

可以在HalconWindow中建立一個可變大小的ROI
使用方式如下


下圖左邊的紅色框框是建立結果


下圖是截取自Halcon文件,是HDrawingObject可建立的ROI種類[1]



進階功能

由於有些動作是需要在HDrawingObject的某些動作時做的,也就是需要事件的觸發。
不過HDrawingObject觸發的方式是消息驅動(Message-Driven) (詳請見參考資料[2]),
目前可以接收的消息有這幾種
這個Callback的用法很特別,研究了很久
先來介紹一下怎麼使用,再來介紹一下我一開始是怎麼栽在這傢伙手上的。
使用方法的部分,我是從stackoverflow上找到的[3],
所以我直接使用stackoverflow的程式碼講解。

下圖是stackoverflow的程式碼及我的理解筆記


這個物件使用要注意的點是,
必需先宣告一個HDrawingObjectCallback的property,
再將要回呼(callback)的method指派給該屬性,
最再使用Marshal.GetFunctionPointerForDelegate轉成IntPtr,以便轉成HTuple。

如果直接使用new的方式建立要委派的callback function,如下圖
會出現
HalconDotNet.HDrawingObject+HDrawingObjectCallback::Invoke' 的記憶體回收委派上進行回呼。這樣可能導致應用程式無法運作、損毀或遺失資料。傳遞委派到 Unmanaged 程式碼時,必須由 Managed 應用程式讓它們保持運作,直到確定不會再呼叫它們為止。'
的錯誤訊息,如下圖

這就是一開始一直卡住的地方。

那為什麼會有這個問題呢?
原因是設成屬性(property)的作用域(scope)比較大[4], [5], [6]:
在這個情境中,
Marshal.GetFunctionPointerForDelegate的功能只是將Delegate轉成native function pointer,
Delegate才是托管要給native code/unmanage code函式的主體(在這個情境中,HDrawingObjectCallback就是那個Delegate)
當非托管的程式碼不使用該函式時,
Delegate會呼叫.NET的CLR會將該函式的資源釋放掉,
因此,GetFunctionPointerForDelegate的參數(也就是要給非托管函式呼叫的Delegate)的作用域必需大一點。
若是使用會出錯的寫法,Delegate是new出來的,所以過了該方法後就會被GC,
因此,需要讓Delegate的作用域長一點,所以才設成property,這樣類別實體存在的期間,
Delegate都可以運作!

最後補充說明一下,
如果想將HDrawingObject序列化,只能使用BinaryFormatter
因為HDrawingObject沒有可以用來序列化成xml或是json的公開(public)屬性。



詳細的程式碼在我的github上(連結)
不過在github中,我已經將HDrawingObject的操作包成一個class ─ HDrawingObjectController,
在Form1中都是呼叫該HDrawingObjectController去做。


參考資料:


沒有留言:

張貼留言