通过 ArUco 标记定义的 ROI 盒
本教程演示了如何使用 ArUco 标记确定 ROI 框的参数,以及如何使用它过滤料箱内容物。我们在此使用 Zivid calibration board (7x8 30mm, 300x300mm) 上的 ArUco 标记,并假设标定板放置在料箱的右下角。同时假定料箱尺寸已知,该数据用于设置 ROI 框的尺寸。这样您就可以自动在相机坐标系中找到 ROI 参数。
备注
本教程使用了一个档案相机(file camera)对下图中的场景进行演示。
首先,我们需要捕获 ArUco 标记的点云。
const auto fileCamera = std::string(ZIVID_SAMPLE_DATA_DIR) + "/BinWithCalibrationBoard.zdf";
const auto loadedFrameWithDiagnostics = Zivid::Frame(fileCamera);
std::cout << "Creating virtual camera using file: " << fileCamera << std::endl;
auto camera = zivid.createFileCamera(loadedFrameWithDiagnostics);
auto settings = loadedFrameWithDiagnostics.settings();
const auto originalFrame = camera.capture2D3D(settings);
auto pointCloud = originalFrame.pointCloud();
string fileCamera = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "/Zivid/BinWithCalibrationBoard.zdf";
var loadedFrameWithDiagnostics = new Zivid.NET.Frame(fileCamera);
Console.WriteLine("Creating virtual camera using file: " + fileCamera);
var camera = zivid.CreateFileCamera(loadedFrameWithDiagnostics);
var settings = loadedFrameWithDiagnostics.Settings;
using (var originalFrame = camera.Capture2D3D(settings))
{
var pointCloud = originalFrame.PointCloud;
file_camera = get_sample_data_path() / "BinWithCalibrationBoard.zdf"
loaded_frame_with_diagnostics = zivid.Frame(file_camera)
print(f"Creating virtual camera using file: {file_camera}")
camera = app.create_file_camera(loaded_frame_with_diagnostics)
settings = loaded_frame_with_diagnostics.settings
original_frame = camera.capture_2d_3d(settings)
point_cloud = original_frame.point_cloud()
ArUco 标记坐标系的原点位于 ArUco 标记的中心。
我们定义了 ROI 盒右下角相对于 ArUco 标记坐标系的位置,以及 ROI 盒尺寸。然后我们从长度和宽度中减去箱边缘的宽度以移除箱壁。
const float roiBoxLength = 545.F;
const float roiBoxWidth = 345.F;
const float roiBoxHeight = 150.F;
// Coordinates are relative to the ArUco marker origin which lies in the center of the ArUco marker.
// Positive x-axis is "East", y-axis is "South" and z-axis is "Down".
const Zivid::PointXYZ roiBoxLowerRightCornerInArUcoFrame{ 240.F, 30.F, 5.F };
const Zivid::PointXYZ roiBoxUpperRightCornerInArUcoFrame{ roiBoxLowerRightCornerInArUcoFrame.x,
roiBoxLowerRightCornerInArUcoFrame.y - roiBoxWidth,
roiBoxLowerRightCornerInArUcoFrame.z };
const Zivid::PointXYZ roiBoxLowerLeftCornerInArUcoFrame{ roiBoxLowerRightCornerInArUcoFrame.x - roiBoxLength,
roiBoxLowerRightCornerInArUcoFrame.y,
roiBoxLowerRightCornerInArUcoFrame.z };
float roiBoxLength = 545F;
float roiBoxWidth = 345F;
float roiBoxHeight = 150F;
// Coordinates are relative to the checkerboard origin which lies in the intersection between the four checkers
// in the top-left corner of the checkerboard: Positive x-axis is "East", y-axis is "South" and z-axis is "Down"
var roiBoxLowerRightCornerInCheckerboardFrame = new Zivid.NET.PointXYZ
{
x = 240F,
y = 30F,
z = 5F
};
var roiBoxUpperRightCornerInCheckerboardFrame = new Zivid.NET.PointXYZ
{
x = roiBoxLowerRightCornerInCheckerboardFrame.x,
y = roiBoxLowerRightCornerInCheckerboardFrame.y - roiBoxWidth,
z = roiBoxLowerRightCornerInCheckerboardFrame.z
};
var roiBoxLowerLeftCornerInCheckerboardFrame = new Zivid.NET.PointXYZ
{
x = roiBoxLowerRightCornerInCheckerboardFrame.x - roiBoxLength,
y = roiBoxLowerRightCornerInCheckerboardFrame.y,
z = roiBoxLowerRightCornerInCheckerboardFrame.z
};
roi_box_length = 545
roi_box_width = 345
roi_box_height = 150
roi_box_lower_right_corner_in_aruco_frame = np.array([240, 30, 5])
roi_box_upper_right_corner_in_aruco_frame = np.array(
[
roi_box_lower_right_corner_in_aruco_frame[0],
roi_box_lower_right_corner_in_aruco_frame[1] - roi_box_width,
roi_box_lower_right_corner_in_aruco_frame[2],
]
)
roi_box_lower_left_corner_in_aruco_frame = np.array(
[
roi_box_lower_right_corner_in_aruco_frame[0] - roi_box_length,
roi_box_lower_right_corner_in_aruco_frame[1],
roi_box_lower_right_corner_in_aruco_frame[2],
]
)
然后可以设置定义 ROI 盒基坐标系的三个点。
const Zivid::PointXYZ pointOInArUcoFrame = roiBoxLowerRightCornerInArUcoFrame;
const Zivid::PointXYZ pointAInArUcoFrame = roiBoxUpperRightCornerInArUcoFrame;
const Zivid::PointXYZ pointBInArUcoFrame = roiBoxLowerLeftCornerInArUcoFrame;
然后我们将配置 ArUco 标记。
std::cout << "Configuring ArUco marker" << std::endl;
const auto markerDictionary = Zivid::Calibration::MarkerDictionary::aruco4x4_50;
std::vector<int> markerId = { 1 };
然后我们检测 ArUco 标记。
然后我们需要估计 ArUco 标记的位姿,将这三个点转换到相机参考系。
std::cout << "Estimating pose of detected ArUco marker" << std::endl;
const auto cameraToMarkerTransform = detectionResult.detectedMarkers()[0].pose().toMatrix();
std::cout << "Transforming the ROI base frame points to the camera frame" << std::endl;
const auto roiPointsInCameraFrame = transformPoints(
std::vector<Zivid::PointXYZ>{ pointOInArUcoFrame, pointAInArUcoFrame, pointBInArUcoFrame },
cameraToMarkerTransform);
Console.WriteLine("Estimating pose of detected ArUco marker");
var cameraToMarkerTransform = new Zivid.NET.Matrix4x4(detectionResult.DetectedMarkers()[0].Pose().ToMatrix());
Console.WriteLine("Transforming the ROI base frame points to the camera frame");
var roiPointsInCameraFrame = TransformPoints(
new List<Zivid.NET.PointXYZ> { pointOInCheckerboardFrame, pointAInCheckerboardFrame, pointBInCheckerboardFrame },
cameraToMarkerTransform);
print("Estimating pose of detected ArUco marker")
camera_to_marker_transform = detection_result.detected_markers()[0].pose.to_matrix()
print("Transforming the ROI base frame points to the camera frame")
roi_points_in_camera_frame = _transform_points(
[point_o_in_aruco_frame, point_a_in_aruco_frame, point_b_in_aruco_frame],
camera_to_marker_transform,
)
提示
详细了解 位置、方向和坐标变换 来了解其工作原理。
现在我们可以根据 ROI 盒的大小和位置过滤点云。将第一个范围(extent)设置为一个较小的负数值来避免过滤掉底板,第二个范围(extent)设置为所需的盒子高度。
const auto roiSettings = Zivid::Settings::RegionOfInterest::Box{
Zivid::Settings::RegionOfInterest::Box::Enabled::yes,
Zivid::Settings::RegionOfInterest::Box::PointO{ roiPointsInCameraFrame[0] },
Zivid::Settings::RegionOfInterest::Box::PointA{ roiPointsInCameraFrame[1] },
Zivid::Settings::RegionOfInterest::Box::PointB{ roiPointsInCameraFrame[2] },
Zivid::Settings::RegionOfInterest::Box::Extents{ -10, roiBoxHeight }
};
现在,我们可以利用感兴趣区域(ROI)对捕获的点云进行掩膜处理,并可视化最终结果。
const auto roiPointCloud = pointCloud.maskedByRegionOfInterest(roiSettings);
std::cout << "Displaying the ROI-filtered point cloud" << std::endl;
visualizeZividPointCloud(roiPointCloud);
最后,我们将 ROI 框添加到捕获设置中,直接应用 ROI 过滤器来捕获点云。这种方法比捕获后再进行掩膜处理速度更快,并且允许您保存包含 ROI 参数的捕获设置,以便在移除标定板后重复使用。
std::cout << "Adding the ROI box to the capture settings and capturing again" << std::endl;
settings.set(Zivid::Settings::RegionOfInterest{ roiSettings });
const auto roiFrame = camera.capture2D3D(settings);
std::cout << "Displaying the ROI-filtered point cloud from the new capture" << std::endl;
visualizeZividPointCloud(roiFrame.pointCloud());
Console.WriteLine("Adding the ROI box to the capture settings and capturing again");
settings.RegionOfInterest.Box = roiSettings;
using (var roiFrame = camera.Capture2D3D(settings))
{
Console.WriteLine("Displaying the ROI-filtered point cloud from the new capture");
VisualizeZividPointCloud(roiFrame);
}
如需根据 ROI 盒过滤点云,您可以运行我们的代码示例。
./ROIBoxViaArucoMarker
./ROIBoxViaArucoMarker
示例: roi_box_via_aruco_marker.py
python roi_box_via_aruco_marker.py
小技巧
如果您希望在自己的设置中使用它,您可以自行修改代码示例:
用您的实际相机和设置替换档案相机。
将标定板放在料箱的右下角。
将 ROI 盒尺寸修改为您的料箱的尺寸。
运行示例!
您现在可以保存包含了 ROI 参数的捕获设置了,然后拿走标定板并在整个料箱上使用该设置。
版本历史
SDK |
变更内容 |
|---|---|
2.18.0 |
通过 ROI 盒对已捕获的点云进行掩膜处理,而不是重新捕获。 |