跳至內容
測試伺服器
開發伺服器

處理測量結果#

本主題將說明如何處理Basler blaze 及 Smart blaze攝影機的測量結果。

資訊

本主題中的所有資訊均適用於所有 blaze 與 Smart blaze 相機型號。為求簡潔,文中以 "blaze" 統稱所有型號。

總覽#

Basler Blaze 攝影機會測量光線在每個感測器像素上行進的距離。

根據這些距離,相機會針對每個感測器像素,在右手座標系中計算出 x、y、z 座標。該座標系的原點位於相機的光學中心,該點位於相機機身內部。y 軸朝下,z 軸則遠離相機。

相機會根據所選的像素格式,以深度圖或點雲的形式提供 3D 資訊。在深度圖中,z 座標以 16 位元灰階值編碼。如下圖所示,所有 3D 座標值均可從灰階值中計算得出。點雲則以浮點數形式包含每個感測器像素的 x、y、z 3D 座標,單位為毫米。

如果某個感測器像素沒有有效的深度資訊(例如,由於 異常值剔除 或光線不足,亦即光線不夠強,無法通過 置信閾值),深度圖或點雲中的對應值將被設定為由 Scan3dInvalidDataValue 參數(預設值為 0)。

深度圖的處理#

深度圖由 16 位元灰階值組成。對於每個感測器像素,相機會將 z 座標值轉換為灰階值,並將其儲存於深度圖中。

結合由 Scan3dCoordinateScale, Scan3dPrincipalPointU, Scan3dPrincipalPointV以及 Scan3dFocalLength 透過這些參數,可從深度圖中擷取完整的 3D 資訊。

資訊

當 Scan3dCoordinateScale 參數值會根據所選的像素格式而有所不同。在 Blaze Viewer 中使用相機時,像素格式總是設定為 Coord3D_ABC32f 像素格式。您無法變更此設定。Blaze Viewer 提供的深度圖是根據點雲所建立的。該 Scan3dCoordinateScale 在此情況下,參數值為 1。當您在pylon Viewer 之外使用 Blaze 攝影機,並將像素格式設定為 Coord3D_C16, Scan3dCoordinateScale 參數值不同。該 Scan3dCoordinateScale 以下表格列出了各種像素格式的參數值。

Pixel Format Scan3dCoordinateScale[C] 參數值
Coord3D_ABC32f 1
Coord3D_C16 0.152588
Mono16 0.152588

請參閱GrabDepthMapC++ 範例,了解如何設定相機以傳送深度圖,以及如何存取深度圖資料。

根據 2D 深度圖計算 3D 座標#

若要將深度圖的 16 位元灰階值轉換為以毫米為單位的 z 座標,請使用以下公式:

z [mm] = gray2mm * g

其中:

g = 深度圖中的灰階值

gray2mm = 的值 Scan3dCoordinateScale 參數

要計算 x 和 y 座標時,請使用以下公式:

x [mm] = (u-cx) * z / f

y [mm] = (v-cy) * z / f

其中:

(u,v) = 深度圖中的列與行

f = 的值 Scan3dFocalLength 參數,即相機鏡頭的焦距

(cx,cy) = 的值 Scan3dPrincipalPointU 進行明確的生命週期管理即呼叫 Scan3dPrincipalPointV 參數,即主點

C++ 範例程式碼#

    // Enable depth maps by enabling the Range component and setting the appropriate pixel format.
    camera.ComponentSelector.SetValue(ComponentSelector_Range);
    camera.ComponentEnable.SetValue(true);
    camera.PixelFormat.SetValue(PixelFormat_Coord3D_C16);

    // Query the conversion factor required to convert gray values to distances:
    // Choose the z axis first...
    camera.Scan3dCoordinateSelector.SetValue(Scan3dCoordinateSelector_CoordinateC);
    // ... then retrieve the conversion factor.
    const auto gray2mm = camera.Scan3dCoordinateScale.GetValue();

    // Configure the gray value used for indicating missing depth data.
    // Note: Before setting the value, the Scan3dCoordinateSelector parameter must be set to the axis the
    // value is to be configured for, in this case the z axis. This means that Scan3dCoordianteSelector must be set
    // to "CoordinateC". This has already been done a few lines above.
    camera.Scan3dInvalidDataValue.SetValue((double)missingDepth);

    // Retrieve calibration data from the camera.
    const auto cx = camera.Scan3dPrincipalPointU.GetValue();
    const auto cy = camera.Scan3dPrincipalPointV.GetValue();
    const auto f = camera.Scan3dFocalLength.GetValue();

    // ....

    // Access the data.
    const auto container = ptrGrabResult->GetDataContainer();
    const auto rangeComponent = container.GetDataComponent(0);
    const auto width = rangeComponent.GetWidth();
    const auto height = rangeComponent.GetHeight();

    // Calculate coordinates for pixel (u,v).
    const uint16_t g = ((uint16_t*)rangeComponent.GetData())[u + v * width];
    const double z = g * gray2mm;
    const double x = (u - cx) * z / f;
    const double y = (v - cy) * z / f;

處理已儲存的深度圖#

對於使用 blaze Legacy SDK、pylon SDK 或 blaze ROS 驅動程式所取得的深度圖,您必須使用以下公式:

測量距離 [mm] = 像素值 × Scan3dCoordinateScale[C]

對於使用 Blaze Viewer 儲存的深度圖,請使用以下公式:

測量距離 [mm] = 最小深度參數 + (像素值 × (最大深度參數 - 最小深度參數)) / 65535

點雲處理#

由於點雲由相機座標系內的 x、y、z 座標三元組所構成,因此無需進行進一步處理即可從點雲中萃取 3D 資訊。

請參閱FirstSampleC++ 範例,了解如何設定相機以傳送點雲,以及如何存取資料。

若您除了點雲之外還需要深度圖,請參閱ConvertPointCloud2DepthMapC++ 範例,該範例說明了如何從點雲計算灰階與 RGB 深度圖。

將座標系原點移至相機外殼前方#

相機座標系的原點位於相機光學中心,該點位於相機機身內部。若您希望採用以相機機身前端為原點的座標系(即沿 z 軸平移的座標系),則必須從 z 座標中減去一個恆定的、特定於該裝置的偏移量。所需的偏移量可透過從相機取得 ZOffsetOriginToCameraFront 參數:

const double offset = camera.ZOffsetOriginToCameraFront.GetValue();

若 (x, y, z) 為相機座標系中某點的座標,則可透過以下公式,求得在沿 z 軸向相機外殼前方平移的座標系中,該點的對應座標 (x', y', z'):

x' = x

y' = y

z' = z - 偏移量

距離的計算#

已知某一點的座標 (x,y,z) 以毫米為單位,該點到相機光學中心的距離可透過以下公式計算:

d = √(xx + yy+ z*z )

距離 d' 至相機機身前端的距離可按以下方式計算:

z' = z - 偏移量

d' = √(xx + yy+ z'*z')

將深度資訊視覺化為 RGB 影像#

您可以透過以下方案,根據 z 座標或距離值計算 RGB 值,以進行彩虹色映射。此方法有助於提升資料的可視化效果。

首先,來自 [minDepth..maxDepth] 值範圍會轉換為 10 位元的值。此 10 位元的色深值會映射至 4 個色彩範圍,每個範圍的分辨率為 8 位元。

minDepth 進行明確的生命週期管理即呼叫 maxDepth = 的值 DepthMin 進行明確的生命週期管理即呼叫 DepthMax 參數,即相機當前的深度 ROI

深度值 映射至「色彩範圍」
0..255 將紅色轉為黃色
(255,0,0) -> (255,255,0)
256..511 黃色轉為綠色
(255,255,0) -> (0, 255, 0)
512..767 從綠色轉為水藍色
(0,255,0) -> (0,255,255)
768..1023 從水藍色轉為藍色
(0,255,255) -> (0, 0, 255)

在以下程式碼片段中, depth 此數值為 Z 值或以毫米為單位的距離值。

const int minDepth = (int)m_camera.DepthMin.GetValue();
const int maxDepth = (int)m_camera.DepthMax.GetValue();

const double scale = 65536.0 / (maxDepth - minDepth);

for each pixel {
    // Set depth either to the corresponding z value or
    // a distance value calculated from the z value.
    // Clip depth if required.
    if (depth < minDepth)
        depth = minDepth;
    else if (depth > maxDepth)
        depth = maxDepth;
    // Compute RGB values.
    const uint16_t g = (uint16_t)((depth - minDepth) * scale);
    const uint16_t val = g >> 6 & 0xff;
    const uint16_t sel = g >> 14;
    uint32_t res = val << 8 | 0xff;
    if (sel & 0x01)
    {
        res = (~res) >> 8 & 0xffff;
    }
    if (sel & 0x02)
    {
        res = res << 8;
    }
    const uint8_t r = res & 0xff;
    res = res >> 8;
    const uint8_t g = res & 0xff;
    res = res >> 8;
    const uint8_t b = res & 0xff;
}