当前位置:网站首页>海思3559万能平台搭建:在截获的YUV图像上旋转操作
海思3559万能平台搭建:在截获的YUV图像上旋转操作
2022-07-02 22:09:00 【快跑bug来啦】
前言
为了进一步巩固yvu格式的存放方式以及应对更多应用场景,在补充下YUV图像怎么旋转
常规算法
一般的来说,要旋转的角度无非就是90,180,270,我们只要能转到90度后进行翻转或者镜像是可以做到其他角度的,参考下图来看,第一行变成了Y13Y9Y5Y1,对应的V4U4也提到了前面,但是很明显这样的运算量或者换个角度头得多大啊
void rotateYUV420SP(unsigned char src[],unsigned char des[],int width,int height)
{
int wh = width * height;
int k = 0;
for(int i=0;i<width;i++)
{
//旋转Y
for(int j=0;j<height;j++)
{
des[k] = src[width*j + i];
k++;
}
}
for(int i=0;i<width;i+=2)
{
//旋转vu
for(int j=0;j<height/2;j++)
{
des[k] = src[wh+ width*j + i];
des[k+1]=src[wh + width*j + i+1];
k+=2;
}
}
}
HI_MPI_VPSS_SetChnRotation
海思也自然考虑到了这点,自己底层有硬件加速,很方便的提供了相应的旋转函数HI_MPI_VPSS_SetChnRotation和任意角度的HI_MPI_VPSS_SetChnRotationEx,只需要提供vpss的group,chnl和旋转角度即可,用起来还是非常方便的,在vpss初始化之后调用
s32Ret = HI_MPI_VPSS_SetChnRotation(VpssGrp, VpssChn[1], ROTATION_90);
if(s32Ret != HI_SUCCESS)
{
printf("HI_MPI_VPSS_SetChnRotation failed with %#x\n", s32Ret);
return HI_FAILURE;
}
注意事项
需要注意的是保存输出的时候一定一定不要忘记修改编码通道的分辨率!不然会报获取不到图像的错误!当时刚好因为dump例程的问题,直接在vpss后保存了yuv,只有y分量正确,uv惨不忍睹。还好在大佬的点醒下,想到venc压根就没配这部分!(同理的还有下一篇记录的YUV422编码获取不到的问题)
通道 AUTO 模式下不支持。
仅支持 semi-planar 420 和单分量像素格式。
(后面两个注意事项手册上有,细心点很容易发现)
补充算法
参考博客
https://blog.csdn.net/huangjiazhi_/article/details/103960883
// Yuv420pRotate.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
// clockwise 顺时针
// contrarotate 逆时针旋转
// flip horizontal 镜像翻转/水平翻转
/** * 顺时针旋转90。 * 取元素:从左下方第一个点开始,从下往上,从左往右取点; * 放元素:从左上方第一个位置开始放,从左往右,从上往下;把每一列转换成每一行。 * * @param yuvFileaName 一帧YUV420P格式的文件 * @param width 图像的宽 * @param height 图像的高 * * @return 空 */
void clockwiseRotate90(const char* yuvFileaName, int width, int height){
FILE* fp = NULL;
fopen_s(&fp, yuvFileaName, "rb");
unsigned char* yuvbuf = new unsigned char[width*height * 3 / 2];
fread(yuvbuf, width*height * 3 / 2, 1, fp);
fclose(fp);
int idx = 0;
//Y
unsigned char* dstbuf = new unsigned char[width*height * 3 / 2];
for (int i = 0; i <= width - 1; i++){
for (int j = height - 1; j >= 0; j--){
dstbuf[idx++] = *(yuvbuf + (j*width + i));
}
}
//U
unsigned char* uheader = yuvbuf + width*height;
int hw = width / 2;
int hh = height / 2;
for (int i = 0; i <= hw - 1; i++){
for (int j = hh - 1; j >= 0; j--){
dstbuf[idx++] = *(uheader + (j*hw + i));
}
}
//V
unsigned char* vheader = uheader + width*height / 4;
for (int i = 0; i <= hw - 1; i++){
for (int j = hh - 1; j >= 0; j--){
dstbuf[idx++] = *(vheader + (j*hw + i));
}
}
FILE* fpout = NULL;
fopen_s(&fpout, "clockwiseRotate90.yuv", "wb");
fwrite(dstbuf, width*height * 3 / 2, 1, fpout);
fclose(fpout);
delete[] yuvbuf;
delete[] dstbuf;
}
/** * 逆时针旋转90。 * 取元素:从右上方第一个点开始,从上往下,从右往左取点; * 放元素:从左上方第一个位置开始放,从左往右,从上往下;把每一列转换成每一行。 * * @param yuvFileaName 一帧YUV420P格式的文件 * @param width 图像的宽 * @param height 图像的高 * * @return 空 */
void contrarotate90(const char* yuvFileaName, int width, int height)
{
int i, j, k, p;
FILE* fp = NULL;
fopen_s(&fp, yuvFileaName, "rb");
unsigned char* yuvbuf = new unsigned char[width*height * 3 / 2];
fread(yuvbuf, width*height * 3 / 2, 1, fp);
fclose(fp);
unsigned char* dstbuf = new unsigned char[width*height * 3 / 2];
char* dest = (char*)dstbuf;
char* src = (char*)yuvbuf;
// rotate Y
for (j = 0; j < width; j++){
for (i = 1; i <= height; i++){
*dest++ = *(src + i*width - j);
}
}
// rotate U
char *src_u = src + width*height;
for (p = 0; p < width / 2; p++){
for (k = 1; k <= height / 2; k++){
*dest++ = *(src_u + k*width / 2 - p);
}
}
// rotate V
char *src_v = src + width*height * 5 / 4;
for (p = 0; p < width / 2; p++){
for (k = 1; k <= height / 2; k++){
*dest++ = *(src_v + k*width / 2 - p);
}
}
FILE* fpout = NULL;
fopen_s(&fpout, "contrarotate90.yuv", "wb");
fwrite(dstbuf, width*height * 3 / 2, 1, fpout);
fclose(fpout);
delete[] yuvbuf;
delete[] dstbuf;
}
/** * 逆时针180。 * 取元素:从右下方第一个点开始,从右往左,从下往上取点; * 放元素:从左上方第一个位置开始放,从左往右,从上往下; * * @param yuvFileaName 一帧YUV420P格式的文件 * @param width 图像的宽 * @param height 图像的高 * * @return 空 */
void contrarotate180(const char* yuvFileaName, int width, int height){
FILE* fp = NULL;
fopen_s(&fp, yuvFileaName, "rb");
unsigned char* yuvbuf = new unsigned char[width*height * 3 / 2];
fread(yuvbuf, width*height * 3 / 2, 1, fp);
fclose(fp);
int idx = 0;
//Y
unsigned char* dstbuf = new unsigned char[width*height * 3 / 2];
for (int i = height - 1; i >= 0; i--){
for (int j = width - 1; j >= 0; j--){
dstbuf[idx++] = *(yuvbuf + (i*width + j));
}
}
//U
unsigned char* uheader = yuvbuf + width*height;
for (int i = height / 2 - 1; i >= 0; i--){
for (int j = width / 2 - 1; j >= 0; j--){
dstbuf[idx++] = *(uheader + (i*width / 2 + j));
}
}
unsigned char* vheader = uheader + width*height / 4;
//V
for (int i = height / 2 - 1; i >= 0; i--){
for (int j = width / 2 - 1; j >= 0; j--){
dstbuf[idx++] = *(vheader + (i*width / 2 + j));
}
}
FILE* fpout = NULL;
fopen_s(&fpout, "contrarotate180.yuv", "wb");
fwrite(dstbuf, width*height * 3 / 2, 1, fpout);
fclose(fpout);
delete[] yuvbuf;
delete[] dstbuf;
}
/** * 镜像翻转/水平翻转 * 取元素:将右上角的点作为第一个点,从右往左,从上往下取点; * 放元素:从左上方第一个位置开始放,从左往右,从上往下; * * @param yuvFileaName 一帧YUV420P格式的文件 * @param width 图像的宽 * @param height 图像的高 * * @return 空 */
void flipHorizontal(const char* yuvFileaName, int width, int height)
{
FILE* fp = NULL;
fopen_s(&fp, yuvFileaName, "rb");
unsigned char* yuvbuf = new unsigned char[width*height * 3 / 2];
fread(yuvbuf, width*height * 3 / 2, 1, fp);
fclose(fp);
int idx = 0;
//Y
unsigned char* dstbuf = new unsigned char[width*height * 3 / 2];
for (int i = 0; i < height; i++){
for (int j = width - 1; j >= 0; j--){
dstbuf[idx++] = *(yuvbuf + (i*width + j));
}
}
//U
unsigned char* uheader = yuvbuf + width*height;
for (int i = 0; i < height / 2; i++){
for (int j = width / 2 - 1; j >= 0; j--){
dstbuf[idx++] = *(uheader + (i*width / 2 + j));
}
}
//V
unsigned char* vheader = uheader + width*height / 4;
for (int i = 0; i < height / 2; i++){
for (int j = width / 2 - 1; j >= 0; j--){
dstbuf[idx++] = *(vheader + (i*width / 2 + j));
}
}
FILE* fpout = NULL;
fopen_s(&fpout, "flipHorizontal.yuv", "wb");
fwrite(dstbuf, width*height * 3 / 2, 1, fpout);
fclose(fpout);
delete[] yuvbuf;
delete[] dstbuf;
}
/** * 逆时针旋转180后,再水平翻转/镜像。 * 取元素:从左下方第一个点开始,从左往右,从下往上取点; * 放元素:从左上方第一个位置开始放,从左往右,从上往下; * * @param yuvFileaName 一帧YUV420P格式的文件 * @param width 图像的宽 * @param height 图像的高 * * @return 空 */
void contrarotate180AndFlipHorizontal(const char* yuvFileaName, int width, int height){
FILE* fp = NULL;
fopen_s(&fp, yuvFileaName, "rb");
unsigned char* yuvbuf = new unsigned char[width*height * 3 / 2];
fread(yuvbuf, width*height * 3 / 2, 1, fp);
fclose(fp);
int idx = 0;
//Y 宽
unsigned char* dstbuf = new unsigned char[width*height * 3 / 2];
for (int i = height - 1; i >= 0; i--){
for (int j = 0; j <= width - 1; j++){
dstbuf[idx++] = *(yuvbuf + (i*width + j));
}
}
//U
unsigned char* uheader = yuvbuf + width*height;
for (int i = height / 2 - 1; i >= 0; i--){
for (int j = 0; j <= width / 2 - 1; j++){
dstbuf[idx++] = *(uheader + (i*width / 2 + j));
}
}
//V
unsigned char* vheader = uheader + width*height / 4;
for (int i = height / 2 - 1; i >= 0; i--){
for (int j = 0; j <= width / 2 - 1; j++){
dstbuf[idx++] = *(vheader + (i*width / 2 + j));
}
}
FILE* fpout = NULL;
fopen_s(&fpout, "contrarotate180AndFlipHorizontal.yuv", "wb");
fwrite(dstbuf, width*height * 3 / 2, 1, fpout);
fclose(fpout);
delete[] yuvbuf;
delete[] dstbuf;
}
int _tmain(int argc, _TCHAR* argv[])
{
const char* yuvFileaName = "yuv420p.yuv";
int w = 160;
int h = 128;
clockwiseRotate90(yuvFileaName, w, h);
contrarotate90(yuvFileaName, w, h);
contrarotate180(yuvFileaName, w, h);
flipHorizontal(yuvFileaName, w, h);
contrarotate180AndFlipHorizontal(yuvFileaName, w, h);
return 0;
}
边栏推荐
- 解决 excel 文件上传时更改选中的文件出现错误net::ERR_UPLOAD_FILE_CHANGED
- 附加:【登录信息存储】与【登录状态校验】;(包括:总结了到目前为止,有关【登录信息存储】与【登录状态校验】的所有内容;)
- [LeetCode] 回文数【9】
- [autosar-dcm] - 4.3-how UDS $22 and $2e services read and write NVM data
- 'when to use const char * and when to use const char []' - when to use const char * and when to use const char []
- 钟薛高回应产品1小时不化:含固体成分 融化不能变成水
- Jerry's modification does not require long press the boot function [chapter]
- Introduction and response to high concurrency
- 高并发介绍及应对
- Storage unit conversion
猜你喜欢
随机推荐
Methods of adding styles to native JS
Graphic view frame
[micro service sentinel] rewrite Sentinel's interface blockexceptionhandler
[leetcode] there are duplicate elements [217]
Golang's learning route
中国信通院、清华大学、腾讯安全,云原生安全产学研用强强联合!
go 4種單例模式
附加:【登录信息存储】与【登录状态校验】;(包括:总结了到目前为止,有关【登录信息存储】与【登录状态校验】的所有内容;)
杰理之充电拔出,无法触摸开机【篇】
`Usage of ${}`
Mathematical modeling -- graph and network models and methods (I)
The kth largest element in the [leetcode] array [215]
[leetcode] number of palindromes [9]
杰理之样机在多次触摸后会触发关机【篇】
WebRTC音视频采集和播放示例及MediaStream媒体流解析
位的高阶运算
送给即将工作的自己
數據分析學習記錄--用EXCEL完成簡單的單因素方差分析
Qt QProgressBar详解
Task and privilege level protection