Съемка изображения с помощью Sapera и копирование данных в вектор - PullRequest
0 голосов
/ 08 февраля 2019

Как взять изображения с помощью Sapera SDK и перенести данные изображения из объекта SapBuffer в вектор?

1 Ответ

0 голосов
/ 08 февраля 2019

Для обработки изображений, снятых камерой с помощью Sapera, вы должны определить специализацию класса SapProcessing, который используется для обработки буферов.В противном случае буфер очищается автоматически после каждого кадра, и вы теряете данные.

Процесс формирования изображения происходит следующим образом:

  1. Вы вызываете Grab() на объекте камеры, чтобы начать формирование изображения
  2. После каждого кадра вызывается обратный вызов передачи.Здесь вы запрашиваете ваш SapProcessing объект для обработки следующего кадра.
  3. Run() вызывается функция вашего SapProcessing объекта.Здесь вы можете прочитать данные из буфера.
  4. После функции Run() вызывается обратный вызов обработки.
  5. Когда вы получили достаточно кадров, вызовите Freeze(), чтобы остановить формирование изображения.

В этом примере кода снимаются изображения с использованием настроек камеры по умолчанию (монохромный 8-разрядный формат пикселей).

#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include <atomic>
#include "SapClassBasic.h"

// Helper function to find the camera by its serial number
SapAcqDevice getDeviceBySN(const std::string& sn)
{
    char serverName[CORSERVER_MAX_STRLEN];
    char serialNumberName[2048];

    const int serverCount = SapManager::GetServerCount();
    for (int i = 0; i < serverCount; i++) {
        if (SapManager::GetResourceCount(i, SapManager::ResourceAcqDevice) != 0)
        {
            SapManager::GetServerName(i, serverName, sizeof(serverName));

            SapAcqDevice camera(serverName);
            if (!camera.Create()) {
                throw std::runtime_error("Failed to create camera object.");
            }
            int featureCount;
            if (camera.GetFeatureCount(&featureCount) && featureCount > 0)
            {
                if (camera.GetFeatureValue("DeviceID", serialNumberName, sizeof(serialNumberName))
                    && serialNumberName == sn)
                {
                    return camera;
                }
            }
            camera.Destroy();
        }
    }
    const auto errorStr = "Camera \"" + sn + "\" was not found.";
    throw std::runtime_error(errorStr.c_str());
}

class SapMyProcessing : public SapProcessing
{
public:
    SapMyProcessing(SapBuffer* pBuffers, SapProCallback pCallback, void* pContext);
    virtual ~SapMyProcessing();

protected:
    virtual BOOL Run();
};

SapMyProcessing::SapMyProcessing(SapBuffer* pBuffers, SapProCallback pCallback, void* pContext)
    : SapProcessing(pBuffers, pCallback, pContext)
{}

SapMyProcessing::~SapMyProcessing()
{
    if (m_bInitOK) Destroy();
}

BOOL SapMyProcessing::Run()
{
    // Get the current buffer index
    const int proIndex = GetIndex();

    // If this is not true, buffer has overflown
    SapBuffer::State state;
    bool goodContent = m_pBuffers->GetState(proIndex, &state)
        && state == SapBuffer::StateFull;

    if (goodContent) {
        void *inAddress = nullptr;
        m_pBuffers->GetAddress(proIndex, &inAddress);
        int inSize = 0;
        m_pBuffers->GetSpaceUsed(proIndex, &inSize);

        // Width, height and pixel format are received from the camera
        const int width = m_pBuffers->GetWidth();
        const int height = m_pBuffers->GetHeight();
        const auto format = m_pBuffers->GetFormat();
        const int outSize = width * height;

        // Skip unexpected pixel format or incomplete frame
        goodContent = format == SapFormatMono8
            && inSize == outSize;

        if (goodContent) {
            // Copy data to vector
            std::vector<uint8_t> outBuffer(outSize);
            std::copy((uint8_t*)inAddress, (uint8_t*)(inAddress) + outSize, outBuffer.begin());

            // Print the first line
            for (int i = 0; i < width; i++) {
                std::cout << std::hex << int(outBuffer[i]);
            }
            std::cout << std::endl << std::endl;
        }
    }

    return TRUE;
}

// Information to pass to callbacks
struct TransferContext {
    std::atomic_int frameGrabCount = 0, frameProcessingCount = 0;
    std::shared_ptr<SapMyProcessing> processing;
};

void transferCallback(SapXferCallbackInfo *info)
{
    auto context = (TransferContext*)info->GetContext();

    context->frameGrabCount++;
    if (!info->IsTrash()) {
        // Execute Run() for this frame
        context->processing->ExecuteNext();
    }
}

// Processing callback is called after Run()
void processingCallback(SapProCallbackInfo* info)
{
    auto context = (TransferContext*)info->GetContext();

    // Processing has finished
    context->frameProcessingCount++;
}

// The main imaging function
void grab(const std::string& serialNumber)
{
    // Number of frames to receive from the camera
    const int maxFrameCount = 10;

    TransferContext context;

    auto camera = getDeviceBySN(serialNumber);
    std::unique_ptr<SapBuffer> buffer
        = std::make_unique<SapBufferWithTrash>(maxFrameCount, &camera);
    std::unique_ptr<SapTransfer> transfer
        = std::make_unique<SapAcqDeviceToBuf>(&camera, buffer.get(), transferCallback, &context);
    context.processing = std::make_shared<SapMyProcessing>(buffer.get(), processingCallback, &context);

    auto cleanup = [&]() {
            if (context.processing) context.processing->Destroy();
            if (transfer) transfer->Destroy();
            if (buffer) buffer->Destroy();
            camera.Destroy();
        };

    try {
        if (!buffer->Create()) {
            throw std::runtime_error("Failed to create buffer object.");
        }
        if (!transfer->Create()) {
            throw std::runtime_error("Failed to create transfer object.");
        }
        if (!context.processing->Create()) {
            throw std::runtime_error("Failed to create processing object.");
        }
        transfer->SetAutoEmpty(false);
        context.processing->SetAutoEmpty(true);
        context.processing->Init();

        transfer->Grab();

        // Wait for the camera to grab all frames
        while (context.frameGrabCount < maxFrameCount);

        transfer->Freeze();
        if (!transfer->Wait(5000)) {
            throw std::runtime_error("Failed to stop grab.");
        }

        // Wait for processing to complete
        while (context.frameProcessingCount < maxFrameCount);

        cleanup();
    }
    catch (...) {
        cleanup();
        throw;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...