【问题标题】:Taking image with Sapera and copying data to vector使用 Sapera 拍摄图像并将数据复制到矢量
【发布时间】:2019-02-08 11:19:25
【问题描述】:

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

【问题讨论】:

    标签: c++ image-processing camera sapera


    【解决方案1】:

    要使用 Sapera 处理相机拍摄的图像,您应该专门化 SapProcessing 类,该类用于处理缓冲区。否则缓冲区会在每一帧后自动清除,你会丢失数据。

    成像过程如下:

    1. 您在相机对象上调用Grab() 以开始成像
    2. 拍摄完每一帧后,调用传输回调。在这里,您请求您的 SapProcessing 对象来处理下一帧。
    3. 调用 SapProcessing 对象的 Run() 函数。在这里您可以从缓冲区中读取数据。
    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多