背景
公司业务需要用到RK3588 的RGA进行图像处理加速,网上搜了下,这方面的资料很少,在此记录下自己从熟悉文档到应用的整个过程,给有相关需求的小伙伴做个参考。
一、什么是RGA
RGA (Raster Graphic Acceleration Unit)是一个独立的2D硬件加速器,可用于加速点/线绘制,执行图像缩放、旋转、格式转换等常见的2D图形操作。
二、RK3588 RGA及代码示例
2.1 从git拉取官方文档及sample示例
git clone https://github.com/airockchip/librga cd librga
其中 include 是相关头文件,libs是运行库,samples是代码示例。注意:官方demo是有默认的验证源文件,开始前先看下图对应的md文件。
2.2 图像缩放或者放大
本示例代码是在官方resize_demo的基础上进行改动、验证。说明:因为是Debian系统,安装opencv会报错,缺少libjasper库。网上搜了下比较麻烦,本人使用的先在Ubuntu先编译好的opencv库。
代码功能:使用opencv读取本地 1.jpg 图片,调用RGA resize接口进行图片缩小和放大,再使用opencv保存为新的文件。BIG宏定义是用来执行控制放大还缩操作。
#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 图像格式转换
本示例代码是在官方cvtcolor_demo的基础上进行改动、验证。
代码功能:
- 打开宏定义BGR2NV12 ,使用opencv读取本地1.jpg图片,调用RGA imcvtcolor 接口实现BGR到YUV的转换;
- 关闭宏定义BGR2NV12,读取YUV文件,调用RGA imcvtcolor 接口实现YUV到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; }