在 C++ 中优化图像缓冲区

Optimizing image buffer in C++

提问人:jlee 提问时间:11/16/2023 最后编辑:jlee 更新时间:11/16/2023 访问量:52

问:

我有 3 台(它们的名字是右、左和后)相机,我同步了它们的帧。但是,代码的性能不是那么好,我想得到一些关于如何优化代码的建议。

“优化”可以是任何东西。事实上,我希望对代码中任何可以做得更好的建议。我是这种编程的新手,只是想学习。

代码说明: 有 3 个线程运行一个繁忙的无限循环,读取相机帧。线程运行 CaptureThread 类的 start() 函数。该行从相机读取一帧。if (camera_.img_buffer->read(frame_))

class CaptureThread
{
public:
    CaptureThread(const Camera& camera) : camera_(camera)
    {
    }

    void start()
    {
        continue_thread_ = true;
        run();
    }

    void stop()
    {
        continue_thread_ = false;
    }

    void attachBufferManager(const std::shared_ptr<BufferManager>& buffer_manager)
    {
        buffer_manager_ = buffer_manager;
    }

private:
    void run()
    {
        while (continue_thread_)
        {
            if (camera_.img_buffer->read(frame_))
            {
                buffer_manager_->syncAndWrite(camera_, frame_);
            }
        }
    }

    cv::Mat frame_;
    bool continue_thread_ = true;
    Camera camera_;
    std::shared_ptr<BufferManager> buffer_manager_;
};

每个 CaptureThread 都使用 attachBufferManager function() 将自身附加到 BufferManager 的同一实例

BufferManager 通过将这些图像捆绑到 std::unordered_map 中来同步这些图像

class BufferManager
{
public:
    BufferManager(int buffer_size) : counter_(0), buffer_size_(buffer_size), num_buffers_(3)
    {
    }

    void syncAndWrite(const Camera& camera, const cv::Mat& frame)
    {
        std::unique_lock lock(mtx_);
        counter_++;
        all_img[camera.name] = frame;

        if (counter_ >= num_buffers_)
        {
            if (all_img_buffer_.size() >= buffer_size_)
            {
                all_img_buffer_.pop();
            }
            all_img_buffer_.push(all_img);
            cv_.notify_all();
            counter_ = 0;
        }
        else
        {
            cv_.wait(lock);
        }
    }

    bool read(std::unordered_map<std::string, cv::Mat>& all_img)
    {
        std::lock_guard lock(mtx_);
        if (all_img_buffer_.empty())
        {
            return false;
        }
        all_img = all_img_buffer_.front();
        all_img_buffer_.pop();
        return true;
    }

private:
    std::queue<std::unordered_map<std::string, cv::Mat>> all_img_buffer_;
    std::unordered_map<std::string, cv::Mat> all_img;
    int counter_;
    int num_buffers_;
    std::condition_variable cv_;
    std::mutex mtx_;
    int buffer_size_;
};

CaptureThread 类的无限循环调用其 BufferManager 的 syncAndWrite 函数

    void run()
    {
        while (continue_thread_)
        {
            if (camera_.img_buffer->read(frame_))
            {
                buffer_manager_->syncAndWrite(camera_, frame_);
            }
        }
    }

syncAndWrite() 将相机帧存储到 unordered_map (key=std::string, value=cv::Mat) 中,并阻塞循环,直到 BufferManager 的变量达到 3。counter_

void syncAndWrite(const Camera& camera, const cv::Mat& frame)
    {
        std::unique_lock lock(mtx_);
        counter_++;
        all_img[camera.name] = frame;

        if (counter_ >= num_buffers_)
        {
            if (all_img_buffer_.size() >= buffer_size_)
            {
                all_img_buffer_.pop();
            }
            all_img_buffer_.push(all_img);
            cv_.notify_all();
            counter_ = 0;
        }
        else
        {
            cv_.wait(lock);
        }
    }

camera.name是“right”、“left”或“back”的字符串

稍后,读取并显示 BufferManager 的all_img_buffer

while (true)
    {
        if (buffer_manager->read(all_imgs))
        {
            cv::hconcat(all_imgs["right"], all_imgs["back"], all_frame);
            cv::hconcat(all_frame, all_imgs["left"], all_frame);
            cv::imshow("all_imgs", all_frame);
            if (cv::waitKey(1) == 'q')
            {
                break;
            }
        }
    }

使用 cv::imshow() 查看 3 帧会导致感觉像是 ~10fps 的视频,这并不理想。一次查看 1 台摄像机感觉就像 ~30fps。

C++ OpenCV 缓冲区

评论

3赞 paddy 11/16/2023
不能代表 OpenCV,但我有以 250 fps 捕获和处理同步视频的经验。您希望避免以下情况:繁忙等待、轮询、由于另一个摄像机而停止来自一台摄像机的帧、在多个线程上写入磁盘。如果可以使用 OpenCV 做到这一点,请设置异步回调,以便在帧到达时通知您。使用环形缓冲区来保存帧数据。将多个相机的帧数据存储内存中(例如,制作“超级帧”)。在单个后台线程上写入磁盘。避免压缩。使用操作系统级别的 I/O 例程提高性能。基准!
1赞 paddy 11/16/2023
顺便说一句,请注意理论数据速率限制。如果这些是 USB 摄像头,请以 30fps 或其他速度计算出单个摄像头的实际比特率。然后将其与 USB 控制器的最大比特率进行比较。您可能会因此而受到限制。一种可能的解决方案是将相机拆分到单独的 USB 控制器上(硬件允许),以避免饱和。如果存储到磁盘,则应考虑类似的数据速率,因为吞吐量可能会受到严重限制。这是输出应该缓冲并与输入解耦的主要原因。

答: 暂无答案