.NET程式設計人員指南#
如果您是pylon的新手,Basler建議您先閱讀 pylon .NET程式設計人員指南,以熟悉pylon .NET API。
.NET程式設計範例#
若要開啟包含blaze相機程式設計範例的資料夾,請按下 Win 鍵,前往 Basler 資料夾,然後選擇 blaze Samples。隨即會開啟「檔案總管」視窗。.NET程式設計範例位於 DotNet 資料夾中。
如何建置範例#
資訊
在建置範例之前,請將包含範例的資料夾複製到您具有讀寫權限的任意位置。
範例提供Visual Studio解決方案與專案檔案。您可以使用Visual Studio 2017或更新版本開啟解決方案並建置範例。
如何建置.NET應用程式#
若要使用C#或Visual Basic .NET操作Basler blaze相機,您必須將 Basler.Pylon 和 Basler.Pylon.Blaze 組件新增至專案的組件參考清單中。
若要新增組件:
- 在Visual Studio「方案總管」中以滑鼠右鍵按一下您的專案,然後選取 Add > Project Reference。
隨即會開啟 Reference Manager 視窗。 - 按一下 Browse 按鈕。
- 瀏覽至 %Program Files%\Basler\pylon 8\Development\Assemblies\Basler.Pylon\x64 資料夾。
- 選取 Basler.Pylon.dll,然後按一下 Add 按鈕。
- 按一下 Browse 按鈕。
- 瀏覽至 %Program Files%\Basler\pylon 8\Development\Assemblies\Basler.Pylon.Blaze\AnyCpu 資料夾。
- 選擇 Basler.Pylon.Blaze.dll,然後按一下 Add 按鈕。
Basler.Pylon 組件的處理器架構
選擇針對 32 位元還是 64 位元平台的組件並不重要。由於組件已安裝在全域組件快取 (GAC) 中,.NET 組件載入器將自動選擇與您的應用程式建置架構相符的組件。
為了在建置應用程式時避免關於潛在架構不相容的警告,Basler 建議手動編輯 Visual Studio 專案檔案以隱藏這些警告。請遵循以下步驟:
- 在「方案總管」中,以滑鼠右鍵按一下您的專案,然後選擇 Unload project。
- 再次以滑鼠右鍵按一下專案,然後選擇 Edit project。
專案的 XML 檔案隨即會在編輯器視窗中開啟。 -
在 XML 檔案中,導覽至參考
Basler.Pylon組件的位置,亦即搜尋類似下列的片段: -
在
ItemGroup元素上方,新增下列 XML 片段:<PropertyGroup> <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch> </PropertyGroup>新增元素之後,您的專案檔案應包含類似這樣的片段:
<PropertyGroup> <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch> </PropertyGroup> <ItemGroup> .... <Reference Include="Basler.Pylon"> <HintPath>..\..\..\..\..\..\Program Files\Basler\pylon\Development\Assemblies\Basler.Pylon\x64\Basler.Pylon.dll</HintPath> </Reference> <Reference Include="Basler.Pylon.Blaze"> <HintPath>..\..\..\..\..\..\Program Files\Basler\pylon\Development\Assemblies\Basler.Pylon.Blaze\AnyCpu\Basler.Pylon.Blaze.dll</HintPath> </Reference> .... </ItemGroup> -
完成編輯後,以滑鼠右鍵按一下專案並選擇 Reload project 以重新載入專案。
當系統詢問時,確認關閉專案檔案並儲存未完成的變更。
開啟並存取blaze相機#
pylon .NET API 針對所有相機類型提供單一 Camera 類別。您可以使用多載建構函式來選取特定的相機裝置。
建立並開啟 blaze 相機物件需要三個步驟:
-
為您要存取的相機建立相機物件。
-
註冊套用預設組態的 blaze 專屬參數組態。如需 blaze 組態事件處理常式類別的詳細資訊,請參閱 Predefined Camera Parameter Configurations 一節。
-
在您的應用程式中呼叫
Open()方法來建立與相機裝置的連線。
以下範例說明這三個步驟:
using Basler.Pylon;
using Basler.Pylon.Blaze;
// ...
var filter = new Dictionary<string, string> {
{ CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass }
};
using (var camera = new Camera(filter, CameraSelectionStrategy.FirstFound))
{
// Set up the camera for continuously grabbing point clouds.
camera.CameraOpened += BlazeConfigurations.AcquirePointCloudsContinuously;
// Open the connection to the camera device.
camera.Open();
// Use the camera.
// Close the connection.
camera.Close();
}
Imports Basler.Pylon
Imports Basler.Pylon.Blaze
' ...
Dim filter = New Dictionary(Of String, String) From {
{CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass}
}
Using camera = New Camera(filter, CameraSelectionStrategy.FirstFound)
' Set up the camera for continuously grabbing point clouds.
AddHandler camera.CameraOpened,
AddressOf BlazeConfigurations.AcquirePointCloudsContinuously
' Open the connection to the camera device.
camera.Open()
' Use the camera.
' Close the connection.
camera.Close()
End Using
為第一個可用的blaze相機建立相機物件#
影像 Camera 類別提供建構函式,允許您傳入鍵值對清單,以指定為其建立相機物件之相機裝置的 Property。
若要開啟第一個可用的 blaze 相機,只需指定裝置類型等於 blaze 裝置類別即可。
為特定的blaze相機建立相機物件#
如果您想要開啟特定的 blaze 相機(例如透過指定其序號),除了將 blaze 相機的 pylon 裝置類別識別碼傳遞至 CreateFirstDevice()之外,您還可以指定其他 Property。
以下程式碼片段說明如何透過序號開啟 blaze 相機。
若要透過使用者定義名稱開啟 blaze 相機,請使用下列程式碼行:
User-Defined Names
您可以使用 DeviceUserID 參數將使用者定義名稱指派給相機。您可以在 blaze Viewer、pylon IP Configurator 或 pylon API 中執行此操作:
透過 IP 地址建立裝置
目前,您無法透過指定裝置的 IP 地址來建立裝置。
如果您想要建立並開啟具有特定 IP 地址的相機,必須先列舉所有相機、走訪傳回的清單,並在查詢 IP 地址及其他網路相關資訊之前開啟每台相機。
如果找不到所需的 blaze 相機,請檢查您是否使用了正確的 Property 值,並檢查相機與網路介面卡的 IP 設定。如需有關設定網路的詳細資訊,請參閱網路組態主題。
預先定義的相機Property設定#
對於 blaze 相機,有 BlazeConfigurations 類別。此類別的方法可以新增至 CameraOpened 事件。這必須在呼叫 Open() 方法來開啟相機之前完成。當相機開啟時,會自動呼叫組態方法並相應地變更相機組態。
範例:
影像 BlazeConfigurations 提供以下組態方法:
AcquirePointCloudsContinuously
持續擷取資料。深度資料以點雲形式表示。AcquireDepthMapsContinuously
持續擷取資料. 深度資料以深度圖形式表示。
請參閱 pylon .NET Programmer's Guide 中的Predefined Camera Parameter Configurations章節,以深入了解 pylon 的組態事件處理常式。
解讀深度資料#
Processing Measurement Results主題提供了關於儲存在 Range 資料元件中的深度資料格式的資訊。
連接至相機#
建立相機物件並註冊組態事件處理常式後,透過呼叫 CBlazeInstantCamera::Open() 方法來建立與相機的連線。
連線會保持作用中,直到呼叫 CBlazeInstantCamera::Close() 方法的 Camera 類別會自動呼叫 Close() (如果尚未明確呼叫)。為了明確控制相機物件的生命週期,Basler 建議如上方程式碼片段所示,在 using 陳述式內使用相機物件。
如果相機未定期收到來自相機的心跳要求,相機將會關閉連線。如果應用程式當機或遭到偵錯工具中斷,就會發生遺漏心跳要求的情況。如需更多詳細資訊,請參閱Debugging Applications and Controlling the GigE Vision Heartbeat章節。
存取Property#
請參閱 pylon .NET Programmer's Guide 中的Parameter Access章節,以熟悉如何使用 pylon .NET API 存取相機參數。
pylon .NET API 提供參數清單作為存取相機參數的便利方法,並在 Visual Studio 的 IntelliSense 輔助下進行。
對於 blaze 相機,有 PLBlaze 參數清單。
以下程式碼片段示範如何使用 PLBlaze 參數清單。
// Set the operating mode of the camera. The choice you make here
// affects the working range of the camera, i.e., the Minimum Working
// Range and Maximum Working Range parameters.
var oldOperatingMode = camera.Parameters[PLBlaze.OperatingMode].GetValue();
camera.Parameters[PLBlaze.OperatingMode].SetValue(PLBlaze.OperatingMode.LongRange);
// Exposure time of the camera. If the operating mode is changed, the
// exposure time is set to the recommended default value.
camera.Parameters[PLBlaze.ExposureTime].SetValue(750); // us
// Enable and configure image filtering.
// The spatial noise filter uses the values of neighboring pixels to
// filter out noise in an image.
camera.Parameters[PLBlaze.SpatialFilter].SetValue(true);
// The temporal noise filter uses the values of the same pixel at
// different points in time to filter out noise in an image.
camera.Parameters[PLBlaze.TemporalFilter].SetValue(true);
camera.Parameters[PLBlaze.TemporalFilterStrength].SetValue(220);
// The outlier removal removes pixels that differ significantly from
// their local environment.
camera.Parameters[PLBlaze.OutlierRemoval].SetValue(true);
// Some properties have restrictions.
// We use API functions that automatically perform value corrections.
// Alternatively, you can use GetInc() / GetMin() / GetMax() to make sure you
// set a valid value.
camera.Parameters[PLBlaze.ConfidenceThreshold].SetValue(
321,
IntegerValueCorrection.Nearest
);
// Not all functions are available in older cameras.
// Therefore, we must use "Try" functions that only perform the action
// when parameters are writable. Otherwise, we would get an exception.
camera.Parameters[PLBlaze.MultiCameraChannel].TrySetValue(1);
Console.WriteLine("Operating Mode : {0}",
camera.Parameters[PLBlaze.OperatingMode].GetValue());
Console.WriteLine("Exposure Time : {0}",
camera.Parameters[PLBlaze.ExposureTime].GetValue());
Console.WriteLine("Spatial Filter : {0}",
camera.Parameters[PLBlaze.SpatialFilter].GetValue());
Console.WriteLine("Temporal Filter : {0}",
camera.Parameters[PLBlaze.TemporalFilter].GetValue());
Console.WriteLine("Temporal Filter Strength : {0}",
camera.Parameters[PLBlaze.TemporalFilterStrength].GetValue());
Console.WriteLine("Outlier Removal : {0}",
camera.Parameters[PLBlaze.OutlierRemoval].GetValue());
Console.WriteLine("Confidence Threshold : {0}",
camera.Parameters[PLBlaze.ConfidenceThreshold].GetValue());
if (camera.Parameters[PLBlaze.MultiCameraChannel].IsReadable)
{
Console.WriteLine("Multi-Camera Channel : {0}",
camera.Parameters[PLBlaze.MultiCameraChannel].GetValue());
}
// Restore the old operating mode.
camera.Parameters[PLBlaze.OperatingMode].SetValue(oldOperatingMode);
' Set the operating mode of the camera. The choice you make here
' affects the working range of the camera, i.e., the Minimum Working
' Range and Maximum Working Range parameters.
Dim oldOperatingMode = camera.Parameters(PLBlaze.OperatingMode).GetValue()
camera.Parameters(PLBlaze.OperatingMode).SetValue(PLBlaze.OperatingMode.LongRange)
' Exposure time of the camera. If the operating mode is changed, the
' exposure time is set to the recommended default value
camera.Parameters(PLBlaze.ExposureTime).SetValue(750) ' us
' Enable and configure image filtering.
' The spatial noise filter uses the values of neighboring pixels to
' filter out noise in an image.
camera.Parameters(PLBlaze.SpatialFilter).SetValue(True)
' The temporal noise filter uses the values of the same pixel at
' different points in time to filter out noise in an image.
camera.Parameters(PLBlaze.TemporalFilter).SetValue(True)
camera.Parameters(PLBlaze.TemporalFilterStrength).SetValue(220)
' The outlier removal removes pixels that differ significantly from
' their local environment
camera.Parameters(PLBlaze.OutlierRemoval).SetValue(True)
' Some properties have restrictions.
' We use API functions that automatically perform value corrections.
' Alternatively, you can use GetInc() / GetMin() / GetMax() to make sure you set
' a valid value.
camera.Parameters(PLBlaze.ConfidenceThreshold).SetValue(
321,
IntegerValueCorrection.Nearest
)
' Not all functions are available in older cameras.
' Therefore, we must use "Try" functions that only perform the action
' when parameters are writable. Otherwise, we would get an exception.
camera.Parameters(PLBlaze.MultiCameraChannel).TrySetValue(1)
Console.WriteLine("Operating Mode : {0}",
camera.Parameters(PLBlaze.OperatingMode).GetValue())
Console.WriteLine("Exposure Time : {0}",
camera.Parameters(PLBlaze.ExposureTime).GetValue())
Console.WriteLine("Spatial Filter : {0}",
camera.Parameters(PLBlaze.SpatialFilter).GetValue())
Console.WriteLine("Temporal Filter : {0}",
camera.Parameters(PLBlaze.TemporalFilter).GetValue())
Console.WriteLine("Temporal Filter Strength : {0}",
camera.Parameters(PLBlaze.TemporalFilterStrength).GetValue())
Console.WriteLine("Outlier Removal : {0}",
camera.Parameters(PLBlaze.OutlierRemoval).GetValue())
Console.WriteLine("Confidence Threshold : {0}",
camera.Parameters(PLBlaze.ConfidenceThreshold).GetValue())
If camera.Parameters(PLBlaze.MultiCameraChannel).IsReadable Then
Console.WriteLine("Multi-Camera Channel : {0}",
camera.Parameters(PLBlaze.MultiCameraChannel).GetValue())
End If
' Restore the old operating mode.
camera.Parameters(PLBlaze.OperatingMode).SetValue(oldOperatingMode)
擷取資料#
請參閱 pylon .NET Programmer's Guide 中的Grabbing Images章節,以熟悉如何使用 pylon .NET API 擷取資料。
pylon 會將擷取的影像表示為稱為 GrabResults 的資料結構。由 2D 相機擷取的 GrabResults 包含單一灰階或彩色影像。
由 blaze 相機擷取的 GrabResults 包含多個元件。預設情況下,每個 GrabResult 都會儲存強度影像、信心圖和深度資訊。
根據為 Range 元件設定的 Pixel Format,深度資料可以表示為 2D 深度圖或 3D 點雲。
擷取迴圈#
pylon 支援用於設定擷取迴圈的不同方法,並提供用於處理 Memory 緩衝區的不同策略。
如需更多詳細資料,請參閱 pylon .NET Programmer's Guide 的 Grabbing Images 節。
下列程式碼範例說明了典型的擷取迴圈:
// Open the connection to the camera device.
camera.Open();
// The MaxNumBuffer parameter can be used to control the amount of buffers
// allocated for grabbing. The default value of this parameter is 10.
camera.Parameters[PLCameraInstance.MaxNumBuffer].SetValue(3);
// Start grabbing.
camera.StreamGrabber.Start();
// Grab a number of images.
for (int i = 0; i < 10; ++i)
{
// Wait for an image and then retrieve it. A timeout of 1000 ms is used.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(
1000,
TimeoutHandling.ThrowException
);
using (grabResult) // Make sure that the grab buffers are reused for
// grabbing as soon we run out of scope.
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Access the data.
// ....
}
else
{
Console.WriteLine("Error: {0} {1}",
grabResult.ErrorCode, grabResult.ErrorDescription);
}
}
}
// Stop grabbing.
camera.StreamGrabber.Stop();
' Open the connection to the camera device.
camera.Open()
' The MaxNumBuffer parameter can be used to control the amount of buffers
' allocated for grabbing. The default value of this parameter is 10.
camera.Parameters(PLCameraInstance.MaxNumBuffer).SetValue(3)
' Start grabbing.
camera.StreamGrabber.Start()
' Grab a number of images.
For i As Integer = 0 To 10 - 1
' Wait for an image and then retrieve it. A timeout of 1000 ms is used.
Dim grabResult As IGrabResult = camera.StreamGrabber.RetrieveResult(
1000,
TimeoutHandling.ThrowException
)
Using grabResult
' Image grabbed successfully?
If grabResult.GrabSucceeded Then
' Access the data.
' ....
Else
Console.WriteLine("Error: {0} {1}",
grabResult.ErrorCode,
grabResult.ErrorDescription)
End If
End Using
Next
' Stop grabbing.
camera.StreamGrabber.Stop()
存取元件#
若要存取 GrabResult 的個別元件,您可以使用 IDataContainer 和 IDataComponent 類別。容器可以容納一個或多個元件。您可以使用容器來查詢元件數量並擷取特定元件。容器中的每個元件都包含實際資料(例如深度值)以及其中繼資料。
請使用 IGrabResult::GetDataContainer() 方法以存取 GrabResult 的 IDataContainer.
如需關於 pylon 如何提供對包含多個元件之 GrabResults 的存取的更多資訊,請參閱 pylon .NET Programmer's Guide 的 Multi-Component Grab Results 節。
範例:
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(
1000,
TimeoutHandling.ThrowException
);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Access the components.
// The container and the components should always be used in combination
// with using statements. This ensures that the underlying grab buffers
// are reused for grabbing new data as soon as the variables go out
// of scope. Omitting the using statements and relying on the garbage
// collector instead will cause buffer underruns resulting in missed data.
using (var container = grabResult.Container)
using (var rangeComponent = container[0])
using (var intensityComponent = container[1])
using (var confidenceComponent = container[2])
{
var pointCloudData = rangeComponent.PixelData as float[];
var intensityData = intensityComponent.PixelData as UInt16[];
var confidenceData = confidenceComponent.PixelData as UInt16[];
// Access the center pixel.
var u = (uint)(rangeComponent.Width / 2);
var v = (uint)(rangeComponent.Height / 2);
var idx = v * rangeComponent.Width + u;
var intensity = intensityData[idx];
var confidence = confidenceData[idx];
// There is a triple (x,y,z) of floats per pixel.
var x = pointCloudData[3 * idx];
var y = pointCloudData[3 * idx + 1];
var z = pointCloudData[3 * idx + 2];
if (confidence != 0) // Alternatively: if (z != 0)
{
// Valid depth data
Console.WriteLine("x={0}, y={1}, z={2}, intensity={3}, confidence = {4}",
x, y, z, intensity, confidence);
}
else
{
Console.WriteLine("No depth data available for pixel ({0},{1}), intensity={2}",
u, v, intensity);
}
}
else
{
Console.WriteLine("Error: {0} {1}",
grabResult.ErrorCode, grabResult.ErrorDescription);
}
}
Dim grabResult As IGrabResult =
camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException)
Using grabResult
' Image grabbed successfully?
If grabResult.GrabSucceeded Then
' Access the components.
' The container and the components should always be used in combination with
' using statements. This ensures that the underlying grab buffers are reused
' for grabbing new data as soon as the variables go out of scope.
' Omitting the using statements and relying on the garbage collector instead
' will cause buffer underruns resulting in missed data.
Using container = grabResult.Container,
rangeComponent = container(0),
intensityComponent = container(1),
confidenceComponent = container(2)
Dim pointCloudData = TryCast(rangeComponent.PixelData, Single())
Dim intensityData = TryCast(intensityComponent.PixelData, UInt16())
Dim confidenceData = TryCast(confidenceComponent.PixelData, UInt16())
' Access the center pixel.
Dim u = CUInt((rangeComponent.Width / 2))
Dim v = CUInt((rangeComponent.Height / 2))
Dim idx = v * rangeComponent.Width + u
Dim intensity = intensityData(idx)
Dim confidence = confidenceData(idx)
Dim x = pointCloudData(3 * idx)
Dim y = pointCloudData(3 * idx + 1)
Dim z = pointCloudData(3 * idx + 2)
If confidence <> 0 Then ' Alternatively: if (z != 0)
' Valid depth data
Console.WriteLine("x={0}, y={1}, z={2}, intensity={3}, confidence = {4}",
x, y, z, intensity, confidence)
Else
Console.WriteLine("No depth data available for pixel ({0},{1}), intensity={2}",
u, v, intensity)
End If
End Using
Else
Console.WriteLine("Error: {0} {1}", grabResult.ErrorCode,
grabResult.ErrorDescription)
End If
End Using
解讀深度資料#
Processing Measurement Results主題提供了關於儲存在 Range 資料元件中的深度資料格式的資訊。
偵錯應用程式與控制GigE Vision心跳訊號#
使用 pylon 7.0 或更舊版本時的重新連線問題
如果應用程式在正常關閉與相機的連線之前終止或當機,相機會保持連線開啟,直到心跳逾時(heartbeat timeout)到期為止。在心跳逾時到期之前,相機會拒絕任何進一步的連線嘗試。當重新啟動您的應用程式或啟動另一個要求存取相機的應用程式時,您將收到一則指出裝置目前正在使用的錯誤。
如果您使用偵錯工具停止應用程式,或者如果您的應用程式非預期地終止,通常會發生這種情況。若要再次開啟相機,您必須等待逾時經過,或者暫時將相機從網路中斷連線。
為了因應這種情況,當應用程式在偵錯工具的控制下執行時,您可以透過將名為 GEV_HEARTBEAT_TIMEOUT 的環境變數設定為所需的毫秒逾時時間,來覆寫心跳逾時的自動調整。或者,您可以使用 pylon API 在應用程式中設定心跳逾時,如 DeviceRemovalCSharp 和 DeviceRemovalVB 範例程式所示。