2

如何使用Sapera SDK拍摄图像并将图像数据从SapBuffer对象传输到矢量?

4

1 回答 1

3

要使用 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;
    }
}
于 2019-02-08T11:19:25.230 回答