ROI Box via Checkerboard
This tutorial demonstrates how to find the ROI box parameters using the Zivid calibration board and how to filter the contents of a bin using it. We assume the calibration board is placed in the bottom right corner of the bin. The bin size is also assumed known and is used to set the dimensions of the ROI box. This way you can automatically find the ROI parameters in the camera frame.
Note
This tutorial uses a file camera for the scene in the image below for demonstration.
First, we capture a point cloud of the checkerboard.
const auto fileCamera = std::string(ZIVID_SAMPLE_DATA_DIR) + "/BinWithCalibrationBoard.zfc";
std::cout << "Creating virtual camera using file: " << fileCamera << std::endl;
auto camera = zivid.createFileCamera(fileCamera);
auto settings = Zivid::Settings{ Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{} } };
const auto originalFrame = camera.capture(settings);
auto pointCloud = originalFrame.pointCloud();
string fileCamera = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "/Zivid/BinWithCalibrationBoard.zfc";
Console.WriteLine("Creating virtual camera using file: " + fileCamera);
var camera = zivid.CreateFileCamera(fileCamera);
var settings = new Zivid.NET.Settings
{
Acquisitions = { new Zivid.NET.Settings.Acquisition { } }
};
var originalFrame = camera.Capture(settings);
var pointCloud = originalFrame.PointCloud;
file_camera = get_sample_data_path() / "BinWithCalibrationBoard.zfc"
print(f"Creating virtual camera using file: {file_camera}")
camera = app.create_file_camera(file_camera)
settings = zivid.Settings([zivid.Settings.Acquisition()])
original_frame = camera.capture(settings)
point_cloud = original_frame.point_cloud()
The checkerboard frame has its origin in the intersection between the four checkers in the top-left corner of the board.
We define the position of the bottom-right corner of the ROI box relative to the checkerboard frame, and the ROI box size. Then we subtract the width of the bin edge from the length and width to remove the bin walls.
// 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"
const Zivid::PointXYZ roiBoxLowerRightCornerInCheckerboardFrame{ 240.F, 260.F, 5.F };
const Zivid::PointXYZ roiBoxUpperRightCornerInCheckerboardFrame{ roiBoxLowerRightCornerInCheckerboardFrame.x,
roiBoxLowerRightCornerInCheckerboardFrame.y
- roiBoxWidth,
roiBoxLowerRightCornerInCheckerboardFrame.z };
const Zivid::PointXYZ roiBoxLowerLeftCornerInCheckerboardFrame{ roiBoxLowerRightCornerInCheckerboardFrame.x
- roiBoxLength,
roiBoxLowerRightCornerInCheckerboardFrame.y,
roiBoxLowerRightCornerInCheckerboardFrame.z };
const float roiBoxLength = 545.F;
const float roiBoxWidth = 345.F;
const float roiBoxHeight = 150.F;
// 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 = 260F,
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
};
float roiBoxLength = 545F;
float roiBoxWidth = 345F;
float roiBoxHeight = 150F;
roi_box_lower_right_corner = np.array([240, 260, 0.5])
roi_box_upper_right_corner = np.array(
[
roi_box_lower_right_corner[0],
roi_box_lower_right_corner[1] - roi_box_width,
roi_box_lower_right_corner[2],
]
)
roi_box_lower_left_corner = np.array(
[
roi_box_lower_right_corner[0] - roi_box_length,
roi_box_lower_right_corner[1],
roi_box_lower_right_corner[2],
]
)
roi_box_length = 545
roi_box_width = 345
roi_box_height = 150
The three points that define the base frame of the ROI box can then be set.
const Zivid::PointXYZ pointOInCheckerboardFrame = roiBoxLowerRightCornerInCheckerboardFrame;
const Zivid::PointXYZ pointAInCheckerboardFrame = roiBoxUpperRightCornerInCheckerboardFrame;
const Zivid::PointXYZ pointBInCheckerboardFrame = roiBoxLowerLeftCornerInCheckerboardFrame;
var pointOInCheckerboardFrame = roiBoxLowerRightCornerInCheckerboardFrame;
var pointAInCheckerboardFrame = roiBoxUpperRightCornerInCheckerboardFrame;
var pointBInCheckerboardFrame = roiBoxLowerLeftCornerInCheckerboardFrame;
point_o_in_checkerboard_frame = roi_box_lower_right_corner
point_a_in_checkerboard_frame = roi_box_upper_right_corner
point_b_in_checkerboard_frame = roi_box_lower_left_corner
Then we estimate the pose of the checkerboard to transform the three points into the camera frame of reference.
std::cout << "Detecting and estimating pose of the Zivid checkerboard in the camera frame" << std::endl;
const auto detectionResult = Zivid::Calibration::detectCalibrationBoard(originalFrame);
const auto transformCameraToCheckerboard = detectionResult.pose().toMatrix();
std::cout << "Transforming the ROI base frame points to the camera frame" << std::endl;
const auto roiPointsInCameraFrame = transformPoints(
std::vector<Zivid::PointXYZ>{
pointOInCheckerboardFrame, pointAInCheckerboardFrame, pointBInCheckerboardFrame },
transformCameraToCheckerboard);
Console.WriteLine("Detecting and estimating pose of the Zivid checkerboard in the camera frame");
var detectionResult = Detector.DetectCalibrationBoard(originalFrame);
var cameraToCheckerboardTransform = new Zivid.NET.Matrix4x4(detectionResult.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 },
cameraToCheckerboardTransform);
print("Detecting and estimating pose of the Zivid checkerboard in the camera frame")
detection_result = zivid.calibration.detect_feature_points(original_frame)
camera_to_checkerboard_transform = detection_result.pose().to_matrix()
print("Transforming the ROI base frame points to the camera frame")
roi_points_in_camera_frame = _transform_points(
[point_o_in_checkerboard_frame, point_a_in_checkerboard_frame, point_b_in_checkerboard_frame],
camera_to_checkerboard_transform,
)
Hint
Learn more about Position, Orientation and Coordinate Transformations to understand how this works.
Now we can filter the point cloud based on the size and position of the ROI box. The first extent is set to a small negative value to include the floor, and the second extent is set to the desired height of the box.
settings.set(Zivid::Settings::RegionOfInterest{
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 } });
settings.RegionOfInterest.Box.Enabled = true;
settings.RegionOfInterest.Box.PointO = roiPointsInCameraFrame[0];
settings.RegionOfInterest.Box.PointA = roiPointsInCameraFrame[1];
settings.RegionOfInterest.Box.PointB = roiPointsInCameraFrame[2];
settings.RegionOfInterest.Box.Extents = new Zivid.NET.Range<double>(-10, roiBoxHeight);
settings.region_of_interest.box.enabled = True
settings.region_of_interest.box.point_o = roi_points_in_camera_frame[0]
settings.region_of_interest.box.point_a = roi_points_in_camera_frame[1]
settings.region_of_interest.box.point_b = roi_points_in_camera_frame[2]
settings.region_of_interest.box.extents = (-10, roi_box_height)
Finally, we take a new capture and visualize the filtered point cloud.
const auto roiFrame = camera.capture(settings);
std::cout << "Displaying the ROI-filtered point cloud" << std::endl;
visualizeZividPointCloud(roiFrame);
var roiFrame = camera.Capture(settings);
Console.WriteLine("Displaying the ROI-filtered point cloud");
VisualizeZividPointCloud(roiFrame);
roi_point_cloud = camera.capture(settings).point_cloud()
print("Displaying the ROI-filtered point cloud")
display_pointcloud(roi_point_cloud.copy_data("xyz"), roi_point_cloud.copy_data("rgba")[:, :, :3])
To filter the point cloud based on a ROI box, you can run our code sample.
Sample: ROIBoxViaCheckerboard.cpp
./ROIBoxViaCheckerboard
Sample: ROIBoxViaCheckerboard.cs
./ROIBoxViaCheckerboard
Sample: roi_box_via_checkerboard.py
python roi_box_via_checkerboard.py
Tip
Modify the code sample if you wish to use this in your own setup:
Replace the file camera with your actual camera and settings.
Place the checkerboard in the bottom right corner of your bin.
Modify the ROI box size to your bin size.
Run sample!
You can now save the capture settings with the ROI parameters, remove the checkerboard and use the settings on the whole bin.