측정 결과 처리#
정보
이 항목의 모든 정보는 모든 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 정보를 검색할 수 있습니다.
정보
이 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 |
카메라를 구성하여 깊이 맵(depth map)을 전송하고 깊이 맵 데이터에 액세스하는 방법은 GrabDepthMap C++ 샘플을 참조하십시오.
2D 뎁스 맵에서 3D 좌표 계산하기#
깊이 맵의 16비트 회색조 값을 mm 단위의 z 좌표로 변환하려면 다음 공식을 사용합니다.
z [mm] = gray2mm * g
여기서:
g = 깊이 맵의 회색조 값
gray2mm = 다음 항목의 값: Scan3dCoordinateScale parameter
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 좌표 삼중항(triples)으로 구성되므로, 포인트 클라우드에서 3D 정보를 추출하기 위한 추가 처리는 필요하지 않습니다.
카메라를 구성하여 포인트 클라우드를 전송하고 데이터에 액세스하는 방법은 FirstSample C++ 샘플을 참조하십시오.
포인트 클라우드 외에도 깊이 맵이 필요한 경우, 포인트 클라우드에서 회색조 및 RGB 깊이 맵을 연산하는 방법을 보여주는 ConvertPointCloud2DepthMap C++ 샘플을 참조하십시오.
좌표계의 원점을 카메라 하우징 전면으로 이동#
카메라 좌표계의 원점은 카메라 하우징 내부에 있는 카메라 광학 중심에 위치합니다. z축을 따라 평행 이동된, 즉 카메라 하우징 전면에 위치한 좌표계의 좌표를 선호하는 경우 장치 고유의 상수 오프셋을 z 좌표에서 빼야 합니다. 필요한 오프셋은 다음의 값을 가져와 카메라에서 검색할 수 있습니다. ZOffsetOriginToCameraFront 파라미터:
(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 즉, 카메라의 현재 Depth ROI
| Depth 값 | 색상 범위에 맵핑됨 |
|---|---|
| 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;
}