コンテンツにスキップ

測定結果を処理しています#

このトピックでは、Basler blaze-101カメラの測定結果を処理する方法について説明します。

概要#

blaze-101カメラは各センサーのピクセルのためにライトが移動する間隔を測定します。

Using these distances, the camera calculates x,y,z coordinates in a right-handed coordinate system for each sensor pixel. The coordinate system's origin is at the camera's optical center, which is located inside the camera housing. The y axis is pointing down, and the z axis is pointing away from the camera.

The camera provides 3D information either as a depth map or as a point cloud. In a depth map, z coordinates are encoded as 16-bit gray values. As illustrated below, all 3D coordinate values can be calculated from the gray values. A point cloud contains the x,y,z 3D coordinates for each sensor pixel as floating point numbers. The unit is mm.

If there is no valid depth information for a sensor pixel (e.g., due to outlier removal or insufficient light, i.e., light that is not strong enough to pass the confidence threshold), the corresponding values in a depth map or a point cloud are set to the value that is defined by the Scan3dInvalidDataValue parameter (default setting is 0).

深度マップの処理#

深度マップは16ビットグレー値で構成されます。各センサーピクセルについては、カメラがz座標値をグレー値に変換し、深度マップに保存します。

Scan3dCoordinateScaleScan3dPrincipalPointUScan3dPrincipalPointV、およびScan3dFocalLengthパラメーターによって提供されるカメラのキャリブレーションデータと組み合わせて、範囲マップから完全な3D情報を取得できます。

情報

The Scan3dCoordinateScale parameter value varies depending on the pixel format selected. When working with the camera in the blaze Viewer, the pixel format is set to the Coord3D_ABC32f pixel format. This setting can't be changed. The depth maps provided by the blaze Viewer are created based on the point clouds. The Scan3dCoordinateScale parameter value is 1 in this case. When you're working with the blaze camera outside the pylon Viewer and set the pixel format to Coord3D_C16, the Scan3dCoordinateScale parameter value is different.

範囲マップを送信するためのカメラの設定方法および範囲マップデータへのアクセス方法については、GrabDepthMap C++サンプルを参照してください。

2D範囲マップから3D座標を計算する#

範囲マップの16ビットグレー値をz座標(mm)に変換するには、次の数式を使用します。

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++サンプルコード#

// Query the conversion factor required to convert gray values to distances:
// Choose the z axis first...
GenApi::CEnumerationPtr(camera.GetParameter("Scan3dCoordinateSelector"))->FromString("CoordinateC");
// ... then retrieve the conversion factor.
const double gray2mm = GenApi::CFloatPtr(camera.GetParameter("Scan3dCoordinateScale"))->GetValue();

// Retrieve calibration data from the camera.
const double cx = GenApi::CFloatPtr(camera.GetParameter("Scan3dPrincipalPointU"))->GetValue();
const double cy = GenApi::CFloatPtr(camera.GetParameter("Scan3dPrincipalPointV"))->GetValue();
const double f = GenApi::CFloatPtr(camera.GetParameter("Scan3dFocalLength"))->GetValue();

const int width = (int)parts[0].width;
const int height = (int)parts[0].height;
uint16_t* pDepthMap = (uint16_t*) parts[0].pData;
for ( int v = 0; v < height; ++v ) {
    for ( int u = 0; u < width; ++u>) {
        const uint16_t g = pDepthMap[v*width + u];
        const double z = gray2mm * g;
    }
}

点群の処理#

点群から3D情報を抽出するために、これ以上の処理は必要ありません。点群は、カメラの座標系内のx、y、z座標の3点で構成されるためです。

点群を送信するためのカメラの設定方法およびデータへのアクセス方法については、FirstSample C++サンプルを参照してください。

点群に加えて深度マップが必要な場合は、ConvertPointCloud2DepthMap C++サンプルを参照してください。点群からグレースケールおよびRGB深度マップを計算する方法が説明されています。

座標系の原点をカメラハウジングの前面にシフトする#

カメラの座標系の原点は、カメラハウジング内にあるカメラの光学中心にあります。カメラのハウジング前面にある座標系(z軸に沿って平行移動される座標系)で座標を使用する場合は、デバイス固有の一定のオフセットをz座標から差し引く必要があります。必要なオフセットは、次のように、ZOffsetOriginToCameraFrontパラメーターの値を取得することでカメラから取得できます。

const double offset = GenApi::CFloatPtr(camera.GetParameter("ZOffsetOriginToCameraFront"))->GetValue();

(x,y,z)がカメラの座標系にある点の座標である場合、z軸に沿ってカメラのハウジングの前面にシフトされた座標系にある対応する座標(x',y',z')は、次の式を使用して決定できます。

x' = x
y' = y
z' = z - offset

距離の計算#

点の座標(x,y,z)がmmで指定されている場合、その点からカメラの光学中心までの距離は、次の式を使用して計算できます。

d = sqrt( x*x + y*y + z*z )

カメラのハウジングの前面までの距離d'は、次のように計算できます。

z' = z - offset
d' = sqrt( x*x + y*y + z'*z')

深度情報をRGB画像として表示#

次の虹色マッピングのスキームを使用して、z座標または距離値からRGB値を計算できます。これは、データの視覚化を改善するために役立ちます。

まず、[minDepth..maxDepth]値の範囲の深度値が10ビット値に変換されます。この10ビットの深度値では、各範囲の解像度が8ビットの4つのカラー範囲にマッピングされます。

minDepthおよびmaxDepth = DepthMinおよびDepthMaxパラメーターの値(カメラの現在の深度ROI)

深度値 カラー範囲へのマッピング
0..255 赤から黄
(255,0,0)->(255,255,0)
256..511 黄~緑
(255、255、0)->(0、255、0)
512..767 green to aqua
(0,255,0) -> (0,255,255)
768..1023 水色から青
(0,255,255) -> (0, 0, 255)

次のコードスニペットで、depthはz値または距離値(mm)のいずれかです。

minDepth = (int) GenApi::CIntegerPtr(camera.GetParameter("DepthMin"))->GetValue();
maxDepth = (int) GenApi::CIntegerPtr(camera.GetParameter("DepthMax"))->GetValue();

const double scale = 65520.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;
}