.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 的「解決方案資源管理員」中,以滑鼠右鍵點擊您的專案,然後選取「新增」>「專案參考」。
此時會開啟「參考管理員」視窗。 - 按下「瀏覽」按鈕。
- 請導航至%Program Files%\Basler\pylon 8\Development\Assemblies\Basler.Pylon\x64資料夾。
- 選取Basler.Pylon.dll,然後按一下「新增」按鈕。
- 按下「瀏覽」按鈕。
- 請導航至%Program Files%\Basler\pylon 8\Development\Assemblies\Basler.Pylon.Blaze\AnyCpu資料夾。
- 選取Basler.Pylon.Blaze.dll 檔案,然後按一下「新增」按鈕。
Basler.Pylon 組件的處理器架構
無論您選擇針對 32 位元平台還是 64 位元平台的組件,都無妨。由於這些組件已安裝在全域組件快取 (GAC) 中,.NET 組件載入器會自動選擇與您的應用程式所針對的架構相符的那個組件。
為避免在建置應用程式時出現有關潛在架構不符的警告,Basler 建議手動編輯 Visual Studio 專案檔案,以抑制此類警告。操作步驟如下:
- 在「解決方案資源管理員」中,右鍵點擊您的專案,然後選擇「卸載專案」。
- 再次右鍵點擊該專案,並選擇「編輯專案」。
專案的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> -
編輯完成後,請右鍵點擊專案並選擇「重新載入專案」來重新載入您的專案。
當系統提示時,請確認關閉專案檔案並儲存待處理的變更。
開啟與存取 blaze 相機#
pylon .NET API 提供一個單一的 Camera 適用於所有相機類型的類別。可透過重載的建構函式來選取特定的相機裝置。
建立並開啟 blaze 相機物件需要三個步驟:
-
為您想要存取的相機建立相機物件。
-
註冊一個適用於 Blaze 的參數設定,該設定會套用預設配置。有關 Blaze 設定事件處理常式類別的更多詳細資訊,請參閱「預定義相機參數設定」一節。
-
呼叫
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 該類別提供了一個建構子,可讓您傳入一組鍵值對清單,用以指定該相機物件所對應的相機裝置之屬性。
要開啟第一個可用的 Blaze 攝影機,只需指定裝置類型等同於 Blaze 裝置類別即可。
為特定的 blaze 相機建立相機物件#
如果您想要開啟特定的 blaze 相機(例如透過指定其序號),除了將 blaze 相機的 pylon 裝置類別識別碼傳遞至 CreateFirstDevice()之外,您還可以指定其他 Property。
以下程式碼片段示範了如何根據序號開啟 Blaze 攝影機。
若要透過使用者自訂名稱開啟 blaze 相機,請使用以下程式碼行:
使用者自訂名稱
您可以透過以下方式為相機指定使用者自訂名稱: DeviceUserID parameter。您可以在 blaze Viewer、pylon IP Configurator 或 pylon API 中執行此操作:
透過 IP 位址建立裝置
目前,您無法透過指定裝置的 IP 位址來建立該裝置。
若要建立並開啟具有特定 IP 位址的攝影機,您必須先枚舉所有攝影機,遍歷回傳的清單,並依序開啟每台攝影機,才能查詢其 IP 位址及其他網路相關資訊。
如果找不到所需的 blaze 相機,請檢查您是否使用了正確的 Property 值,並檢查相機和網路介面卡的 IP 組態設定。如需有關設定網路的詳細資訊,請參閱網路組態主題。
預設的相機參數設定#
關於 Blaze 攝影機,有以下 BlazeConfigurations 類別。此類別的方法可新增至 CameraOpened 事件。這必須在開啟相機之前,透過呼叫 Open() 方法。當相機開啟時,系統會自動呼叫此設定方法,並據此變更相機的設定。
範例:
當 BlazeConfigurations 提供以下配置方法:
AcquirePointCloudsContinuously
持續擷取數據。深度數據以點雲的形式呈現。AcquireDepthMapsContinuously
持續擷取資料。深度資料以深度圖的形式呈現。
如欲進一步了解 pylon 的配置事件處理常式,請參閱《pylon .NET 程式設計師指南》中的「預定義相機參數配置」一節。
解讀深度資料#
「處理測量結果」主題提供有關儲存於「測距」資料元件中的深度資料格式之相關資訊。
連接至相機#
建立相機物件並註冊組態事件處理常式後,會透過呼叫 CBlazeInstantCamera::Open() 方法後的任何時間設定要變更的參數。
連線會保持開啟,直到呼叫 CBlazeInstantCamera::Close() 方法被呼叫。該物件的析構函式 Camera 類別呼叫 Close() 若未明確呼叫該方法,系統將自動執行。若要明確控制相機物件的生命週期,Basler 建議如上方的程式碼片段所示,將相機物件置於 using 語句之中。
如果相機未定期收到來自相機的心跳要求,相機將會關閉連線。若應用程式當機或被偵錯工具中斷,就會發生遺漏心跳要求的情況。如需更多詳細資料,請參閱偵錯應用程式與控制 GigE Vision 心跳一節。
存取參數#
請參閱《pylon .NET 程式設計師指南》中的「參數存取」章節,以熟悉如何使用 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 程式設計師指南》中的「擷取影像」章節,以熟悉如何使用 pylon .NET API 擷取資料。
pylon 將擷取的影像表示為稱為 GrabResults 的資料結構。由 2D 相機擷取的 GrabResults 包含單一灰階或彩色影像。
由 blaze 相機擷取的 GrabResults 包含多個元件。預設情況下,每個 GrabResult 會儲存強度影像、信心圖與深度資訊。
根據「Range」元件所設定的像素格式,深度資料可呈現為 2D 深度圖或 3D 點雲。
擷取迴圈#
pylon 支援設定擷取迴圈的不同方法,並提供用於處理記憶體緩衝區的不同策略。
更多詳細資訊,請參閱《pylon .NET 程式設計師指南》中的「擷取影像」一節。
以下程式碼範例展示了一個典型的擷取迴圈:
// 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 程式設計師指南》中的「多元件 Grab 結果」一節。
範例:
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
解讀深度資料#
「處理測量結果」主題提供有關儲存於「測距」資料元件中的深度資料格式之相關資訊。
偵錯應用程式與控制 GigE Vision Heartbeat#
使用 pylon 7.0 或更低版本時的重新連線問題
如果在應用程式正確關閉與相機的連線之前終止或當機,相機將保持連線開啟,直到心跳逾時。在心跳逾時之前,相機會拒絕任何進一步的連線嘗試。當重新啟動應用程式或啟動另一個請求存取相機的應用程式時,您將收到一條錯誤訊息,指出裝置目前正在使用中。
這通常發生在您使用偵錯工具停止應用程式,或您的應用程式異常終止時。若要再次開啟相機,您必須等待逾時時間過期,或暫時將相機從網路中斷連線。
若要解決此問題,當應用程式在偵錯工具的控制下執行時,您可以透過將名為以下名稱的環境變數設為所需的逾時時間(以毫秒為單位),來覆寫心跳逾時的自動調整: GEV_HEARTBEAT_TIMEOUT 或者,您可以使用 pylon API 在應用程式中設定心跳逾時,如 DeviceRemovalCSharp 進行明確的生命週期管理即呼叫 DeviceRemovalVB 範例程式。