关于多个 Zivid 相机同时工作的性能的考虑因素
To capture with multiple Zivid cameras at the best speed, capture sequentially if the cameras' fields of view overlap, or in parallel if they do not. Overlapping FOVs mean the cameras' projected light patterns interfere with each other, so only one camera can capture at a time; non-overlapping FOVs have no such interference, so all cameras can capture at the same time.
Capture Sequentially
下面是两个使用了顺序捕获的应用的示例:
使用多个相机从不同侧面对物体进行成像(检测)
使用多个相机对一个或多个料箱进行成像来规避遮挡问题(料箱拣选/单品拣选)
此类应用中的多台相机之间存在重叠的 FOV。因此,为避免投影的白光图案在相机之间产生干扰,需要一次使用一台相机进行拍摄。
For both the inspection and bin/piece-picking use cases above, we recommend the same capture strategy. To explain this strategy, let us take as an example the inspection of an object on a conveyor belt.
当检测对象位于相机的视野内时,传送带停止。为了优化捕获过程的速度,我们建议顺序调用捕获(capture )函数,因为捕获(capture )API 会在采集(acquisition )完成时返回。
std::vector<Zivid::Frame> frames;
for(auto &camera : connectedCameras)
{
std::cout << "Capturing frame with camera: " << camera.info().serialNumber() << std::endl;
const auto settings =
Zivid::Settings{ Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{} },
Zivid::Settings::Color{ Zivid::Settings2D{
Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } } } };
const auto frame = camera.capture2D3D(settings);
frames.push_back(frame);
}
小技巧
如果您执行 2D 捕获而不是 3D 捕获,建议采用相同的策略。但是,如果您同时需要 2D 和 3D,那么建议您查看我们的 2D+3D 捕获策略 。
一旦所有相机都完成了捕获,场景就可以相对于相机移动了。在本文的示例中,即为运输物体的传送带可以开始移动了。
这也是复制数据、拼接点云和检测对象等过程可以开始进行的时候。这些操作可以顺序发生或并行发生。在下面的实施示例中,我们展示了如何复制数据并将其并行保存到 ZDF 文件。
备注
为了优化速度,重要的是在捕获函数返回之后和调用 API 以获取点云之前触发移动传送带。
namespace
{
Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB> processAndSaveInThread(const Zivid::Frame &frame)
{
const auto pointCloud = frame.pointCloud();
auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA_SRGB>();
// This is where you should run your processing
const auto dataFile = "Frame_" + frame.cameraInfo().serialNumber().value() + ".zdf";
std::cout << "Saving frame to file: " << dataFile << std::endl;
frame.save(dataFile);
return data;
}
std::vector<Zivid::Camera> connectToAllAvailableCameras(const std::vector<Zivid::Camera> &cameras)
{
std::vector<Zivid::Camera> connectedCameras;
for(auto camera : cameras)
{
if(camera.state().status() == Zivid::CameraState::Status::available)
{
std::cout << "Connecting to camera: " << camera.info().serialNumber() << std::endl;
camera.connect();
connectedCameras.push_back(camera);
}
else
{
std::cout << "Camera " << camera.info().serialNumber() << "is not available. "
<< "Camera status: " << camera.state().status() << std::endl;
}
}
return connectedCameras;
}
} // namespace
std::vector<std::future<Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB>>> futureData;
for(auto &frame : frames)
{
std::cout << "Starting to process and save (in a separate thread) the frame captured with camera: "
<< frame.cameraInfo().serialNumber().value() << std::endl;
futureData.emplace_back(std::async(std::launch::async, processAndSaveInThread, frame));
}
要进一步优化整个过程的速度,您可以执行以下操作。一旦捕获函数返回,就启动一个不同的线程,在 frame 上执行以下操作:
获取点云
将点云复制到 CPU 内存
可能需要的其它点云操作,例如,将点云转换到某个坐标系
查看下面的实施示例。
namespace
{
Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB> processAndSaveInThread(const Zivid::Frame &frame)
{
const auto pointCloud = frame.pointCloud();
auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA_SRGB>();
// This is where you should run your processing
const auto dataFile = "Frame_" + frame.cameraInfo().serialNumber().value() + ".zdf";
std::cout << "Saving frame to file: " << dataFile << std::endl;
frame.save(dataFile);
return data;
}
std::vector<Zivid::Camera> connectToAllAvailableCameras(const std::vector<Zivid::Camera> &cameras)
{
std::vector<Zivid::Camera> connectedCameras;
for(auto camera : cameras)
{
if(camera.state().status() == Zivid::CameraState::Status::available)
{
std::cout << "Connecting to camera: " << camera.info().serialNumber() << std::endl;
camera.connect();
connectedCameras.push_back(camera);
}
else
{
std::cout << "Camera " << camera.info().serialNumber() << "is not available. "
<< "Camera status: " << camera.state().status() << std::endl;
}
}
return connectedCameras;
}
} // namespace
std::vector<std::future<Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB>>> futureData;
for(auto &camera : connectedCameras)
{
std::cout << "Capturing frame with camera: " << camera.info().serialNumber() << std::endl;
const auto settings =
Zivid::Settings{ Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{} },
Zivid::Settings::Color{ Zivid::Settings2D{
Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } } } };
const auto frame = camera.capture2D3D(settings);
std::cout << "Starting to process and save (in a separate thread) the frame captured with camera: "
<< frame.cameraInfo().serialNumber().value() << std::endl;
futureData.emplace_back(std::async(std::launch::async, processAndSaveInThread, frame));
}
然后您需要等到所有数据都可用,才能执行进一步的处理,例如,拼接点云。
Capture in Parallel
下面是一个使用并行捕获的应用的示例:
使用多台相机对不适合单台相机 FOV 尺寸的物体进行成像(检测)
此类应用中的多台相机之前没有重叠的 FOV(使用多台相机的目的是扩展 FOV)。因此,可以并行捕获以节省时间。
为了解释我们推荐的捕获策略,让我们以检测传送带上的大型物体为例。
当待检物体位于相机的组合视场内时,传送带停止。为了优化捕获过程的速度,我们建议在单独的线程中只调用每个相机的捕获函数并阻塞,直到所有线程执行结束。我们建议只调用捕获(capture )函数,因为捕获(capture )API 会在采集(acquisition )完成时返回。
namespace
{
Zivid::Frame captureInThread(Zivid::Camera &camera)
{
const auto settings =
Zivid::Settings{ Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{} },
Zivid::Settings::Color{ Zivid::Settings2D{
Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } } } };
std::cout << "Capturing frame with camera: " << camera.info().serialNumber().value() << std::endl;
auto frame = camera.capture2D3D(settings);
return frame;
}
} // namespace
std::vector<std::future<Zivid::Frame>> futureFrames;
for(auto &camera : connectedCameras)
{
std::cout << "Starting to capture (in a separate thread) with camera: "
<< camera.info().serialNumber().value() << std::endl;
futureFrames.emplace_back(std::async(std::launch::async, captureInThread, std::ref(camera)));
}
std::vector<Zivid::Frame> frames;
for(size_t i = 0; i < connectedCameras.size(); ++i)
{
std::cout << "Waiting for camera " << connectedCameras[i].info().serialNumber() << " to finish capturing"
<< std::endl;
const auto frame = futureFrames[i].get();
frames.push_back(frame);
}
小技巧
如果您执行 2D 捕获而不是 3D 捕获,建议采用相同的策略。但是,如果您同时需要 2D 和 3D,那么建议您查看我们的 2D+3D 捕获策略 。
一旦所有相机都完成了捕获,场景就可以相对于相机移动了。在本文的示例中,即为运输物体的传送带可以开始移动了。
这也是复制数据、拼接点云和检测对象等过程可以开始进行的时候。这些操作可以顺序发生或并行发生。在下面的实施示例中,我们展示了如何复制数据并将其并行保存到 ZDF 文件。
备注
为了优化速度,重要的是在捕获函数返回之后和调用 API 以获取点云之前触发移动传送带。
namespace
{
Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB> processAndSaveInThread(const Zivid::Frame &frame)
{
const auto pointCloud = frame.pointCloud();
auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA_SRGB>();
// This is where you should run your processing
const auto dataFile = "Frame_" + frame.cameraInfo().serialNumber().value() + ".zdf";
std::cout << "Saving frame to file: " << dataFile << std::endl;
frame.save(dataFile);
return data;
}
} // namespace
std::vector<std::future<Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB>>> futureData;
for(auto &frame : frames)
{
std::cout << "Starting to process and save (in a separate thread) the frame captured with camera: "
<< frame.cameraInfo().serialNumber().value() << std::endl;
futureData.emplace_back(std::async(std::launch::async, processAndSaveInThread, frame));
}
然后您需要等到所有数据都可用,才能执行进一步的处理,例如,拼接点云。
std::vector<Zivid::Array2D<Zivid::PointXYZColorRGBA_SRGB>> allData;
for(size_t i = 0; i < frames.size(); ++i)
{
std::cout << "Waiting for processing and saving to finish for camera "
<< frames[i].cameraInfo().serialNumber().value() << std::endl;
const auto data = futureData[i].get();
allData.push_back(data);
}
版本历史
SDK |
变更 |
|---|---|
2.11.0 |
Zivid 2 和 2+ 现在支持 3D ➞ 2D 和 3D ➞ 2D 的并发处理和采集,并且捕获模式之间的切换已得到优化。 |