RK3588 RGA image manipulation

background

The company's business needs to use the RGA of RK3588 for image processing acceleration. After searching the Internet, there is very little information in this area. I will record the whole process from familiarizing myself with the document to the application here, as a reference for small partners who have related needs.

1. What is RGA

RGA (Raster Graphic Acceleration Unit) is an independent 2D hardware accelerator that can be used to accelerate point/line drawing and perform common 2D graphics operations such as image scaling, rotation, and format conversion.

2. RK3588 RGA and code example

2.1 Pull official documents and samples from git

git clone https://github.com/airockchip/librga
cd librga

insert image description here
Among them, include is the relevant header file, libs is the runtime library, and samples is the code sample. Note: The official demo has a default verification source file. Before starting, look at the md file corresponding to the figure below.
insert image description here
insert image description here

2.2 Image scaling or magnification

This sample code is modified and verified on the basis of the official resize_demo. Note: Because it is a Debian system, an error will be reported when installing opencv, and the libjasper library is missing. It is troublesome to search on the Internet. I used the opencv library compiled in Ubuntu first.

insert image description here

Code function: use opencv to read the local 1.jpg image, call the RGA resize interface to reduce and enlarge the image, and then use opencv to save it as a new file. The BIG macro definition is used to perform control zoom-in and zoom-out operations.

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "im2d_version.h"
#include "im2d_type.h"
#include "im2d_single.h"
#include "im2d_common.h"
#include "im2d_buffer.h"
#include "RgaUtils.h"
#include "src/utils/utils.h"
#include "./opencv2/core/core.hpp"
#include "./opencv2/highgui/highgui.hpp"

using namespace std;
using namespace cv;

#define BIG

#ifdef BIG
#define RESIZE_WIDTH  1920
#define RESIZE_HEIGHT 1080
#define SCALE_NAME "./scale_1920_1080.jpg"
#else
#define RESIZE_WIDTH  640
#define RESIZE_HEIGHT 480
#define SCALE_NAME "./zoom_640_480.jpg"
#endif

int main(int argc, char **argv)
{
    
    
    clock_t t1, t2;
    t1 = clock();
    int ret = 0;
    int src_width, src_height, src_format;
    int dst_width, dst_height, dst_format;
    char *src_buf, *dst_buf;
    int src_buf_size, dst_buf_size;

    rga_buffer_t src_img, dst_img;
    rga_buffer_handle_t src_handle, dst_handle;

    memset(&src_img, 0, sizeof(src_img));
    memset(&dst_img, 0, sizeof(dst_img));

    Mat image, res;
	image = imread("./1.jpg");
	if (image.data == nullptr)                     
	{
    
    
		cout << "图片文件不存在" << endl;
	}

    cout << "图像宽为:" << image.cols << "\t高度为:" << image.rows << "\t通道数为:" << image.channels() << endl;
    src_width = image.cols;
    src_height = image.rows;
    src_format = RK_FORMAT_BGR_888;

    // src_format = RK_FORMAT_RGBA_8888; // RK_FORMAT_YCbCr_420_SP

    dst_width = RESIZE_WIDTH;
    dst_height = RESIZE_HEIGHT;
    dst_format = RK_FORMAT_BGR_888;


    src_buf_size = src_width * src_height * get_bpp_from_format(src_format);
    dst_buf_size = dst_width * dst_height * get_bpp_from_format(dst_format);
    cout << " src format: " << get_bpp_from_format(src_format) << endl;
    cout << " dst format: " << get_bpp_from_format(dst_format) << endl;

    src_buf = (char *)malloc(src_buf_size);
    dst_buf = (char *)malloc(dst_buf_size);


    memcpy(src_buf, image.data, src_width * src_height * get_bpp_from_format(src_format));

    memset(dst_buf, 0x80, dst_buf_size);

    src_handle = importbuffer_virtualaddr(src_buf, src_buf_size);
    dst_handle = importbuffer_virtualaddr(dst_buf, dst_buf_size);
    if (src_handle == 0 || dst_handle == 0) {
    
    
        printf("importbuffer failed!\n");
        // goto release_buffer;
        return -1;
    }

    src_img = wrapbuffer_handle(src_handle, src_width, src_height, src_format);
    dst_img = wrapbuffer_handle(dst_handle, dst_width, dst_height, dst_format);


    ret = imcheck(src_img, dst_img, {
    
    }, {
    
    });
    if (IM_STATUS_NOERROR != ret) {
    
    
        printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
        return -1;
    }
    printf("%d, check success \n", __LINE__);


    ret = imresize(src_img, dst_img);
    if (ret == IM_STATUS_SUCCESS) {
    
    
        printf("imresize running success!\n");
    } else {
    
    
        printf("running failed, %s\n", imStrError((IM_STATUS)ret));
        // goto release_buffer;
        return -1;
    }
    t2 = clock();

    double time_use = (double)(t2 - t1) / CLOCKS_PER_SEC; // 微秒
    printf("vptdt_init  time_use is [%f] s\n", time_use);
    
    res.create(RESIZE_HEIGHT, RESIZE_WIDTH, CV_8UC3);
    memcpy(res.data, dst_buf, RESIZE_HEIGHT*RESIZE_WIDTH*3);

    cv::imwrite(SCALE_NAME, res);
    printf("save picture: [ %s ] success\n", SCALE_NAME);


release_buffer:
    if (src_handle)
        releasebuffer_handle(src_handle);
    if (dst_handle)
        releasebuffer_handle(dst_handle);

    if (src_buf)
        free(src_buf);
    if (dst_buf)
        free(dst_buf);
    return ret;

    return 0;
}

2.2 Image format conversion

This sample code is modified and verified on the basis of the official cvtcolor_demo.
insert image description here
Code function:

  1. Open the macro definition BGR2NV12, use opencv to read the local 1.jpg image, and call the RGA imcvtcolor interface to realize the conversion from BGR to YUV;
  2. Close the macro definition BGR2NV12, read the YUV file, and call the RGA imcvtcolor interface to realize the conversion from YUV to BGR;
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "im2d_version.h"
#include "im2d_type.h"
#include "im2d_single.h"
#include "im2d_common.h"
#include "im2d_buffer.h"
#include "RgaUtils.h"
#include "src/utils/utils.h"
#include "./opencv2/core/core.hpp"
#include "./opencv2/highgui/highgui.hpp"

#include "./opencv4/opencv2/opencv.hpp"
using namespace std;
using namespace cv;

#define TRANSFER_FILE "./transfer.YUV"
#define RGA_WRITE_FILE "./rga_res.jpg"
#define OPENCV_WRITE_FILE "./opecv_res.jpg"
#define BGR2NV12
// #define OPENCV_TRANSFER
int main(int argc, char **argv)
{
    
    

    int ret = 0;
    int src_width, src_height, src_format;
    int dst_width, dst_height, dst_format;
    char *src_buf, *dst_buf;
    int src_buf_size, dst_buf_size;

    rga_buffer_t src_img, dst_img;
    rga_buffer_handle_t src_handle, dst_handle;

    memset(&src_img, 0, sizeof(src_img));
    memset(&dst_img, 0, sizeof(dst_img));

#ifdef BGR2NV12
    clock_t t1, t2;
    t1 = clock();
    Mat image, res;
    image = imread("./1.jpg");
    if (image.data == nullptr)
    {
    
    
        cout << "图片文件不存在" << endl;
    }

    cout << "图像宽为:" << image.cols << "\t高度为:" << image.rows << "\t通道数为:" << image.channels() << endl;
    src_width = image.cols;
    src_height = image.rows;
    src_format = RK_FORMAT_BGR_888;

    dst_width = image.cols;
    dst_height = image.rows;
    dst_format = RK_FORMAT_YCbCr_420_SP; // NV12
    cout << " src format: " << get_bpp_from_format(src_format) << endl;
    cout << " dst format: " << get_bpp_from_format(dst_format) << endl;

    src_buf_size = src_width * src_height * get_bpp_from_format(src_format);
    dst_buf_size = dst_width * dst_height * get_bpp_from_format(dst_format);

    src_buf = (char *)malloc(src_buf_size);
    dst_buf = (char *)malloc(dst_buf_size);

    memcpy(src_buf, image.data, src_width * src_height * get_bpp_from_format(src_format));

    memset(dst_buf, 0x80, dst_buf_size);

    src_handle = importbuffer_virtualaddr(src_buf, src_buf_size);
    dst_handle = importbuffer_virtualaddr(dst_buf, dst_buf_size);
    if (src_handle == 0 || dst_handle == 0)
    {
    
    
        printf("importbuffer failed!\n");
        if (src_handle)
            releasebuffer_handle(src_handle);
        if (dst_handle)
            releasebuffer_handle(dst_handle);

        if (src_buf)
            free(src_buf);
        if (dst_buf)
            free(dst_buf);
        return ret;
    }

    src_img = wrapbuffer_handle(src_handle, src_width, src_height, src_format);
    dst_img = wrapbuffer_handle(dst_handle, dst_width, dst_height, dst_format);

    ret = imcheck(src_img, dst_img, {
    
    }, {
    
    });
    if (IM_STATUS_NOERROR != ret)
    {
    
    
        printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
        return -1;
    }

    // ret = imcvtcolor(src_img, dst_img, src_format, dst_format, IM_RGB_TO_YUV_BT709_LIMIT);
    ret = imcvtcolor(src_img, dst_img, src_format, dst_format, IM_RGB_TO_YUV_BT709_LIMIT);
    if (ret == IM_STATUS_SUCCESS)
    {
    
    
        printf("imcvtcolor running success!\n");
    }
    else
    {
    
    
        printf("imcvtcolo rrunning failed, %s\n", imStrError((IM_STATUS)ret));
        if (src_handle)
            releasebuffer_handle(src_handle);
        if (dst_handle)
            releasebuffer_handle(dst_handle);

        if (src_buf)
            free(src_buf);
        if (dst_buf)
            free(dst_buf);
        return ret;
    }
    t2 = clock();
    double time_use = (double)(t2 - t1) / CLOCKS_PER_SEC; // 微秒
    printf("imcvtcolo to YUV time_use is [%f] s\n", time_use);
    FILE *file = fopen(TRANSFER_FILE, "wb+");
    if (!file)
    {
    
    
        fprintf(stderr, "Could not open %s\n", TRANSFER_FILE);
        return false;
    }
    else
    {
    
    
        fprintf(stderr, "open %s and write ok\n", TRANSFER_FILE);
    }
    fwrite(dst_buf, image.cols * image.rows * get_bpp_from_format(dst_format), 1, file);
    fclose(file);

#else
    src_width = 1920;
    src_height = 1080;
    src_format = RK_FORMAT_YCbCr_420_SP; // NV12
#ifdef OPENCV_TRANSFER

    cout << " src format: " << get_bpp_from_format(src_format) << endl;
    src_buf_size = src_width * src_height * get_bpp_from_format(src_format);

    src_buf = (char *)malloc(src_buf_size);
    FILE *file = fopen(TRANSFER_FILE, "rb");
    if (!file)
    {
    
    
        fprintf(stderr, "Could not open %s\n", TRANSFER_FILE);
        return -EINVAL;
    }
    fread(src_buf, src_width * src_height * get_bpp_from_format(src_format), 1, file);
    fclose(file);

    cv::Mat yuvNV12, rgb24;
    yuvNV12.create(src_height * 3 / 2, src_width, CV_8UC1);
    memcpy(yuvNV12.data, src_buf, src_width*src_height * 3 / 2);
    // trans to rgb24
    cv::cvtColor(yuvNV12, rgb24, cv::COLOR_YUV2BGR_NV12);

    cv::imwrite(OPENCV_WRITE_FILE, rgb24);
    printf("[OPENCV] save picture: [ %s ] success\n", OPENCV_WRITE_FILE);
    free(src_buf);
    src_buf = NULL;
#else
    clock_t t1, t2;
    t1 = clock();
    dst_width = 1920;
    dst_height = 1080;
    dst_format = RK_FORMAT_BGR_888;

    cout << "src format: " << get_bpp_from_format(src_format) << endl;
    cout << "dst format: " << get_bpp_from_format(dst_format) << endl;

    src_buf_size = src_width * src_height * get_bpp_from_format(src_format);
    dst_buf_size = dst_width * dst_height * get_bpp_from_format(dst_format);

    src_buf = (char *)malloc(src_buf_size);
    dst_buf = (char *)malloc(dst_buf_size);

    FILE *file = fopen(TRANSFER_FILE, "rb");
    if (!file)
    {
    
    
        fprintf(stderr, "Could not open %s\n", TRANSFER_FILE);
        return -EINVAL;
    }
    fread(src_buf, src_width * src_height * get_bpp_from_format(src_format), 1, file);
    fclose(file);
    printf("read src file success!\n");
    memset(dst_buf, 0x80, dst_buf_size);

    src_handle = importbuffer_virtualaddr(src_buf, src_buf_size);
    dst_handle = importbuffer_virtualaddr(dst_buf, dst_buf_size);
    if (src_handle == 0 || dst_handle == 0)
    {
    
    
        printf("importbuffer failed!\n");
        if (src_handle)
            releasebuffer_handle(src_handle);
        if (dst_handle)
            releasebuffer_handle(dst_handle);

        if (src_buf)
            free(src_buf);
        if (dst_buf)
            free(dst_buf);
        return ret;
    }

    src_img = wrapbuffer_handle(src_handle, src_width, src_height, src_format);
    dst_img = wrapbuffer_handle(dst_handle, dst_width, dst_height, dst_format);

    ret = imcheck(src_img, dst_img, {
    
    }, {
    
    });
    if (IM_STATUS_NOERROR != ret)
    {
    
    
        printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
        return -1;
    }

    ret = imcvtcolor(src_img, dst_img, src_format, dst_format, IM_YUV_TO_RGB_BT709_LIMIT);
    if (ret == IM_STATUS_SUCCESS)
    {
    
    
        printf("imcvtcolor running success!\n");
    }
    else
    {
    
    
        printf("imcvtcolo rrunning failed, %s\n", imStrError((IM_STATUS)ret));
        if (src_handle)
            releasebuffer_handle(src_handle);
        if (dst_handle)
            releasebuffer_handle(dst_handle);

        if (src_buf)
            free(src_buf);
        if (dst_buf)
            free(dst_buf);
        return ret;
    }
    t2 = clock();
    double time_use = (double)(t2 - t1) / CLOCKS_PER_SEC; // 微秒
    printf("imcvtcolo YUV to BGR time_use is [%f] s\n", time_use);
    Mat rgb24;
    rgb24.create(src_height, src_width, CV_8UC3);
    memcpy(rgb24.data, dst_buf, dst_width*dst_height*3);
    cv::imwrite(RGA_WRITE_FILE, rgb24);
    printf("[RGA] save picture: [ %s ] success\n", RGA_WRITE_FILE);
#endif // OPENCV_TRANSFER


#endif
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_46935110/article/details/129844176