概述
RGA (Raster Graphic Acceleration Unit) 是一个独立的 2D 硬件加速器,可用于加速点/线绘制,执行图像缩放、旋转、bitBlt、alpha 混合等常见的 2D 图形操作。假设驱动环境已就绪,可直接使用。
环境准备
1. 查看驱动版本
cat /sys/kernel/debug/rkrga/driver_version
2. 下载测试代码
参考 GitHub 仓库:TRQ-UP/Rk3588-linux-rga
代码实现
1. CMakeLists.txt 配置
后续 RGA 或 OpenCV 的更新版本,直接放到 3rdparty 文件夹中,在 CMakeLists 中配置即可。
cmake_minimum_required(VERSION 3.16)
project(opencv_411_test)
set(CMAKE_CXX_STANDARD 11)
# 设置库架构
set(LIB_ARCH "aarch64")
set(DEVICE_NAME "RK3588")
# 设置 OpenCV 路径
set(OpenCV_DIR ./3rdparty/opencv/opencv-linux-aarch64/share/OpenCV)
find_package(OpenCV REQUIRED)
# 输出 OpenCV 信息
message(STATUS "OpenCV include dirs: ${OpenCV_INCLUDE_DIRS}")
message(STATUS "Found OpenCV Version: ${OpenCV_VERSION}")
set(3RDPARTY_PATH ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty)
# 设置 RGA 的路径
set(RGA_DIR ${3RDPARTY_PATH}/rga/${DEVICE_NAME})
set(RGA_LIB ${RGA_DIR}/lib/Linux/${LIB_ARCH}/librga.so)
# 用来搜索头文件的目录
include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${RGA_DIR}/include)
# 编译源代码
add_executable(opencv_411_test src/main.cpp)
# 链接 OpenCV 和 RGA 库
target_link_libraries(opencv_411_test ${OpenCV_LIBS} ${RGA_LIB})
2. 主程序逻辑
完整功能请参考 RGA IM2D API 开发指南。
使用 RGA 的基本步骤:
- 定义图像缓冲区的描述结构体(如
rga_buffer_t)。 - 初始化这些结构体(通常通过
memset清零)。 - 创建或获取图像缓冲区的句柄(如
rga_buffer_handle_t)。 - 使用这些结构体和句柄进行图像处理操作(如缩放、旋转、格式转换等)。
#include "opencv2/opencv.hpp"
#include <iostream>
#include "im2d_version.h"
#include "im2d_type.h"
#include "im2d_single.h"
#include "im2d_common.h"
#include "im2d_buffer.h"
#include "RgaUtils.h"
using namespace std;
const char* querystring(int name);
/* RGA_VENDOR - 厂商信息
RGA_VERSION - 版本信息
RGA_MAX_INPUT - 支持的最大输入分辨率
RGA_MAX_OUTPUT - 支持的最大输出分辨率
RGA_SCALE_LIMIT - 支持的缩放倍数
RGA_INPUT_FORMAT - 支持的输入格式
RGA_OUTPUT_FORMAT - 支持的输出格式
RGA_EXPECTED - 预期性能
RGA_ALL - 输出所有信息 */
void print_rga_info() {
cout << querystring(RGA_ALL) << endl;
}
int main(int argc, char **argv) {
// 输出 RGA 的信息
print_rga_info();
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));
// 使用 OpenCV 读取图片
cv::Mat image, res;
image = cv::imread("../img/test.jpg");
if (image.data == nullptr) {
cout << "图片文件不存在" << endl;
return -1;
}
cout << "图像宽为:" << image.cols << "\t高度为:" << image.rows << "\t通道数为:" << image.channels() << endl;
cv::Mat opencv_resize;
cv::resize(image, opencv_resize, cv::Size(1920, 1080));
cv::imwrite("../img/opencv_resize.jpg", opencv_resize);
// 设置源图像的宽度、高度和格式
src_width = image.cols;
src_height = image.rows;
src_format = RK_FORMAT_RGB_888;
// 设置目标图像的宽度、高度和格式
dst_width = 1920;
dst_height = 1080;
dst_format = RK_FORMAT_RGB_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);
// 使用 malloc 分配内存给源图像和目标图像的缓冲区
src_buf = (char *)malloc(src_buf_size);
dst_buf = (char *)malloc(dst_buf_size);
cout << "src format: " << get_bpp_from_format(src_format) << endl;
cout << "dst format: " << get_bpp_from_format(dst_format) << endl;
// 将源图像数据从 OpenCV 的 cv::Mat 对象复制到自定义的缓冲区 src_buf 中
memcpy(src_buf, image.data, src_width * src_height * get_bpp_from_format(src_format));
memset(dst_buf, 0x80, dst_buf_size);
// 使用 importbuffer_virtualaddr 将源图像和目标图像的缓冲区导入为 RGA 可识别的句柄
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");
return -1;
}
// 使用 wrapbuffer_handle 将句柄包装为 rga_buffer_t 结构体
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__);
// 图像翻转
/* 图片镜像
0:不变
IM_HAL_TRANSFORM_FLIP_H:左右翻转
IM_HAL_TRANSFORM_FLIP_V:上下翻转 */
ret = imflip(src_img, dst_img, 0);
if (ret == IM_STATUS_SUCCESS) {
printf("imflip running success!\n");
} else {
printf("running failed, %s\n", imStrError((IM_STATUS)ret));
return -1;
}
// 将 rk 格式的图片转成 OpenCV 识别的图片格式并保存
res.create(dst_height, dst_width, CV_8UC3);
memcpy(res.data, dst_buf, dst_height * dst_width * 3);
cv::imwrite("../img/result.jpg", res);
printf("save picture: [ %s ] success\n", "../img/result.jpg");
// 释放资源
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;
}
运行结果
[图片:原始图片] 原始图片 |
[图片:OpenCV 处理结果] opencv-resize |
[图片:RGA 处理结果] rga-resize |

