From 4b1d623b8f6d6b5cc684e2b3f009208814531c69 Mon Sep 17 00:00:00 2001 From: gftrobots Date: Tue, 16 Jul 2024 19:22:36 +0200 Subject: [PATCH] Create cv_template_stage For opencv developers it is not intuitive how use the post processor stage in RGB or BGR color space. This example shows how to use the post processor stage for other color spaces and use cases. The sobel stage has been used as a template with only minor modifications. --- post_processing_stages/cv_template_stage | 111 +++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 post_processing_stages/cv_template_stage diff --git a/post_processing_stages/cv_template_stage b/post_processing_stages/cv_template_stage new file mode 100644 index 00000000..22470629 --- /dev/null +++ b/post_processing_stages/cv_template_stage @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2021, Raspberry Pi (Trading) Limited + * + * cv_template_stage.cpp - Sobel filter implementation, using OpenCV + */ + +#include +#include + +#include "core/rpicam_app.hpp" + +#include "post_processing_stages/post_processing_stage.hpp" + +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/opencv.hpp" + +using namespace cv; + +using Stream = libcamera::Stream; + +class CvTemplateStage : public PostProcessingStage +{ +public: + CvTemplateStage(RPiCamApp *app) : PostProcessingStage(app) {} + + char const *Name() const override; + + void Read(boost::property_tree::ptree const ¶ms) override; + + void Configure() override; + + bool Process(CompletedRequestPtr &completed_request) override; + +private: + Stream *stream_; + int some_config_value_ = 99; +}; + +#define NAME "cv_template" + +char const *CvTemplateStage::Name() const +{ + return NAME; +} + +void CvTemplateStage::Read(boost::property_tree::ptree const ¶ms) +{ + some_config_value_ = params.get("some_config_value", 99); +} + +void CvTemplateStage::Configure() +{ + + stream_ = app_->GetMainStream(); + + // opencv requires YUV420 format + if (!stream_ || stream_->configuration().pixelFormat != libcamera::formats::YUV420) + throw std::runtime_error("CvTemplateStage: only YUV420 format supported"); + +} + +bool CvTemplateStage::Process(CompletedRequestPtr &completed_request) +{ + + // get stream info: height, width, stride + StreamInfo src_info = app_->GetStreamInfo(stream_); + + // define stream info for RGB image + StreamInfo rgb_info; + rgb_info.width = src_info.width; + rgb_info.height = src_info.height; + rgb_info.stride = rgb_info.width * 3; + + // get the frame buffer + BufferWriteSync w(app_, completed_request->buffers[stream_]); + libcamera::Span buffer = w.Get()[0]; + + // convert YUV420 frame buffer to RGB output + std::vector output(rgb_info.height * rgb_info.stride); + Yuv420ToRgb(output.data(), buffer.data(), src_info, rgb_info); + uint8_t *ptr = (uint8_t *)output.data(); + + // note: the output is decoupled from the frame buffer + // modifications will not be visible in the preview window + // you are not responsible for any type of display or other output + + // convert RGB buffer to rgb Mat + Mat rgb = Mat(rgb_info.height, rgb_info.width, CV_8UC3, ptr, rgb_info.stride); + Mat bgr; + + // convert RGB Mat to BGR Mat (opencv internal format) + cvtColor(rgb, bgr, COLOR_RGB2BGR); + + // cv image procesing here ... + // for example, apply filter, threshold, etc. + // save your data + // std::string filename = "dummy_output_.jpg"; + // imwrite(filename, bgr); + // note: display data with imshow is not possible in this process loop + + return false; +} + +static PostProcessingStage *Create(RPiCamApp *app) +{ + return new CvTemplateStage(app); +} + +static RegisterStage reg(NAME, &Create);