Performance Considerations for Multiple Zivid Cameras

순차 캡처를 활용하는 애플리케이션의 두 가지 예는 다음과 같습니다.

  • 여러 대의 카메라로 물체를 여러 면에서 촬영하는 경우 (검사)

  • Occlusion(가림)을 피하기 위해 여러 대의 카메라로 하나 이상의 빈을 촬영하는 경우 (Bin Picking / Piece Picking)

이러한 애플리케이션의 카메라는 FOV가 겹칩니다. 따라서 투사된 백색광 패턴으로 인한 카메라 간 간섭을 피하기 위해 한 번에 하나의 카메라로 촬영해야 합니다.

위에서 언급한 두 애플리케이션에 대해 동일한 캡처 전략을 권장합니다. 이 전략을 설명하기 위해 컨베이어 벨트에 있는 물체를 검사하는 경우를 예로 들어 보겠습니다.

FOV가 겹치는 여러 대의 카메라로 컨베이어 벨트 위의 물체 검사

검사 대상이 카메라의 FOV에 있으면 컨베이어 벨트가 멈춥니다. 속도를 위해 캡처 프로세스를 최적화하려면 수집이 완료되면 캡처 API가 반환되기 때문에 캡처 함수를 순차적으로 호출하는 것이 좋습니다.

소스로 이동

source

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);
}

The same strategy is recommended if you are performing a 2D capture instead of a 3D capture. However, if you need both 2D and 3D, then you should check out our 2D + 3D Capture Strategy.

모든 카메라가 캡처를 마치면 장면이 카메라를 기준으로 이동할 수 있습니다. 이 예의 경우 물체가 있는 컨베이어 벨트가 움직이기 시작할 수 있습니다.

이때 데이터를 복사하고 포인트 클라우드를 연결하고 개체를 검사하는 프로세스도 시작할 수 있습니다. 이러한 작업은 순차적으로 또는 병렬로 발생할 수 있습니다. 아래의 구현 예에서는 데이터를 복사하고 병렬로 ZDF 파일에 저장하는 방법을 보여줍니다.

참고

속도를 최적화하려면 캡처 기능이 반환된 후 API를 호출하여 포인트 클라우드를 가져오기 전에 컨베이어를 이동하는 것이 중요합니다.

소스로 이동

source

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));
        }

속도를 위해 전체 프로세스를 더욱 최적화하려면 다음을 수행할 수 있습니다. 캡처 함수가 반환되는 즉시 프레임에서 다음 작업을 사용하여 다른 스레드를 시작합니다.

  • 포인트 클라우드 가져오기

  • 포인트 클라우드를 CPU 메모리에 복사

  • 필요한 경우 다른 포인트 클라우드 조작(예: 포인트 클라우드를 공통 좌표계로 변환)

아래 구현 예를 확인하십시오.

소스로 이동

source

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));
        }

그런 다음 포인트 클라우드 연결과 같은 추가 처리를 수행하려면 모든 데이터를 사용할 수 있을 때까지 기다려야 합니다.

소스로 이동

source

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를 확장하는 것임). 따라서 시간을 절약하기 위해 병렬 캡처가 가능합니다.

우리가 권장하는 캡처 전략을 설명하기 위해 컨베이어 벨트에서 큰 물체를 검사하는 예를 들어 보겠습니다.

FOV 중첩 없이 여러 대의 카메라로 컨베이어 벨트 위의 물체 검사

검사 대상이 카메라의 결합된 FOV에 있으면 컨베이어 벨트가 멈춥니다. 속도를 위해 캡처 프로세스를 최적화하려면 별도의 스레드에서 각 카메라에 대한 캡처 함수만 호출하고 모든 스레드 실행이 완료될 때까지 차단하는 것이 좋습니다. 획득이 완료되면 캡처 API가 반환되기 때문에 캡처 함수만 호출하는 것이 좋습니다.

소스로 이동

source

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);
        }

The same strategy is recommended if you are performing a 2D capture instead of a 3D capture. However, if you need both 2D and 3D, then you should check out our 2D + 3D Capture Strategy.

모든 카메라가 캡처를 마치면 장면이 카메라를 기준으로 이동할 수 있습니다. 이 예의 경우 물체가 있는 컨베이어 벨트가 움직이기 시작할 수 있습니다.

이때 데이터를 복사하고 포인트 클라우드를 연결하고 개체를 검사하는 프로세스도 시작할 수 있습니다. 이러한 작업은 순차적으로 또는 병렬로 발생할 수 있습니다. 아래의 구현 예에서는 데이터를 복사하고 병렬로 ZDF 파일에 저장하는 방법을 보여줍니다.

참고

속도를 최적화하려면 캡처 기능이 반환된 후 API를 호출하여 포인트 클라우드를 가져오기 전에 컨베이어를 이동하는 것이 중요합니다.

소스로 이동

source

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));
        }

그런 다음 포인트 클라우드 연결과 같은 추가 처리를 수행하려면 모든 데이터를 사용할 수 있을 때까지 기다려야 합니다.

소스로 이동

source

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);
}

Version History

SDK

Changes

2.11.0

2 and 2+ now support concurrent processing and acquisition for 3D ➞ 2D and 3D ➞ 2D, and switching between capture modes have been optimized.