FFmpeg之yuv镜像(十八)
在开发相机相关程序时,由于人们习惯于看镜子,因此开发者们经常会遇到镜像显示预览数据的需求。各个手机厂家也了解这一点,因此一般手机打开相机切换到前置摄像头看到的画面都是镜像的。本文提供了一些常见YUV、RGB数据的水平镜像和垂直镜像方法。
一、按像素点将图像镜像
图像可按水平镜像和垂直镜像。
假设有以下一张图像:
Pixel1 Pixel2 Pixel3 Pixel4
Pixel5 Pixel6 Pixel7 Pixel8
在**水平镜像**后,新的镜像数据内容将会是:
Pixel4 Pixel3 Pixel2 Pixel1
Pixel8 Pixel7 Pixel6 Pixel5
也就是:
- 原始数据第 0 行第 0 列的像素点将会变成目标数据第 0 行第 width - 1 列的像素点
- 原始数据第 0 行第 1 列的像素点将会变成目标数据第 0 行第 width - 2 列的像素点
- …
- 原始数据第 0 行第 width - 1 列的像素点将会变成目标数据第 0 行第 0 列的像素点
- …
- 原始数据第 height - 2 行第 0 列的像素点将会变成目标数据第 height - 2 行第 width - 1 列的像素点
- 原始数据第 height - 2 行第 1 列的像素点将会变成目标数据第 height - 2 行第 width - 2 列的像素点
- …
- 原始数据第 height - 2 行第 width - 1 列的像素点将会变成目标数据第 height - 2 行第 0 列的像素点
- …
- 原始数据第 height - 1 行第 0 列的像素点将会变成目标数据第 height - 1 行第 width - 1 列的像素点
- 原始数据第 height - 1 行第 1 列的像素点将会变成目标数据第 height - 1 行第 width - 2 列的像素点
- …
- 原始数据第 height - 1 行第 width - 1 列的像素点将会变成目标数据第 height - 1 行第 0 列的像素点
在垂直镜像后,新的镜像数据内容将会是:
Pixel5 Pixel6 Pixel7 Pixel8
Pixel1 Pixel2 Pixel3 Pixel4
也就是:
- 原始数据第 0 行第 0 列的像素点将会变成目标数据第 height - 1 行第 0 列的像素点
- 原始数据第 0 行第 1 列的像素点将会变成目标数据第 height - 1 行第 1 列的像素点
- …
- 原始数据第 0 行第 width - 1 列的像素点将会变成目标数据第 height - 1 行第 width - 1 列的像素点
- …
- 原始数据第 height - 2 行第 0 列的像素点将会变成目标数据第 1 行第 0 列的像素点
- 原始数据第 height - 2 行第 1 列的像素点将会变成目标数据第 1 行第 1 列的像素点
- …
- 原始数据第 height - 2 行第 width - 1 列的像素点将会变成目标数据第 1 行第 width - 1 列的像素点
- …
- 原始数据第 height - 1 行第 0 列的像素点将会变成目标数据第 0 行第 0 列的像素点
- 原始数据第 height - 1 行第 1 列的像素点将会变成目标数据第 0 行第 1 列的像素点
- …
- 原始数据第 height - 1 行第 width - 1 列的像素点将会变成目标数据第 0 行第 width - 1 列的像素点
二、镜像BGR24 / RGB24
由于BGR数据是3个byte作为一个像素点,因此我们在拷贝每个像素时需要每次移动3个byte。
- 水平镜像
void horizontalMirrorBgr24(char *bgr24, char *mirrorBgr24, int width, int height) {int lineStartIndex = 0;int lineDataSize = width * 3;for (int h = 0; h < height; h++) {for (int w = 0; w < lineDataSize; w += 3) {mirrorBgr24[lineStartIndex + w] = bgr24[lineStartIndex + lineDataSize - w - 3];mirrorBgr24[lineStartIndex + w + 1] = bgr24[lineStartIndex + lineDataSize - w - 2];mirrorBgr24[lineStartIndex + w + 2] = bgr24[lineStartIndex + lineDataSize - w - 1];}lineStartIndex += lineDataSize;}
}
- 垂直镜像
void verticalMirrorBgr24(char *bgr24, char *mirrorBgr24, int width, int height) {int lineDataSize = width * 3;bgr24 += width * height * 3;for (int h = 0; h < height; h++) {memcpy(mirrorBgr24, bgr24, lineDataSize);mirrorBgr24 += lineDataSize;bgr24 -= lineDataSize;}
}
三、镜像NV21 / NV12
由于NV21和NV12的结构只是UV数据位置相反,因此镜像NV21的代码同样适用于镜像NV12。
- 水平镜像
void horizontalMirrorNv21(char *nv21, char *mirrorNv21, int width, int height) {int yLineStartIndex = 0;int uvLineStartIndex = width * height;for (int h = 0; h < height; h++) {for (int w = 0; w < width; w += 2) {mirrorNv21[yLineStartIndex + w] = nv21[yLineStartIndex + width - w];mirrorNv21[yLineStartIndex + w + 1] = nv21[yLineStartIndex + width - w - 1];if ((h & 1) == 0) {mirrorNv21[uvLineStartIndex + w] = nv21[uvLineStartIndex + width - w];mirrorNv21[uvLineStartIndex + w + 1] = nv21[uvLineStartIndex + width - w - 1];}}yLineStartIndex += width;if ((h & 1) == 0) {uvLineStartIndex += width;}}
}
- 垂直镜像
void verticalMirrorNv21(char *nv21, char *mirrorNv21, int width, int height) {int yLineDataSize = width;int nv21Index = 0, mirrorNv21Index = 0;nv21Index += width * height - yLineDataSize;//mirror yfor (int h = 0; h < height; h++) {memcpy(mirrorNv21 + mirrorNv21Index, nv21 + nv21Index, yLineDataSize);mirrorNv21Index += yLineDataSize;nv21Index -= yLineDataSize;}int uvLineDataSize = width;//mirror uvint uvHeight = height / 2;//point to final line of uvnv21Index += (width * height * 3 / 2 - uvLineDataSize);for (int h = 0; h < uvHeight; h++) {memcpy(mirrorNv21 + mirrorNv21Index, nv21 + nv21Index, uvLineDataSize);mirrorNv21Index += uvLineDataSize;nv21Index -= uvLineDataSize;}
}
四、镜像I420 / YV12
由于I420 和YV12的结构只是UV数据位置相反,因此镜像I420的代码同样适用于镜像YV12。
- 水平镜像
void horizontalMirrorI420(char *i420, char *mirrorI420, int width, int height) {int yLineStartIndex = 0;int uLineStartIndex = width * height;int vLineStartIndex = width * height * 5 / 4;for (int h = 0; h < height; h++) {for (int w = 0; w < width; w += 2) {mirrorI420[yLineStartIndex + w] = i420[yLineStartIndex + width - w];mirrorI420[yLineStartIndex + w + 1] = i420[yLineStartIndex + width - w - 1];if ((h & 1) == 0) {mirrorI420[uLineStartIndex + (w >> 1)] = i420[uLineStartIndex + ((width - w) >> 1)];mirrorI420[vLineStartIndex + (w >> 1) + 1] = i420[vLineStartIndex +((width - w) >> 1) - 1];}}yLineStartIndex += width;if ((h & 1) == 0) {uLineStartIndex += width >> 1;vLineStartIndex += width >> 1;}}
}
- 垂直镜像
void verticalMirrorI420(char *i420, char *mirrorI420, int width, int height) {int halfWidth = width / 2;int yLineDataSize = width;int i420Index = 0, mirrorI420Index = 0;i420Index += width * height - yLineDataSize;//mirror yfor (int h = 0; h < height; h++) {memcpy(mirrorI420 + mirrorI420Index, i420 + i420Index, yLineDataSize);mirrorI420Index += yLineDataSize;i420Index -= yLineDataSize;}int uvLineDataSize = halfWidth;//mirror uvint uHeight = height / 2;//point to final line of ui420Index += (width * height * 5 / 4 + yLineDataSize - uvLineDataSize);for (int h = 0; h < uHeight; h++) {memcpy(mirrorI420 + mirrorI420Index, i420 + i420Index, uvLineDataSize);mirrorI420Index += uvLineDataSize;i420Index -= uvLineDataSize;}//point to final line of vi420Index += width * height / 2;int vHeight = height / 2;for (int h = 0; h < vHeight; h++) {memcpy(mirrorI420 + mirrorI420Index, i420 + i420Index, uvLineDataSize);mirrorI420Index += uvLineDataSize;i420Index -= uvLineDataSize;}
}
五、镜像YUYV
YUYV的共用关系是每2个Y共用1组U和V,因此在水平镜像时需要每4个Y替换其中两个Y的顺序。而垂直镜像时,整行处理即可。
- 水平镜像
void horizontalMirrorYuyv(char *yuyv, char *mirrorYuyv, int width, int height) {int lineStartIndex = 0;int lineDataSize = width * 2;for (int h = 0; h < height; h++) {for (int w = 0; w < lineDataSize; w += 4) {mirrorYuyv[lineStartIndex + w] = yuyv[lineStartIndex + lineDataSize - w - 2];mirrorYuyv[lineStartIndex + w + 1] = yuyv[lineStartIndex + lineDataSize - w - 3];mirrorYuyv[lineStartIndex + w + 2] = yuyv[lineStartIndex + lineDataSize - w - 4];mirrorYuyv[lineStartIndex + w + 3] = yuyv[lineStartIndex + lineDataSize - w - 1];}lineStartIndex += lineDataSize;}
}
- 垂直镜像
void verticalMirrorYuyv(char *yuyv, char *mirrorYuyv, int width, int height) {int lineDataSize = width * 2;yuyv += width * height * 2;for (int h = 0; h < height; h++) {memcpy(mirrorYuyv, yuyv, lineDataSize);mirrorYuyv += lineDataSize;yuyv -= lineDataSize;}
}
FFmpeg之yuv镜像(十八)相关推荐
- FFmpeg之yuv旋转(十九)
一. 按像素点旋转图像 假设有以下一张图像: Pixel1 Pixel2 Pixel3 Pixel4 Pixel5 Pixel6 Pixel7 Pixel8 其图像分辨率是width x ...
- opencv镜像_DX200操作要领—PAM与镜像平移变换(三十八)
6.4 PAM功能 6.4.1 PAM功能 再现中的位置修改功能 (PAM 功能:Position Adjustment Manual) ,可在查看机器人动作状况的同时,在不停止机器人的情况下,通过简 ...
- OpenCV学习笔记(四十六)——FAST特征点检测features2D OpenCV学习笔记(四十七)——VideoWriter生成视频流highgui OpenCV学习笔记(四十八)——PCA算
OpenCV学习笔记(四十六)--FAST特征点检测features2D 特征点检测和匹配是计算机视觉中一个很有用的技术.在物体检测,视觉跟踪,三维常年关键等领域都有很广泛的应用.这一次先介绍特征点检 ...
- OpenCV学习笔记(十六)——CamShift研究 OpenCV学习笔记(十七)——运动分析和物体跟踪Video OpenCV学习笔记(十八)——图像的各种变换(cvtColor*+)imgproc
OpenCV学习笔记(十六)--CamShift研究 CamShitf算法,即Continuously Apative Mean-Shift算法,基本思想就是对视频图像的多帧进行MeanShift运算 ...
- [Python从零到壹] 五十八.图像增强及运算篇之图像锐化Sobel、Laplacian算子实现边缘检测
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
- ComicEnhancerPro 系列教程十八:JPG文件长度与质量
作者:马健 邮箱:stronghorse_mj@hotmail.com 主页:http://www.comicer.com/stronghorse/ 发布:2017.07.23 教程十八:JPG文件长 ...
- 机器学习之MATLAB代码--CEEMDAN+EEMD+EMD+VMD+IMF重构络(十八)
机器学习之MATLAB代码--CEEMDAN+EEMD+EMD+VMD+IMF重构络(十八) 压缩分量的EEMD代码 压缩分量的EEMD数据 压缩分量的EEMD结果 CEEMDAN代码 CEEMDAN ...
- [Python从零到壹] 三十八.图像处理基础篇之图像几何变换(平移缩放旋转)
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
- Windows 8的十八项特点
一.支持ARM架构 在年初的CES 2011上,微软正式宣布,Windows 8将支持ARM芯片架构.即来自Intel.AMD.NVIDIA.高通和德州仪器等芯片厂商的ARM系统都将一并提供支持.微软 ...
最新文章
- 非标自动化转行机器人_机器人与非标自动化这两个有什么区别?可以从结构,功能等方面谈谈吗?...
- 达内软件测试证书是什么证书,达内软件测试培训让我拥有了实际工作经验
- SharePoint2013开发环境搭建(完整版:图文并茂)
- java aop execution_Spring AOP -- execution表达式
- Not Equal on a Segment CodeForces - 622C
- AWK 批量杀进程号,好记性不如烂笔头
- javascript基础-ajax
- sendgrid java_java – SendGrid电子邮件API,发送电子邮件附件
- [转载] OpenCV-Python图像位与运算bitwise_and函数详解
- 全选、取消全选、单选
- 【原】unity3D之Draw Call
- 制作U盘macos系统
- excel把多个工作表合并
- java图形用户界面基础
- linux wifi音箱,基于Orangpi Zero和Linux ALSA实现WIFI无线音箱(三)
- 使用定积分计算三角形面积
- 计算机的复数形式英语,名词的复数形式大全
- 《手机传感器》参数与选择
- Win10电脑开机后黑屏只有鼠标怎么办?
- text改为longtext