YUV420P旋转

2023-05-16

YUV420与YUV420P

YUV 和我们熟知的 RGB 类似,是一种颜色编码格式。它主要用于电视系统和模拟视频邻域(如 Camera 系统)。

YUV 包含三个分量,其中 Y 表示明亮度(Luminance 或 Luma),也就是灰度值。而 U 和 V 则表示色度(Chrominance 或 Chroma),作用是描述图像色彩及饱和度,用于指定像素的颜色。没有 UV 分量信息,一样可以显示完整的图像,只不过是黑白的灰度图像。YUV 格式的好处是很好地解决了彩色电视机与黑白电视机的兼容问题。而且 YUV 不像 RGB 那样要求三个独立的视频信号同时传输,所以用 YUV 方式传送占用极少的频宽。

YUV 格式包含两大类,分别为 planar 和 packed:
1)对于 planar 格式,先连续存储所有像素点的 Y 分量,紧接着存储所有像素点的 U 分量,最后是所有像素点的 V 分量;
2)对于 packed 格式,和 planar 格式一样,也是先连续存储所有像素点的 Y 分量,紧接着存储所有像素点的 UV 分量。不同的是,UV 分量是交替存放的。

在 YUV420 中,一个像素点对应一个 Y 分量,一个 2x2 的小方块对应一个 U 和 V,上面两种格式的 Y 值在排列是完全相同的(只有 Y 的图像就是灰度图像)。

420p 它是先存放完 U 分量,再存放 V 放量,也就是说他们的 UV 分量是连续的。

假设原始图像的宽度和高度分别使用 w 和 h 表示,旋转前的图像尺寸是 wh,旋转后的图像尺寸是 hw,旋转前后图像大小保持不变。对于 YUV420p 数据格式,其数据在内存中安排如下:
图像占用的内存空间大小: w * h * 3 / 2;
1)Y 分量占用的内存大小为 w * h,从内存起始位置开始存放;
2)Y 分量中每个 2x2 的小方块对应一个 U 和 V;
3)U 分量大小为 (w/2)(h/2),存放的位置从图像的 w * h 偏移位置开始;
4)V 分量大小为 (w/2)(h/2),存放的位置从图像的 w * h + (w * h)/4 偏移位置开始。

YUV420p 格式

这些数据在内存中是线性存储的。当使用图片浏览器显示的是时候需要指定它们的尺寸(宽度和高度),否则不能正确显示。例如,40x30 和 20x60 这两张图像的像素点的个数相同,但如果把 40x30 的图像按照 20x60 的图像来显示,就会出现显示异常。

在这里插入图片描述
YUV420p 旋转 90 度

把 YUV420p 的图像顺时针旋转 90 度后,Y 分量在内存中存放如下图所示,随后是连续的 U 分量 和 V 分量。

在这里插入图片描述 

 旋转步骤如下,把图像看作是一个类似 image[w][h] 的二维数组。
1)先处理 Y 分量,原始图像的第一个像素位置为 (h-1)*w,旋转后的目标位置为 (0, 0);第二个像素位置为 (h-2)*w,旋转后的目标位置为 (0, 1),以此类推;
2)接下来处理 U 分量,U 和 V 分量的大小都为 (w/2)*(h/2)。原图的第一个像素位置为 (w*h)+(((h/2)-1)*(w/2)),旋转后的目标位置为(w*h)+(0, 0);第二个像素位置为 (w*h)+(((h/2)-2)*(w/2)),旋转后的目标位置为 (w*h)+(0, 1),以此类推;
3)最后处理 V 分量。原图的第一个像素位置为 (w*h)+(w*h/4)+(((h/2)-1)*(w/2)),旋转后的目标位置为 (w*h)+(w*h/4)+(0, 0);第二个像素位置为 (w*h)+(w*h/4)+(((h/2)-2)*(w/2)),旋转后的目标位置为 (w*h)+(w*h/4)+(0, 1),以此类推。

void YUV420p_Rotate_90(BYTE* &des, BYTE* &src, int width, int height)
{
    int n = 0;
    int wh = width * height;
    //y
    for (int j = 0; j < width; j++)
    {
        for(int i = height - 1; i >= 0; i--)
        {
            des[n++] = src[width * i + j];
        }
    }
    //u
    for (int i = 0; i < width / 2; i++)
    {
        for (int j = 1; j <= height / 2; j++)
        {
            des[n++] = src[wh + ((height/2 - j) * (width / 2) + i)];
        }
    }
    //v
    for(int i = 0; i < width / 2; i++)
    {
        for(int j = 1; j <= height / 2; j++)
        {
            des[n++] = src[wh + wh / 4 + ((height / 2 - j) * (width / 2) + i)];
        }
    }
}


YUV420p 旋转 180 度

void YUV420p_Rotate_180(BYTE* &des, BYTE* &src, int width, int height)
{
    int n = 0;
    int hw = width / 2;
    int hh = height / 2;
    //copy y
    for(int j = height - 1; j >= 0; j--)
    {
        for(int i = width; i > 0; i--)
        {
            des[n++] = src[width*j + i];
        }
    }

    //copy u
    BYTE *ptemp = src + width * height;
    for(int j = hh - 1;j >= 0; j--)
    {
        for(int i = hw; i > 0; i--)
        {
            des[n++] = ptemp[hw * j + i];
        }
    }

    //copy v
    ptemp += width * height / 4;
    for(int j = hh - 1;j >= 0; j--)
    {
        for(int i = hw; i > 0; i--)
        {
            des[n++] = ptemp[hw * j + i];
        }
    }
}


YUV420p 旋转 270 度

void YUV420p_Rotate_270(BYTE* &des, BYTE* &src, int width, int height)
{
    int n = 0;
    int hw = width / 2;
    int hh = height / 2;
    //copy y
    for(int j = width; j > 0; j--)
    {
        for(int i = 0; i < height;i++)
        {
            des[n++] = src[width*i + j];
        }
    }

    //copy u
    BYTE *ptemp = src + width * height;
    for(int j = hw; j > 0;j--)
    {
        for(int i = 0; i < hh;i++)
        {
            des[n++] = ptemp[hw * i + j];
        }
    }

    //copy v
    ptemp += width * height / 4;
    for(int j = hw; j > 0;j--)
    {
        for(int i = 0; i < hh;i++)
        {
            des[n++] = ptemp[hw * i + j];
        }
    }
}


YUV420p 水平镜像

void YUV420p_Flip_Horizontal(BYTE* &des, BYTE* &src, int width, int height)  
{  
    int n = 0;  
    int hw = width / 2;  
    int hh = height / 2;  
    //copy y  
    for(int j = 0; j < height; j++)  
    {  
        for(int i = width - 1;i >= 0;i--)  
        {  
            des[n++] = src[width * j + i];  
        }  
    }  
  
    //copy u  
    BYTE *ptemp = src + width * height;  
    for(int j = 0; j < hh; j++)  
    {  
        for(int i = hw - 1;i >= 0;i--)  
        {  
            des[n++] = ptemp[hw * j + i];  
        }  
    }  
      
    //copy v  
    ptemp += width * height / 4;  
    for(int j = 0; j < hh; j++)  
    {  
        for(int i = hw - 1;i >= 0;i--)  
        {  
            des[n++] = ptemp[hw * j + i];  
        }  
    }  
}  

YUV420p 垂直镜像

void YUV420p_Flip_Vertical(BYTE* &des, BYTE* &src, int width, int height)  
{  
    int n = 0;  
    int hw = width / 2;  
    int hh = height / 2;  
    //copy y  
    for(int j = 0; j < width;j++)  
    {  
        for(int i = height - 1; i >= 0;i--)  
        {  
            des[n++] = src[width * i + j];  
        }  
    }  
  
    //copy u  
    BYTE *ptemp = src + width * height;  
    for(int j = 0; j < hw; j++)  
    {  
        for(int i = hh - 1; i >= 0;i--)  
        {  
            des[n++] = ptemp[ hw * i + j];  
        }  
    }  
  
    //copy v  
    ptemp += width * height / 4;  
    for(int j = 0; j < hw; j++)  
    {  
        for(int i = hh - 1; i >= 0; i--)  
        {  
            des[n++] = ptemp[ hw * i + j];  
        }  
    }  
}  

原始图片

在这里插入图片描述
旋转后的图片

在这里插入图片描述 

 打印yuv420p

uint8_t* pData = new uint8_t [width*height*3/2];
YUV420p_Rotate_90(pData, *_decodeO.ppData, width, height);

FILE *file4 = fopen("/mnt/WebShare/Media/DST/yuvv4.yuv", "wb");
fwrite(pData, _decodeO.nWidth*_decodeO.nHeight*3/2, 1, file4);
fclose(file4);

delete [] pData;
pData = nullptr;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

YUV420P旋转 的相关文章

  • Android源码刷机步骤

    打开OEM开关 xff1a 先点击设置 关于手机 版本号七次 开发者选项 打开OEM解锁 xff08 这步必须可以上网 xff0c 否则打不开 xff09 进入bootloader页面 使用方法1必须安装adb platform tools
  • Android Studio导入和调试Android8.0源码

    生成IDE相关文件 idegen专门为IDE环境调试源码而设计的工具 xff0c 依次执行如下命令 xff1a source build envsetup sh mmm development tools idegen developmen
  • make snod注意事项-刷机后启动异常

    1 正确执行顺序 需要执行 source build envsetup sh lunch 2 单独编译 xff0c 刷机后运行异常 全编andorid后 xff0c 单独修改编译一个framwork模块 xff0c make snod会有如
  • adb remount 系统提示只读文件系统Read-only file system,解决用adb disable-verity

    在Android6 0 xff08 Android M xff09 userdebug版本上 eng版本不存在该问题 xff0c 发现使用adb remount 系统之后 xff0c 还是不能对system分区进行操作 xff0c 提示没有
  • 枚举 switchcase 标签必须为枚举常量的非限定名称

    enum switch case label must be the unqualified name of an enumeration constant 或 错误 枚举 switchcase 标签必须为枚举常量的非限定名称case Co
  • VMware为什么会越用占用的内存越大?该如何清理?

    现象描述 xff1a VMware用了一段时间后发现原来刚开始只占5G左右的内存 xff0c 慢慢的会占用几十个G xff0c 甚至更多 xff0c 磁盘空间占用越来越大 解决办法 xff1a 虚拟机内部执行cat dev zero gt
  • H264中的时间戳(DTS和PTS)

    xff08 1 xff09 Ffmpeg中的DTS 和 PTS H264里有两种时间戳 xff1a DTS xff08 Decoding Time Stamp xff09 和PTS xff08 Presentation Time Stamp
  • UEFI/Legacy两种启动模式下安装Win10/Ubuntu双系统

    文章目录 更多操作细节请移步到 UEFI Legacy两种启动模式下安装Win10 Ubuntu双系统 http www aigrantli com archives uefilegacy E4 B8 A4 E7 A7 8D E5 90 A
  • H264视频编码原理

    一 为什么要对视频编码 视频是由一帧帧的图像组成 xff0c 就像gif图片一样 一般视频为了不会让人感觉到卡顿 xff0c 一秒钟至少需要16帧画面 一般30帧 加入该视频是一个1280x720的分辨率 xff0c 那么不经过编码一秒钟传
  • H.264基础知识总结

    H264是视频编解码格式 xff1b 学习H264之前首先要搞明白一个问题 xff0c 视频为什么要编码 xff0c 编码传输不行吗 xff1f 视频就是一堆图片按时间顺序播放 xff0c 在编码标准出现之前 xff0c 不经过编码的原始码
  • linux文件分割(将大的日志文件分割成小的)

    linux文件分割 xff08 将大的日志文件分割成小的 xff09 linux下文件分割可以通过split命令来实现 xff0c 可以指定按行数分割和安大小分割两种模式 Linux下文件合并可以通过cat命令来实现 xff0c 非常简单
  • 华为AGC性能管理功能sdk集成

    集成SDK 1 xff09 在AGC网站的我的项目中选择需要启用性能管理的应用 xff0c 点击质量 gt 性能管理 xff0c 进入性能管理服务页面 xff0c 立即开通服务 2 xff09 添加AGC插件 xff0c 在Android
  • Android平台集成华为AGC性能管理服务问题处理指南

    最近尝试集成了华为AGC的性能管理服务 xff0c 集成过程中也遇到一些问题 本文就对我在集成性能管理服务的踩坑记录进行总结 xff0c 希望能帮到大家 问题一 xff1a 刚集成性能管理服务 xff0c 报错miss client id
  • Android ANR全解析&华为AGC性能管理解决ANR案例集

    1 ANR介绍 1 1 ANR是什么 ANR xff0c 全称为Application Not Responding xff0c 也就是应用程序无响应 如果 Android 应用的界面线程处于阻塞状态的时间过长 xff0c 就会触发 应用无
  • JAVA包装类

    什么是包装类 虽然 Java 语言是典型的面向对象编程语言 xff0c 但其中的八种基本数据类型并不支持面向对象编程 xff0c 基本类型的数据不具备 对象 的特性 不携带属性 没有方法可调用 沿用它们只是为了迎合人类根深蒂固的习惯 xff
  • Rxjava理论(一)

    大家都知道RxJava上手是非常难的一个框架 xff0c 为什么说是难呢 xff0c 因为它的功能非常强大 xff0c 各种操作符让人很难上手 xff0c 搭配使用带生命周期的框架有RxLife等 以至于后面出了很多类似Rxjava的框架

随机推荐

  • rxjava理论(二)

    doOnSubscribe的监听 在上一节我们介绍过subscribeOn是控制上游的observable在哪个线程执行 xff0c 关于怎么控制上游的observable可以看我上篇文章RxJava面经一 xff0c 拿去 xff0c 不
  • RxJava Hook(钩子)方法

    Hook技术又叫钩子函数 xff0c 在系统没有调用函数之前 xff0c 钩子就先捕获该消息 xff0c 得到控制权 这时候钩子程序既可以改变该程序的执行 xff0c 插入我们要执行的代码片段 xff0c 还可以强制结束消息的传递 RxJa
  • android底层之什么是Zram?

    ZRAM的理解 ZRAM xff08 压缩内存 xff09 的意思是说在内存中开辟一块区域压缩数据 就是说假设原来150MB的可用内存现在可以放下180MB的东西 本身不会提高内存容量和运行速度 只是让后台程序更少被系统砍掉罢了 xff0c
  • rxjava - compose()操作符

    1 问题背景 想要给多个流重复应用 34 一系列 34 相同的操作符 该怎么办 比如 我们使用Rx 43 Retrofit进行网络请求时 都有遇到这样场景 要在io线程中请求数据 在主线程订阅 更新UI 所以必须频繁使用下面这样的代码 su
  • RxJava2 背压

    1 背压 在RxJava中 xff0c 会遇到被观察者发送消息太快以至于它的操作符或者订阅者不能及时处理相关的消息 xff0c 这就是典型的背压 Back Pressure 场景 BackPressure经常被翻译为背压 xff0c 背压的
  • MVVM实现与原理分析

    1 MVVM简介 1 1 MVC amp MVP amp MVVM MVP MVVM与MVP结构类似 xff0c MVP也是通过Presenter将View与Model解耦 不过MVVM是基于观察者模式 xff0c viewModel不持有
  • PCM数据格式

    什么是PCM PCM全称Pulse Code Modulation xff0c 翻译一下是脉冲调制编码 其实大可以不用关心英文释义 xff0c 之所以这么命名是因为一些历史原因 在音视频中 xff0c PCM是一种用数字表示采样模拟信号的方
  • 音频帧大小的计算

    音频aac mp3文档规定 xff1a AAC xff1a 帧大小1024个sample xff0c 采样率为44100Hz 帧播放时长 xff1a acc dur 61 1024 44100 61 0 02322s 61 23 22ms
  • Java多线程系列--join()

    1 join 介绍 join 定义在Thread java中 join 的作用 xff1a 让 主线程 等待 子线程 结束之后才能继续运行 这句话可能有点晦涩 xff0c 我们还是通过例子去理解 xff1a 主线程 public class
  • Android的设计模式-装饰者模式

    1 定义 动态地给一个对象添加一些额外的职责 就增加功能来说 xff0c 装饰模式相比生成子类更为灵活 2 介绍 装饰者模式属于结构型模式 装饰者模式在生活中应用实际上也非常广泛 xff0c 一如一间房 xff0c 放上厨具 xff0c 它
  • android音频焦点Audio Focus

    为了便于理解 xff0c 我们以android的8 0以前的版本为例 xff0c 8 0以后有一定改动 xff0c 但是基本思路一样 关于管理音频焦点 xff08 8 0以前和更高版本 xff09 的官方文档 xff1a https dev
  • Android音频通路的切换

    Android支持多种设备的的输出 一台正常的机子 xff0c 本身就自带话筒 xff0c 扬声器 xff0c 麦克风等多个声音输入输出设备 xff0c 再加上五花八门的外置设备 xff08 通过耳机 xff0c 蓝牙 xff0c wifi
  • Java实现基本数据结构——数组

    数组概念 所谓数组 xff0c 是有序的元素序列 若将有限个类型相同的变量的集合命名 xff0c 那么这个名称为数组名 在数据结构中 xff0c 数组是一种线性表 xff0c 就是数据排列成一条直线一样的结构 在内容空间中 xff0c 数组
  • 块元素居中方式

    1 定位 span class token doctype lt DOCTYPE html gt span span class token tag span class token tag span class token punctua
  • wireshark以太帧的分析

    首先应该明白 xff0c 封装以太帧的位于OSI七层模型的第二层 xff0c 也就是数据链路层 xff0c wireshark可以把完整的以太帧抓起来 xff0c 我们可以清楚的看到 打开wireshark找到自己ip对应的网卡 xff0c
  • 网络协议——七层、五层、四层协议概念及功能分析

    一 7层 7层是指OSI七层协议模型 xff0c 主要是 xff1a 应用层 xff08 Application xff09 表示层 xff08 Presentation xff09 会话层 xff08 Session xff09 传输层
  • 为什么 UDP 头只有 8 个字节

    为什么这么设计 xff08 Why s THE Design xff09 是一系列关于计算机领域中程序设计决策的文章 xff0c 我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点 对具体实现造成的影响 如
  • Java 泛型

    Java 泛型 xff08 generics xff09 是 JDK 5 中引入的一个新特性 泛型提供了编译时类型安全检测机制 xff0c 该机制允许程序员在编译时检测到非法的类型 泛型的本质是参数化类型 xff0c 也就是说所操作的数据类
  • Android 端处理 YUV 数据 - Libyuv 的编译与使用

    在 Android 系统上 Camera 输出的图像一般为 NV21 YUV420SP 系列 格式 当我们想进行录像处理时 会面临两个问题 问题 1 图像的旋转问题 后置镜头 需要旋转 90 前置镜头 需要旋转 270 然后再进行镜像处理
  • YUV420P旋转

    YUV420与YUV420P YUV 和我们熟知的 RGB 类似 xff0c 是一种颜色编码格式 它主要用于电视系统和模拟视频邻域 xff08 如 Camera 系统 xff09 YUV 包含三个分量 xff0c 其中 Y 表示明亮度 xf