以下是針對提供的C#代碼的詳細注釋和解釋,結合Halcon庫的功能和代碼結構進行說明:
---
### **代碼整體結構**
該代碼是一個基于Halcon庫的條碼掃描類`GeneralBarcodeScan`,支持單臺或雙臺相機的條碼檢測,并通過回調接口返回結果。主要功能包括:
1. 相機初始化與圖像采集。
2. 條碼檢測模型配置(靜區、容錯等)。
3. 單/雙相機圖像處理與條碼識別。
4. 資源管理(釋放相機、圖像對象等)。
---
### **關鍵代碼注釋**
#### **1. 類定義與成員變量**
```csharp
public class GeneralBarcodeScan : IDisposable
{
? ? private string mLastErrorMsg; ?// 存儲最后的錯誤信息
? ? private ICcdCallback mCallback; ?// 相機回調接口,用于處理掃描到的條碼數據
? ? private HTuple mHvAcqHandle; ? ?// 第一臺相機的句柄
? ? private HTuple mHvAcqHandle2; ? // 第二臺相機的句柄
? ? private HObject mHoImage; ? ? ? // 存儲第一臺相機捕獲的圖像
? ? private HObject mHoImage2; ? ? ?// 存儲第二臺相機捕獲的圖像
? ? // ... 其他窗口相關變量 ...
}
```
- **功能**:定義類的成員變量,包括相機句柄、圖像對象、錯誤信息和回調接口。
- **關鍵點**:`HTuple`是Halcon中常用的參數傳遞類型,`HObject`用于存儲圖像數據。
---
#### **2. 構造函數與資源初始化**
```csharp
public GeneralBarcodeScan()
{
? ? mHvAcqHandle = new HTuple(); ? ?// 初始化相機句柄
? ? mHvAcqHandle2 = new HTuple();
? ? HOperatorSet.GenEmptyObj(out mHoImage); ?// 創建空圖像對象
? ? HOperatorSet.GenEmptyObj(out mHoImage2);
? ? // 設置系統默認圖像大小為512x512
? ? HOperatorSet.SetSystem("width", 512);
? ? HOperatorSet.SetSystem("height", 512);
? ? // 初始化第二個窗口的尺寸為0
? ? mWndWidth2 = 0;
? ? mWndHeight2 = 0;
}
```
- **功能**:初始化類成員變量,并設置Halcon的默認圖像尺寸。
- **關鍵函數**:
? - `GenEmptyObj`:創建空的`HObject`對象。
? - `SetSystem`:設置Halcon系統參數(如默認圖像尺寸)。
---
#### **3. 相機打開與初始化方法**
```csharp
public bool OpenImageAcq(HWindow hHalconWnd, int wndWidth, int wndHeight, int deviceQty)
{
? ? this.mHPreviewWnd = hHalconWnd; ?// 設置顯示窗口
? ? this.mWndWidth = wndWidth;
? ? this.mWndHeight = wndHeight;
? ? // ... 省略部分代碼 ...
? ? // 獲取相機設備信息
? ? HOperatorSet.InfoFramegrabber("GigEVision2", "device", out hvDeviceInfo, out hvDeviceInfoValues);
? ? if (hvDeviceInfoValues.Length == 0) ?// 檢查設備是否存在
? ? {
? ? ? ? this.mLastErrorMsg = "獲取不到相機設備";
? ? ? ? return false;
? ? }
? ? // 打開第一臺相機
? ? HOperatorSet.OpenFramegrabber("GigEVision2", 0, 0, 0, 0, 0, 0, "progressive",
? ? ? ? -1, "default", -1, "false", "default", hvDeviceInfoValues.TupleSelect(0), 0, -1, out mHvAcqHandle);
? ? // 設置相機超時參數
? ? HOperatorSet.SetFramegrabberParam(mHvAcqHandle, "grab_timeout", 2000);
? ? HOperatorSet.GrabImageStart(mHvAcqHandle, -1); ?// 開始異步圖像采集
? ? // ... 雙相機處理邏輯 ...
? ? return true;
}
```
- **功能**:打開相機并初始化參數,支持單/雙相機配置。
- **關鍵函數**:
? - `OpenFramegrabber`:通過GigE Vision協議連接相機。
? - `GrabImageStart`:開始異步圖像采集(`-1`表示連續采集)。
- **參數說明**:
? - `"GigEVision2"`:指定相機協議類型。
? - `hvDeviceInfoValues.TupleSelect(0)`:選擇第一個檢測到的相機設備。
---
#### **4. 相機關閉與資源釋放**
```csharp
public void CloseImageAcq()
{
? ? if (this.mHoImage != null)
? ? {
? ? ? ? this.mHoImage.Dispose(); ?// 釋放圖像對象
? ? ? ? this.mHoImage = null;
? ? }
? ? if (this.mHvAcqHandle != null)
? ? {
? ? ? ? HOperatorSet.CloseFramegrabber(this.mHvAcqHandle); ?// 關閉相機
? ? ? ? this.mHvAcqHandle.Dispose();
? ? ? ? this.mHvAcqHandle = null;
? ? }
? ? // ... 處理第二個相機和窗口 ...
}
```
- **功能**:釋放相機句柄、圖像對象和窗口資源。
- **關鍵函數**:
? - `CloseFramegrabber`:關閉相機連接。
? - `Dispose`:釋放Halcon對象資源。
---
#### **5. 條碼掃描核心邏輯(單相機)**
```csharp
public void StartScanBarcode(int qty)
{
? ? List<string> barcodeList = new List<string>();
? ? HObject hoImage; ?// 當前捕獲的圖像
? ? HTuple hvBarCodeHandle; ?// 條碼檢測模型句柄
? ? // ... 省略部分代碼 ...
? ? // 創建條碼檢測模型并配置參數
? ? HOperatorSet.CreateBarCodeModel(new HTuple("quiet_zone"), new HTuple("true"), out hvBarCodeHandle);
? ? HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "majority_voting", "true"); ?// 啟用多數表決
? ? HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "element_size_variable", "true"); ?// 允許模塊尺寸變化
? ? // 捕獲圖像并檢測條碼
? ? HOperatorSet.GrabImageAsync(out hoImage, mHvAcqHandle, -1); ?// 異步獲取圖像
? ? HOperatorSet.FindBarCode(hoImage, out hoSymbolRegions, hvBarCodeHandle, "Code 128", out hvDecodedDataStrings);
? ? // 處理檢測結果
? ? for (int i = 0; i < hvDecodedDataStrings.Length; i++)
? ? {
? ? ? ? barcodeList.Add(hvDecodedDataStrings[i]); ?// 存儲解碼后的條碼數據
? ? }
? ? // 釋放資源并觸發回調
? ? if (mCallback != null) mCallback.FoundBarcode(barcodeList); ?// 通知回調函數
}
```
- **功能**:捕獲圖像并檢測Code 128條碼,通過回調返回結果。
- **關鍵步驟**:
? 1. **創建檢測模型**:`CreateBarCodeModel`配置靜區檢測。
? 2. **設置參數**:啟用多數表決(減少誤檢)、允許模塊尺寸變化(適應變形條碼)。
? 3. **圖像采集**:`GrabImageAsync`異步獲取單張圖像。
? 4. **條碼檢測**:`FindBarCode`返回解碼結果。
- **參數解釋**:
? - `quiet_zone`:檢測條碼周圍的空白區域,提升穩定性。
? - `majority_voting`:通過多條掃描線投票選擇最終解碼結果。
---
#### **6. 雙相機拼接與檢測**
```csharp
public void StartScanBarcodeBy2Device(bool reverse)
{
? ? HObject hoImage, hoImage2, hoImages; ?// 兩臺相機的圖像
? ? // ... 省略部分代碼 ...
? ? // 捕獲并拼接圖像
? ? HOperatorSet.GrabImageAsync(out hoImage, mHvAcqHandle, -1);
? ? HOperatorSet.GrabImageAsync(out hoImage2, mHvAcqHandle2, -1);
? ? if (reverse) ?// 根據參數決定拼接順序
? ? {
? ? ? ? HOperatorSet.ConcatObj(hoImages, hoImage2, out hoImages);
? ? ? ? HOperatorSet.ConcatObj(hoImages, hoImage, out hoImages);
? ? }
? ? else
? ? {
? ? ? ? HOperatorSet.ConcatObj(hoImages, hoImage, out hoImages);
? ? ? ? HOperatorSet.ConcatObj(hoImages, hoImage2, out hoImages);
? ? }
? ? HOperatorSet.TileImages(hoImages, out hoObjectsConcat, 2, "horizontal"); ?// 水平拼接
? ? // 執行檢測(后續步驟與單相機相同)
}
```
- **功能**:同時捕獲雙相機圖像并拼接,再進行條碼檢測。
- **關鍵函數**:
? - `ConcatObj`:合并圖像對象。
? - `TileImages`:將圖像拼接成單個圖像(`horizontal`表示水平方向)。
- **參數`reverse`**:控制圖像拼接的順序(是否反轉雙相機的順序)。
---
#### **7. 窗口適配與顯示**
```csharp
private HTuple[] GetDisplayRect(int wndWidth, int wndHeight, int imageWidth, int imageHeight)
{
? ? // 計算圖像在窗口中的顯示區域,保持比例
? ? double widthRatio = (double)imageWidth / wndWidth;
? ? double heightRatio = (double)imageHeight / wndHeight;
? ? HTuple row1, column1, row2, column2;
? ? if (widthRatio >= heightRatio) ?// 寬度占優,以寬度比例縮放
? ? {
? ? ? ? row1 = -(wndHeight * widthRatio - imageHeight) / 2;
? ? ? ? column1 = 0;
? ? ? ? row2 = row1 + wndHeight * widthRatio;
? ? ? ? column2 = column1 + wndWidth * widthRatio;
? ? }
? ? else ?// 高度占優,以高度比例縮放
? ? {
? ? ? ? row1 = 0;
? ? ? ? column1 = -(wndWidth * heightRatio - imageWidth) / 2;
? ? ? ? row2 = row1 + wndHeight * heightRatio;
? ? ? ? column2 = column1 + wndWidth * heightRatio;
? ? }
? ? return new HTuple[] { row1, column1, row2, column2 };
}
```
- **功能**:根據窗口尺寸計算圖像顯示區域,保持圖像比例。
- **實現邏輯**:
? - 計算寬高比,選擇占優方向進行縮放。
? - 調整顯示區域的坐標,確保圖像居中顯示。
---
### **關鍵函數與參數說明**
#### **Halcon函數**
| 函數名 | 功能 | 參數示例 |
|--------|------|----------|
| `OpenFramegrabber` | 打開相機 | `"GigEVision2"`, 設備標識符 |
| `GrabImageAsync` | 異步抓取圖像 | `out HObject`, 相機句柄 |
| `CreateBarCodeModel` | 創建條碼檢測模型 | `'quiet_zone'`, `'true'` |
| `FindBarCode` | 檢測圖像中的條碼 | `'Code 128'` |
| `TileImages` | 拼接圖像 | `'horizontal'` |
#### **參數解釋**
| 參數名 | 作用 |
|--------|------|
| `quiet_zone` | 啟用條碼周圍空白區域檢測 |
| `majority_voting` | 啟用多條掃描線投票機制 |
| `element_size_variable` | 允許條碼模塊尺寸變化(適應變形條碼) |
| `start_stop_tolerance` | 設置起始符/終止符的容錯級別 |
---
### **代碼優勢與注意事項**
#### **優勢**
1. **資源管理**:通過`IDisposable`接口確保相機和圖像對象的正確釋放。
2. **雙相機支持**:可擴展至多相機協同檢測,提升檢測范圍。
3. **條碼檢測優化**:通過靜區和容錯參數提升魯棒性。
#### **注意事項**
1. **相機配置**:
? ?- 需確保相機型號與`GigEVision2`協議兼容。
? ?- 網絡配置(如IP地址)需提前設置。
2. **資源泄漏風險**:
? ?- 必須在`using`塊或`Dispose()`中調用`CloseImageAcq()`。
3. **性能優化**:
? ?- 雙相機拼接可能增加處理時間,需根據場景調整。
---
### **典型使用流程**
```csharp
// 1. 初始化類并設置回調
var scanner = new GeneralBarcodeScan();
scanner.setCallback(new MyCcdCallback());
// 2. 打開相機(假設單相機)
scanner.OpenImageAcq(window, 1280, 720, 1);
// 3. 開始檢測
scanner.StartScanBarcode(1);
// 4. 關閉資源
scanner.Dispose();
```
通過以上注釋和解釋,開發者可以清晰理解代碼功能、參數含義及實現邏輯。
using HalconDotNet; // 引用 Halcon 圖像處理庫
using Hggit.Hwodc.Common; // 引用其他庫
using System; // 引用系統庫
using System.Collections.Generic; // 引用集合類庫
using System.Linq; // 引用 LINQ 查詢庫
using System.Text; // 引用字符串處理類庫
using System.Threading.Tasks; // 引用異步任務處理庫namespace Hggit.Hwodc.Halcon
{public class GeneralBarcodeScan : IDisposable{private string mLastErrorMsg; // 保存最后的錯誤信息private ICcdCallback mCallback; // 相機回調接口,用于處理掃描到的條形碼/// <summary>/// 相機句柄,用于相機圖像捕獲/// </summary>private HTuple mHvAcqHandle;/// <summary>/// 第二個相機句柄/// </summary>private HTuple mHvAcqHandle2;/// <summary>/// 捕獲的圖像對象/// </summary>private HObject mHoImage;/// <summary>/// 第二個捕獲的圖像對象/// </summary>private HObject mHoImage2;/// <summary>/// 窗口的寬度/// </summary>private int mWndWidth;/// <summary>/// 窗口的高度/// </summary>private int mWndHeight;/// <summary>/// Halcon 圖像顯示窗口/// </summary>private HWindow mHPreviewWnd;/// <summary>/// Halcon 圖像顯示窗口內部句柄/// </summary>HTuple mHvWindowHandle;/// <summary>/// 第二個窗口寬度/// </summary>private int mWndWidth2;/// <summary>/// 第二個窗口高度/// </summary>private int mWndHeight2;/// <summary>/// 第二個窗口的句柄/// </summary>HTuple mHvWindowHandle2;public void Dispose(){// 清理資源,關閉相機及圖像對象CloseImageAcq();}public GeneralBarcodeScan(){// 初始化相機句柄和圖像對象mHvAcqHandle = new HTuple();mHvAcqHandle2 = new HTuple();HOperatorSet.GenEmptyObj(out mHoImage);HOperatorSet.GenEmptyObj(out mHoImage2);// 設置系統默認圖像大小HOperatorSet.SetSystem("width", 512);HOperatorSet.SetSystem("height", 512);mWndWidth2 = 0;mWndHeight2 = 0;}public void setCallback(ICcdCallback callback){// 設置回調接口this.mCallback = callback;}/// <summary>/// 打開相機并初始化圖像采集/// </summary>/// <returns>返回是否成功打開相機</returns>public bool OpenImageAcq(HWindow hHalconWnd, int wndWidth, int wndHeight, int deviceQty){this.mHPreviewWnd = hHalconWnd;this.mWndWidth = wndWidth;this.mWndHeight = wndHeight;// 檢查操作系統是否為 Windows,設置線程安全if (HalconAPI.isWindows)HOperatorSet.SetSystem("use_window_thread", "true");HTuple hvDeviceInfo;HTuple hvDeviceInfoValues;// 獲取相機設備信息HOperatorSet.InfoFramegrabber("GigEVision2", "device", out hvDeviceInfo, out hvDeviceInfoValues);// 如果沒有設備信息,返回錯誤if (hvDeviceInfoValues.Length == 0){this.mLastErrorMsg = "獲取不到相機設備";return false;}// 檢查是否有兩個相機設備if (deviceQty == 2){if (hvDeviceInfoValues.Length < 2){this.mLastErrorMsg = "只檢測到了一個相機設備!";return false;}}// 打開第一個相機HOperatorSet.OpenFramegrabber("GigEVision2", 0, 0, 0, 0, 0, 0, "progressive",-1, "default", -1, "false", "default", hvDeviceInfoValues.TupleSelect(0), 0, -1, out mHvAcqHandle);// 設置相機參數HOperatorSet.SetFramegrabberParam(mHvAcqHandle, "grab_timeout", 2000);HOperatorSet.GrabImageStart(mHvAcqHandle, -1);// 打開第二個相機(如果有)if (deviceQty == 2){HOperatorSet.OpenFramegrabber("GigEVision2", 0, 0, 0, 0, 0, 0, "progressive",-1, "default", -1, "false", "default", hvDeviceInfoValues.TupleSelect(1), 0, -1, out mHvAcqHandle2);HOperatorSet.SetFramegrabberParam(mHvAcqHandle2, "grab_timeout", 2000);HOperatorSet.GrabImageStart(mHvAcqHandle2, -1);}// 關閉之前打開的窗口if (HDevWindowStack.IsOpen()){var hvWnd = HDevWindowStack.Pop();while (hvWnd != null){HOperatorSet.CloseWindow(hvWnd);}}// 打開顯示窗口并設置窗口句柄HOperatorSet.OpenWindow(0, 0, wndWidth, wndHeight, hHalconWnd, "visible", "", out this.mHvWindowHandle);HDevWindowStack.Push(mHvWindowHandle);return true;}public void CloseImageAcq(){// 清理相機和圖像資源if (HalconAPI.isWindows)HOperatorSet.SetSystem("use_window_thread", "true");if (this.mHoImage != null){this.mHoImage.Dispose();this.mHoImage = null;}if (this.mHvWindowHandle != null){this.mHvWindowHandle.Dispose();this.mHvWindowHandle = null;}if (this.mHvAcqHandle != null){HOperatorSet.CloseFramegrabber(this.mHvAcqHandle);this.mHvAcqHandle.Dispose();this.mHvAcqHandle = null;}if (mHoImage2 != null){this.mHoImage2.Dispose();this.mHoImage2 = null;}if (this.mHvWindowHandle2 != null){this.mHvWindowHandle2.Dispose();this.mHvWindowHandle2 = null;}if (this.mHvAcqHandle2 != null){HOperatorSet.CloseFramegrabber(this.mHvAcqHandle2);this.mHvAcqHandle2.Dispose();this.mHvAcqHandle2 = null;}}public string GetLastErrorMsg(){// 獲取最后的錯誤信息return this.mLastErrorMsg;}public void GrabImage(){// 異步捕獲圖像并顯示在窗口HObject hoImage;HTuple imageWidth;HTuple imageHeight;if (HalconAPI.isWindows)HOperatorSet.SetSystem("use_window_thread", "true");HOperatorSet.GrabImageAsync(out hoImage, mHvAcqHandle, -1);HOperatorSet.GetImageSize(hoImage, out imageWidth, out imageHeight);if (HDevWindowStack.IsOpen()){HTuple[] displayRect = GetDisplayRect(mWndWidth, mWndHeight, imageWidth, imageHeight);HOperatorSet.SetPart(HDevWindowStack.GetActive(), displayRect[0], displayRect[1], displayRect[2], displayRect[3]);}if (HDevWindowStack.IsOpen()){HOperatorSet.DispImage(hoImage, HDevWindowStack.GetActive());}if (hoImage != null){hoImage.Dispose();}if (imageWidth != null){imageWidth.Dispose();}if (imageHeight != null){imageHeight.Dispose();}}public void StartScanBarcode(int qty){// 執行條形碼掃描List<string> barcodeList = new List<string>();HObject hoImage;HObject hoObjectsConcat;HObject hoSymbolRegions;HTuple hvBarCodeHandle;HTuple imageWidth;HTuple imageHeight;HTuple hvWindowHandle;int wndWidth, wndHeight;if (qty == 1){// 如果是單臺相機,使用第一個相機窗口和尺寸wndWidth = this.mWndWidth;wndHeight = this.mWndHeight;hvWindowHandle = this.mHvWindowHandle;}else{// 如果是雙臺相機,使用第二個相機窗口和尺寸wndWidth = this.mWndWidth2;wndHeight = this.mWndHeight2;hvWindowHandle = this.mHvWindowHandle2;}HTuple hvDecodedDataStrings;// 創建空對象,用于存放圖像和檢測到的條形碼區域HOperatorSet.GenEmptyObj(out hoObjectsConcat);HOperatorSet.GenEmptyObj(out hoSymbolRegions);// 創建條形碼檢測模型,指定條形碼檢測的類型HOperatorSet.CreateBarCodeModel("quiet_zone", "true", out hvBarCodeHandle);// 設置條形碼檢測的參數HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "majority_voting", "true"); // 啟用多數投票HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "element_size_variable", "true"); // 啟用可變元素大小HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "start_stop_tolerance", "low"); // 設置開始/停止容差為低// 根據相機數量,選擇相應的相機進行圖像捕獲if (qty == 1){// 如果只有一臺相機,捕獲圖像HOperatorSet.GrabImageAsync(out hoImage, mHvAcqHandle, -1);}else{// 如果有兩臺相機,捕獲兩臺相機的圖像HOperatorSet.GrabImageAsync(out hoImage, mHvAcqHandle, -1);}// 獲取圖像的尺寸HOperatorSet.GetImageSize(hoImage, out imageWidth, out imageHeight);// 根據窗口尺寸和圖像尺寸,計算顯示區域if (HDevWindowStack.IsOpen()){HTuple[] displayRect = GetDisplayRect(wndWidth, wndHeight, imageWidth, imageHeight);HOperatorSet.SetPart(hvWindowHandle, displayRect[0], displayRect[1], displayRect[2], displayRect[3]);}// 顯示捕獲的圖像if (HDevWindowStack.IsOpen()){HOperatorSet.DispImage(hoImage, hvWindowHandle);}// 執行條形碼查找HOperatorSet.FindBarCode(hoImage, out hoSymbolRegions, hvBarCodeHandle,"Code 128", out hvDecodedDataStrings);// 顯示條形碼區域if (HDevWindowStack.IsOpen()){HOperatorSet.DispRegion(hoSymbolRegions, hvWindowHandle);}// 將找到的條形碼數據加入列表for (int i = 0; i < hvDecodedDataStrings.Length; i++){string item = hvDecodedDataStrings[i];barcodeList.Add(string.Copy(item));}// 釋放資源if (hoObjectsConcat != null){hoObjectsConcat.Dispose();}if (hoSymbolRegions != null){hoSymbolRegions.Dispose();}if (hvBarCodeHandle != null){hvBarCodeHandle.Dispose();}if (hoImage != null){hoImage.Dispose();}if (imageWidth != null){imageWidth.Dispose();}if (imageHeight != null){imageHeight.Dispose();}if (hvDecodedDataStrings != null){hvDecodedDataStrings.Dispose();}// 調用回調函數,將條形碼數據返回if (mCallback != null){mCallback.FoundBarcode(barcodeList);}}public void StartScanBarcodeBy2Device(bool revease){// 使用兩臺相機進行條形碼掃描List<string> barcodeList = new List<string>();HObject hoImage;HObject hoImage2;HObject hoImages;HObject hoObjectsConcat;HObject hoSymbolRegions;HTuple hvBarCodeHandle;HTuple imageWidth;HTuple imageHeight;HTuple hvWindowHandle;int wndWidth, wndHeight;// 設置第一個相機的窗口尺寸wndWidth = this.mWndWidth;wndHeight = this.mWndHeight;hvWindowHandle = this.mHvWindowHandle;HTuple hvDecodedDataStrings;// 創建空對象,用于存放圖像和檢測到的條形碼區域HOperatorSet.GenEmptyObj(out hoImage);HOperatorSet.GenEmptyObj(out hoImage2);HOperatorSet.GenEmptyObj(out hoImages);HOperatorSet.GenEmptyObj(out hoObjectsConcat);HOperatorSet.GenEmptyObj(out hoSymbolRegions);// 創建條形碼檢測模型HOperatorSet.CreateBarCodeModel("quiet_zone", "true", out hvBarCodeHandle);// 設置條形碼檢測的參數HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "majority_voting", "true");HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "element_size_variable", "true");HOperatorSet.SetBarCodeParam(hvBarCodeHandle, "start_stop_tolerance", "low");// 捕獲第一臺相機的圖像HOperatorSet.GrabImageAsync(out hoImage, mHvAcqHandle, -1);// 捕獲第二臺相機的圖像HOperatorSet.GrabImageAsync(out hoImage2, mHvAcqHandle2, -1);// 根據 `revease` 參數的值,決定圖像的拼接順序if (revease){HOperatorSet.ConcatObj(hoImages, hoImage2, out hoImages);HOperatorSet.ConcatObj(hoImages, hoImage, out hoImages);}else{HOperatorSet.ConcatObj(hoImages, hoImage, out hoImages);HOperatorSet.ConcatObj(hoImages, hoImage2, out hoImages);}// 將兩臺相機的圖像拼接在一起HOperatorSet.TileImages(hoImages, out hoObjectsConcat, 2, "horizontal");// 獲取拼接后的圖像尺寸HOperatorSet.GetImageSize(hoObjectsConcat, out imageWidth, out imageHeight);// 根據窗口尺寸和圖像尺寸,計算顯示區域if (HDevWindowStack.IsOpen()){HTuple[] displayRect = GetDisplayRect(wndWidth, wndHeight, imageWidth, imageHeight);HOperatorSet.SetPart(hvWindowHandle, displayRect[0], displayRect[1], displayRect[2], displayRect[3]);}// 顯示拼接后的圖像if (HDevWindowStack.IsOpen()){HOperatorSet.DispImage(hoObjectsConcat, hvWindowHandle);}// 執行條形碼查找HOperatorSet.FindBarCode(hoObjectsConcat, out hoSymbolRegions, hvBarCodeHandle,"Code 128", out hvDecodedDataStrings);// 顯示條形碼區域if (HDevWindowStack.IsOpen()){HOperatorSet.DispRegion(hoSymbolRegions, hvWindowHandle);}// 將找到的條形碼數據加入列表for (int i = 0; i < hvDecodedDataStrings.Length; i++){string item = hvDecodedDataStrings[i];barcodeList.Add(string.Copy(item));}// 釋放資源if (hoObjectsConcat != null){hoObjectsConcat.Dispose();}if (hoImages != null){hoImages.Dispose();}if (hoSymbolRegions != null){hoSymbolRegions.Dispose();}if (hvBarCodeHandle != null){hvBarCodeHandle.Dispose();}if (hoImage != null){hoImage.Dispose();}if (hoImage2 != null){hoImage2.Dispose();}if (imageWidth != null){imageWidth.Dispose();}if (imageHeight != null){imageHeight.Dispose();}if (hvDecodedDataStrings != null){hvDecodedDataStrings.Dispose();}// 調用回調函數,將條形碼數據返回if (mCallback != null){mCallback.FoundBarcode(barcodeList);}}/// <summary>/// 計算顯示區域的矩形,以適應圖像與窗口的大小比例/// </summary>/// <param name="wndWidth">窗口寬度</param>/// <param name="wndHeight">窗口高度</param>/// <param name="imageWidth">圖像寬度</param>/// <param/// <summary>/// 計算顯示區域的矩形,以適應圖像與窗口的大小比例/// </summary>/// <param name="wndWidth">窗口寬度</param>/// <param name="wndHeight">窗口高度</param>/// <param name="imageWidth">圖像寬度</param>/// <param name="imageHeight">圖像高度</param>/// <returns>顯示區域矩形</returns>private HTuple[] GetDisplayRect(int wndWidth, int wndHeight, int imageWidth, int imageHeight){// 計算圖像與窗口的寬高比例double widthRatio = (1.0) * imageWidth / wndWidth;double heightRatio = (1.0) * imageHeight / wndHeight;HTuple row1, colume1, row2, colume2;// 如果圖像的寬度比高度占優,則以寬度比例為主if (widthRatio >= heightRatio){row1 = -(1.0) * (wndHeight * widthRatio - imageHeight) / 2;colume1 = 0;row2 = row1 + wndHeight * widthRatio;colume2 = colume1 + wndWidth * widthRatio;}else{// 否則,以高度比例為主row1 = 0;colume1 = -(1.0) * (wndWidth * heightRatio - imageWidth) / 2;row2 = row1 + wndHeight * heightRatio;colume2 = colume1 + wndWidth * heightRatio;}// 返回顯示區域的四個坐標點(行列)return new HTuple[] { row1, colume1, row2, colume2 };}}
}