cpp
#include "opencv2/opencv.hpp"
#include "im2d_version.h"
#include "im2d_type.h"
#include "im2d_single.h"
#include "im2d_common.h"
#include "im2d_buffer.h"
#include "RgaUtils.h"
#include "dma_alloc.h"
#include <iostream>
#include <chrono>
#include <filesystem>
using namespace std;
// 对齐宏
#define ALIGN_CEIL(x, align) ( ((x) + ((align) - 1) ) & ( ~((align) - 1) ) )
#define ALIGN_FLOOR(x, align) ( (x) & (~((align) - 1) ) )
struct LetterboxParam
{
int x_pad;
int y_pad;
float scale;
LetterboxParam()
{
x_pad = 0;
y_pad = 0;
scale = 1;
}
};
cv::Mat rga_letterbox(const cv::Mat& input_image,
LetterboxParam &letterbox_param,
int dst_width,
int dst_height,
int pad_color = 7500402)
{
int ret = 0;
if (input_image.empty())
{
printf("Error: rga_letterbox, input_image is empty!\n");
return cv::Mat();
}
if (dst_width <= 0 || dst_height <= 0)
{
printf("Error: rga_letterbox, invalid target size!\n");
return cv::Mat();
}
rga_buffer_t src_image;
rga_buffer_t padding_image;
rga_buffer_t resize_image;
rga_buffer_handle_t src_rga_buffer_handle;
rga_buffer_handle_t padding_rga_buffer_handle;
rga_buffer_handle_t resize_rga_buffer_handle;
memset(&src_image, 0, sizeof(src_image));
memset(&padding_image, 0, sizeof(padding_image));
memset(&resize_image, 0, sizeof(resize_image));
int src_width = input_image.cols;
int src_height = input_image.rows;
int src_format = RK_FORMAT_RGB_888;
if ((src_width == dst_width) and (src_height == dst_height))
{
return input_image;
}
// --- src buffer ---
int src_virtual_width = ALIGN_CEIL(src_width, 16);
int src_buf_size = src_virtual_width * src_height * get_bpp_from_format(src_format);
char *src_buf = nullptr;
int src_dma_fd = 0;
ret = dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, src_buf_size, &src_dma_fd, (void **)&src_buf);
if (ret < 0)
{
printf("Error: rga_letterbox, alloc src dma_heap buffer failed!\n");
return cv::Mat();
}
memset(src_buf, 0x00, src_buf_size);
for (int i = 0; i < src_height; ++i)
{
memcpy(src_buf + i * src_virtual_width * 3, input_image.data + i * src_width * 3, src_width * 3);
}
src_rga_buffer_handle = importbuffer_fd(src_dma_fd, src_buf_size);
if (!src_rga_buffer_handle)
{
printf("Error: rga_letterbox, importbuffer failed!\n");
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
src_image = wrapbuffer_handle(src_rga_buffer_handle, src_virtual_width, src_height, src_format);
// src_image.wstride = src_virtual_width;
// src_image.hstride = src_height;
// src_image.width = src_width;
// src_image.height = src_height;
// --- resize buffer ---
int resize_virtual_width = ALIGN_CEIL(dst_width, 16);
int resize_buf_size = resize_virtual_width * dst_height * get_bpp_from_format(src_format);
char *resize_buf = nullptr;
int resize_dma_fd = 0;
ret = dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, resize_buf_size, &resize_dma_fd, (void **)&resize_buf);
if (ret < 0)
{
printf("Error: rga_letterbox, alloc resize dma_heap buffer failed!\n");
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
memset(resize_buf, 0x00, resize_buf_size);
resize_rga_buffer_handle = importbuffer_fd(resize_dma_fd, resize_buf_size);
if (!resize_rga_buffer_handle)
{
printf("Error: rga_letterbox, importbuffer failed!\n");
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
resize_image = wrapbuffer_handle(resize_rga_buffer_handle, resize_virtual_width, dst_height, src_format);
resize_image.wstride = resize_virtual_width;
resize_image.hstride = dst_height;
resize_image.width = dst_width;
resize_image.height = dst_height;
// --- compute padding ---
int padding_x = 0;
int padding_y = 0;
float scale = 1.0;
float scale_width = float(src_width) / dst_width;
float scale_height = float(src_height) / dst_height;
char *padding_buf = nullptr;
int padding_dma_fd = 0;
int padding_buf_size = 0;
if (scale_width >= scale_height)
{
scale = scale_width;
float tmp_h = scale * dst_height;
padding_y = int(abs((tmp_h - src_height) / 2.0));
int padding_width = src_virtual_width;
int padding_height = src_height + padding_y * 2;
int padding_virtual_width = ALIGN_CEIL(padding_width, 16);
padding_buf_size = padding_virtual_width * padding_height * get_bpp_from_format(src_format);
ret = dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, padding_buf_size, &padding_dma_fd, (void **)&padding_buf);
if (ret < 0)
{
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
memset(padding_buf, 0x00, padding_buf_size);
padding_rga_buffer_handle = importbuffer_fd(padding_dma_fd, padding_buf_size);
if (!padding_rga_buffer_handle)
{
if (padding_buf) dma_buf_free(padding_buf_size, &padding_dma_fd, padding_buf);
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
padding_image = wrapbuffer_handle(padding_rga_buffer_handle, padding_virtual_width, padding_height, src_format);
// padding_image.wstride = padding_virtual_width;
// padding_image.hstride = padding_height;
// padding_image.width = src_virtual_width;
// padding_image.height = src_height + 2 * padding_y;
int padding_left = 0;
int padding_right = 0;
int paddings = padding_image.width - src_image.width;
if (paddings % 2 == 0)
{
padding_left = paddings / 2;
padding_right = padding_left;
}
else
{
padding_left = paddings / 2;
padding_right = padding_left + 1;
}
ret = immakeBorder(src_image, padding_image, padding_y, padding_y, padding_left, padding_right, IM_BORDER_CONSTANT, pad_color);
}
else
{
scale = scale_height;
float tmp_w = scale * dst_width;
padding_x = int(abs((tmp_w - src_width) / 2.0));
int padding_width = src_virtual_width + padding_x * 2;
int padding_height = src_height;
int padding_virtual_width = ALIGN_CEIL(padding_width, 16);
padding_buf_size = padding_virtual_width * padding_height * get_bpp_from_format(src_format);
ret = dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, padding_buf_size, &padding_dma_fd, (void **)&padding_buf);
if (ret < 0)
{
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
memset(padding_buf, 0x00, padding_buf_size);
padding_rga_buffer_handle = importbuffer_fd(padding_dma_fd, padding_buf_size);
if (!padding_rga_buffer_handle)
{
if (padding_buf) dma_buf_free(padding_buf_size, &padding_dma_fd, padding_buf);
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
padding_image = wrapbuffer_handle(padding_rga_buffer_handle, padding_virtual_width, padding_height, src_format);
// padding_image.wstride = padding_virtual_width;
// padding_image.hstride = padding_height;
// padding_image.width = src_virtual_width + 2 * padding_x;
// padding_image.height = src_height;
int padding_left = 0;
int padding_right = 0;
int paddings = padding_image.width - src_image.width;
if (paddings % 2 == 0)
{
padding_left = paddings / 2;
padding_right = padding_left;
}
else
{
padding_left = paddings / 2;
padding_right = padding_left + 1;
}
ret = immakeBorder(src_image, padding_image, 0, 0, padding_left, padding_right, IM_BORDER_CONSTANT, pad_color);
}
if (ret != IM_STATUS_SUCCESS)
{
printf("Error: rga_letterbox, immakeBorder failed: %s\n", imStrError((IM_STATUS)ret));
if (padding_rga_buffer_handle) releasebuffer_handle(padding_rga_buffer_handle);
if (padding_buf) dma_buf_free(padding_buf_size, &padding_dma_fd, padding_buf);
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
// 保存参数
letterbox_param.x_pad = padding_x;
letterbox_param.y_pad = padding_y;
letterbox_param.scale = scale;
ret = imresize(padding_image, resize_image);
if (ret != IM_STATUS_SUCCESS)
{
printf("Error: rga_letterbox, imresize failed: %s\n", imStrError((IM_STATUS)ret));
if (padding_rga_buffer_handle) releasebuffer_handle(padding_rga_buffer_handle);
if (padding_buf) dma_buf_free(padding_buf_size, &padding_dma_fd, padding_buf);
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return cv::Mat();
}
cv::Mat final_result = cv::Mat(dst_height, dst_width, CV_8UC3, resize_buf).clone();
// --- clean ---
if (padding_rga_buffer_handle) releasebuffer_handle(padding_rga_buffer_handle);
if (padding_buf) dma_buf_free(padding_buf_size, &padding_dma_fd, padding_buf);
if (resize_rga_buffer_handle) releasebuffer_handle(resize_rga_buffer_handle);
if (resize_buf) dma_buf_free(resize_buf_size, &resize_dma_fd, resize_buf);
if (src_rga_buffer_handle) releasebuffer_handle(src_rga_buffer_handle);
if (src_buf) dma_buf_free(src_buf_size, &src_dma_fd, src_buf);
return final_result;
}
int main()
{
printf("%s\n", querystring(RGA_ALL));
std::string test_image_file = "./1.jpg";
cv::Mat src_image = cv::imread(test_image_file);
if (src_image.data == nullptr)
{
printf("read image failed !\n");
return -1;
}
// 创建 letterbox 参数结构
LetterboxParam letterbox_param;
cv::Mat padding_image = rga_letterbox(src_image, letterbox_param, 640, 384);
if (padding_image.empty())
{
cerr << "padding operation failed!" << endl;
return -1;;
}
std::string save_file_path = "1_result.jpg";
cv::imwrite(save_file_path, padding_image);
return 0;
}
原始图片:

letterbox到640x384:
