关于多个Zivid相机同时工作的性能的考虑因素
下面是两个使用了顺序捕获的应用的示例:
使用多个相机从不同侧面对物体进行成像(检测)
使用多个相机对一个或多个料箱进行成像来规避遮挡问题(料箱拣选/单品拣选)
此类应用中的多台相机之间存在重叠的FOV。因此,为避免投影的白光图案在相机之间产生干扰,需要一次使用一台相机进行拍摄。
对于上面提到的两个应用,我们推荐相同的捕获策略。为了解释这个策略,让我们以检测传送带上的物体为例。
当检测对象位于相机的视野内时,传送带停止。为了优化捕获过程的速度,我们建议顺序调用捕获(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 parameters = Zivid::CaptureAssistant::SuggestSettingsParameters{
Zivid::CaptureAssistant::SuggestSettingsParameters::AmbientLightFrequency::none,
Zivid::CaptureAssistant::SuggestSettingsParameters::MaxCaptureTime{ std::chrono::milliseconds{ 800 } }
};
const auto settings = Zivid::CaptureAssistant::suggestSettings(camera, parameters);
const auto frame = camera.capture(settings);
frames.push_back(frame);
}
小技巧
如果您执行 2D 捕获而不是 3D 捕获,建议采用相同的策略。但是,如果您同时需要 2D 和 3D,那么建议您查看我们的 2D+3D捕获策略 。
一旦所有相机都完成了捕获,场景就可以相对于相机移动了。在本文的示例中,即为运输物体的传送带可以开始移动了。
这也是复制数据、拼接点云和检测对象等过程可以开始进行的时候。这些操作可以顺序发生或并行发生。在下面的实施示例中,我们展示了如何复制数据并将其并行保存到ZDF文件。
备注
为了优化速度,重要的是在捕获函数返回之后和调用API以获取点云之前触发移动传送带。
namespace
{
Zivid::Array2D<Zivid::PointXYZColorRGBA> processAndSaveInThread(const Zivid::Frame &frame)
{
const auto pointCloud = frame.pointCloud();
auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA>();
// 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>>> 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> processAndSaveInThread(const Zivid::Frame &frame)
{
const auto pointCloud = frame.pointCloud();
auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA>();
// 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>>> futureData;
for(auto &camera : connectedCameras)
{
std::cout << "Capturing frame with camera: " << camera.info().serialNumber() << std::endl;
const auto parameters = Zivid::CaptureAssistant::SuggestSettingsParameters{
Zivid::CaptureAssistant::SuggestSettingsParameters::AmbientLightFrequency::none,
Zivid::CaptureAssistant::SuggestSettingsParameters::MaxCaptureTime{ std::chrono::milliseconds{ 800 } }
};
const auto settings = Zivid::CaptureAssistant::suggestSettings(camera, parameters);
const auto frame = camera.capture(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));
}
然后您需要等到所有数据都可用,才能执行进一步的处理,例如,拼接点云。
std::vector<Zivid::Array2D<Zivid::PointXYZColorRGBA>> allData;
for(size_t i = 0; i < cameras.size(); ++i)
{
std::cout << "Waiting for processing and saving to finish for camera " << cameras[i].info().serialNumber()
<< std::endl;
const auto data = futureData[i].get();
allData.push_back(data);
}
下面是一个使用并行捕获的应用的示例:
使用多台相机对不适合单台相机FOV尺寸的物体进行成像(检测)
此类应用中的多台相机之前没有重叠的FOV(使用多台相机的目的是扩展FOV)。因此,可以并行捕获以节省时间。
为了解释我们推荐的捕获策略,让我们以检测传送带上的大型物体为例。
当待检物体位于相机的组合视场内时,传送带停止。为了优化捕获过程的速度,我们建议在单独的线程中只调用每个相机的捕获函数并阻塞,直到所有线程执行结束。我们建议只调用捕获(capture )函数,因为捕获(capture )API会在采集(acquisition )完成时返回。
namespace
{
Zivid::Frame captureInThread(Zivid::Camera &camera)
{
const auto parameters = Zivid::CaptureAssistant::SuggestSettingsParameters{
Zivid::CaptureAssistant::SuggestSettingsParameters::AmbientLightFrequency::none,
Zivid::CaptureAssistant::SuggestSettingsParameters::MaxCaptureTime{ std::chrono::milliseconds{ 800 } }
};
const auto settings = Zivid::CaptureAssistant::suggestSettings(camera, parameters);
std::cout << "Capturing frame with camera: " << camera.info().serialNumber().value() << std::endl;
auto frame = camera.capture(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> processAndSaveInThread(const Zivid::Frame &frame)
{
const auto pointCloud = frame.pointCloud();
auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA>();
// 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>>> 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>> 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 的并发处理和采集,并且捕获模式之间的切换已得到优化。 |