콘텐츠로 바로 가기
STAGING SERVER
DEVELOPMENT SERVER

Processing Measurement Results#

이 항목에서는 Basler blaze 및 Smart blaze 카메라의 측정 결과를 처리하는 방법에 대해 설명합니다.

정보

이 항목의 모든 정보는 모든 blaze 및 Smart blaze 카메라 모델에 적용됩니다. 간결함을 위해 모든 모델을 지칭할 때 "blaze"를 사용합니다.

개요#

Basler blaze 카메라는 각 센서 픽셀에 대해 빛이 이동한 거리를 측정합니다.

이 거리를 사용하여 카메라는 각 센서 픽셀에 대한 오른손잡이 좌표계의 x, y, z 좌표를 계산합니다. 좌표계의 원점은 카메라 하우징 내부에 위치한 카메라의 광학 중심에 있습니다. y축은 아래쪽을 향하고 z축은 카메라에서 멀어지는 방향을 향합니다.

카메라는 선택한 Pixel Format에 따라 뎁스 맵 또는 포인트 클라우드 형식으로 3D 정보를 제공합니다. 뎁스 맵에서 z 좌표는 16비트 회색조 값으로 인코딩됩니다. 아래 그림과 같이 모든 3D 좌표 값은 회색조 값에서 계산할 수 있습니다. 포인트 클라우드는 각 센서 픽셀의 x, y, z 3D 좌표를 부동 소수점 숫자로 포함합니다. 단위는 mm입니다.

센서 픽셀에 대한 유효한 깊이 정보가 없는 경우(예: 이상치 제거 또는 광량이 부족하여, 즉 빛이 통과하기에 충분히 강하지 않은 경우 신뢰 구간), 뎁스 맵 또는 포인트 클라우드의 해당 값은 Scan3dInvalidDataValue 매개변수(기본 설정은 0)에 의해 정의된 값으로 설정됩니다.

뎁스 맵 처리#

뎁스 맵은 16비트 회색조 값으로 구성됩니다. 각 센서 픽셀에 대해 카메라는 z 좌표 값을 회색조 값으로 변환하여 뎁스 맵에 저장합니다.

제공되는 카메라 캘리브레이션 데이터와 결합하여 Scan3dCoordinateScale, Scan3dPrincipalPointU, Scan3dPrincipalPointV및 Scan3dFocalLength 매개변수를 통해 뎁스 맵에서 완전한 3D 정보를 검색할 수 있습니다.

정보

The Scan3dCoordinateScale 매개변수 값은 선택한 Pixel Format에 따라 다릅니다. blaze Viewer에서 카메라로 작업할 때 Pixel Format은 항상 Coord3D_ABC32f Pixel Format으로 설정됩니다. 이 설정은 변경할 수 없습니다. blaze Viewer에서 제공하는 뎁스 맵은 포인트 클라우드를 기반으로 생성됩니다. 이 경우 Scan3dCoordinateScale 매개변수 값은 1입니다. pylon Viewer 외부에서 blaze 카메라로 작업하고 Pixel Format을 Coord3D_C16, Scan3dCoordinateScale 매개변수 값이 다릅니다. 서로 다른 Pixel Format에 대한 Scan3dCoordinateScale 매개변수 값은 다음 표에 나열되어 있습니다.

Pixel Format Scan3dCoordinateScale[C] 파라미터 값
Coord3D_ABC32f 1
Coord3D_C16 0.152588
Mono16 0.152588

카메라를 구성하여 뎁스 맵을 전송하는 방법과 뎁스 맵 데이터에 액세스하는 방법은 GrabDepthMap C++ 샘플을 참조하십시오.

2D 뎁스 맵에서 3D 좌표 계산하기#

뎁스 맵의 16비트 그레이 값을 mm 단위의 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 파라미터, 즉 주점(principal point)

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] = Pixel_Value x Scan3dCoordinateScale[C]

blaze Viewer로 저장한 뎁스 맵의 경우 다음 공식을 사용하십시오.

측정된 거리 [mm] = DepthMin_parameter + (Pixel_Value x (DepthMax_Parameter - DepthMin_parameter)) / 65535

포인트 클라우드 처리#

포인트 클라우드는 카메라 좌표계 내의 x, y, z 좌표 삼원조(triple)로 구성되므로, 포인트 클라우드에서 3D 정보를 추출하기 위한 추가 처리가 필요하지 않습니다.

카메라를 구성하여 포인트 클라우드를 전송하는 방법과 데이터에 액세스하는 방법은 FirstSample C++ 샘플을 참조하십시오.

포인트 클라우드 외에 뎁스 맵이 필요한 경우, 포인트 클라우드에서 그레이스케일 및 RGB 뎁스 맵을 계산하는 방법을 보여주는 ConvertPointCloud2DepthMap C++ 샘플을 참조하십시오.

좌표계의 원점을 카메라 하우징 전면으로 이동#

카메라 좌표계의 원점은 카메라 하우징 내부에 있는 카메라 광학 중심에 위치합니다. 하우징 전면에 위치한 좌표계(즉, z축을 따라 이동된 좌표계)의 좌표를 선호하는 경우, 디바이스 고유의 상수 오프셋을 z 좌표에서 빼야 합니다. 필요한 오프셋은 다음 값을 가져와서 카메라에서 검색할 수 있습니다. ZOffsetOriginToCameraFront Parameter:

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

(x, y, z)가 카메라 좌표계 내 한 점의 좌표인 경우, 카메라 하우징 전면의 z축을 따라 이동한 좌표계에서의 해당 좌표 (x', y', z')는 다음 공식을 사용하여 결정할 수 있습니다.

x' = x

y' = y

z' = z - offset

거리 계산#

한 점의 좌표가 주어지면 (x,y,z) (단위: mm), 카메라 광학 중심에서 해당 점까지의 거리는 다음 공식을 사용하여 계산할 수 있습니다.

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

거리 d' 카메라 하우징 전면까지의 거리는 다음과 같이 계산할 수 있습니다.

z' = z - offset

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

깊이 정보를 RGB 이미지로 시각화하기#

무지개 색상 매핑을 위해 다음 방식을 사용하면 z 좌표 또는 거리 값에서 RGB 값을 계산할 수 있습니다. 이는 데이터 시각화를 개선하는 데 유용할 수 있습니다.

먼저, 다음의 깊이 값 [minDepth..maxDepth] 값 범위가 10비트 값으로 변환됩니다. 이 10비트 깊이 값은 각각 8비트 해상도를 가진 4개의 색상 범위로 매핑됩니다.

minDepth 및 maxDepth = 다음의 값: DepthMin 및 DepthMax parameter, 즉 카메라의 현재 Depth ROI

Depth Value 색상 범위로 매핑됨
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 값 또는 mm 단위의 거리 값입니다.

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;
}