关于RGB转换YUV的探讨与实现
最近在Android手机上使用相机识别条形码工作取得了比较理想的进展,自动识别功能基本完成,然而在手动识别指定条形码图片时遇到困难,由于Zxing开源Jar包识别图片的颜色编码式为YUV,而普通的图片使用RGB颜色分量来保存颜色信息。非压缩的24位的BMP图像就采用RGB空间来保存图像。一个像素24位,每8位保存一种颜色强度(0-255),例如红色保存为 0xFF0000。经过两天的探索与查阅相关YUV与RGB资料后,尝试编写了RGB转换为YUV代码,几番调试后终于转换成功。下面就作一些简单介绍,然后贴出代码。
YUV是被欧洲电视系统所采用的一种颜色编码方法。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma)。在彩色的广播电视中,并不是直接传送RGB三基色信号,而是把三基色经过转换成可以代表三基色信号的新的三个基本参量YUV来传输的。YUV格式通常有两大类,打包格式和平面格式。打包格式有以下几种:YUV2格式,YUYV格式, YVYU格式, UYVY格式。平面格式有IF09格式,IYUV格式,YVU9格式。Android摄像头预览的视频流色彩编码方案默认为YCbCr4:2:0,其中4:2:0表示2:1的水平下采样,2:1的垂直下采样,体现为以下分布。
详见:http://blog.csdn.net/SearchSun/article/details/2443867
我以我理解的方式来表示来RGB与YCbCr420的对应关系,请看下图。
如上图所示为一张(宽X高)为(6 *4),即len=6×4的RGB编码位图,图中的每一个小球代表一个像素点。在便携式视频设备(MPEG-4)中,YCbCr4:2:0是最常用的格式,表示每4个像素有4个亮度分量,2个色度分量(YYYYCbCr)。从图上,可以直观地看出4个像素点共享U和V分量(颜色标志相同的小球),也即2:1的水平下采样,2:1的垂直下采样。接下来,申请一个字节数组来保存YUV数据,该YUV的数组长度为len×3/2,Y分量占len长度字节,U和V分别占len/4长度字节。
代码:
len = width * height;
byte[] yuv = new byte[len * 3 / 2];
上图中的坐标值表示该分量在在YUV数组中位置index。现在给出index计算方式:
Y_index = (i * width + j);
U_index= (len + (i >> 1) * width + (j & ~1) + 0)
V_index=(len + (i >> 1) * width + (j & ~1) + 1)
Y、U、V分量与R、G、B分量的对应关系为:
y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
r = 1.166f * (y - 16) + 1.596f * (v - 128);
g = 1.164f * (y - 16) - 0.813f * (v - 128)- 0.391f * (u - 128);
b = 1.164f * (y - 16) + 2.018f * (u - 128);
因此代码很容易就可写出:假定已获取到像素值,如果是一张图片,你可以通过代码先获得该图片的像素值整型数组,然后传入该数组,以及该图片的宽度和高度调用以下方法即可获取YCbCr420格式数组。
public byte[] rgb2YCbCr420(int[] pixels, int width, int height) {
int len = width * height;
//yuv格式数组大小,y亮度占len长度,u,v各占len/4长度。
byte[] yuv = new byte[len * 3 / 2];
int y, u, v;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
//屏蔽ARGB的透明度值
int rgb = pixels[i * width + j] & 0x00FFFFFF;
//像素的颜色顺序为bgr,移位运算。
int r = rgb & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb >> 16) & 0xFF;
//套用公式
y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
//调整
y = y < 16 ? 16 : (y > 255 ? 255 : y);
u = u < 0 ? 0 : (u > 255 ? 255 : u);
v = v < 0 ? 0 : (v > 255 ? 255 : v);
//赋值
yuv[i * width + j] = (byte) y;
yuv[len + (i >> 1) * width + (j & ~1) + 0] = (byte) u;
yuv[len + +(i >> 1) * width + (j & ~1) + 1] = (byte) v;
}
}
return yuv;
}
再附上YCbCr420转换成RGB的代码,可以通过该代码还原RGB位图。
public void yCbCr2Rgb (byte[] yuv, int width, int height) {
int frameSize = width * height;
int[] rgba = new int[frameSize];
for (int i = 0; i < height; i++){
for (int j = 0; j < width; j++) {
int y = (0xff & ((int) yuv[i * width + j]));
int u = (0xff & ((int) yuv [frameSize + (i >> 1) * width
+ (j & ~1) + 0]));
int v = (0xff & ((int) yuv [frameSize + (i >> 1) * width
+ (j & ~1) + 1]));
y = y < 16 ? 16 : y;
int r = Math.round(1.166f * (y - 16) + 1.596f * (v - 128));
int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128)
- 0.391f * (u - 128));
int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));
r = r < 0 ? 0 : (r > 255 ? 255 : r);
g = g < 0 ? 0 : (g > 255 ? 255 : g);
b = b < 0 ? 0 : (b > 255 ? 255 : b);
rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;
}
}
Bitmap bmp = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bmp.setPixels(rgba, 0, width, 0, 0, width, height);
String bmpName = "test.jpg";
String path = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/scan_test";
// 文件目录
File root = new File(path);
if (!root.isDirectory() || !root.exists()) {
root.mkdirs();
}
File myCaptureFile = new File(path, bmpName);
try {
myCaptureFile.createNewFile();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(myCaptureFile));
// 采用压缩转档方法
bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
} catch (Exception e) {
myCaptureFile.delete();
}
}
关于RGB转换YUV的探讨与实现的更多相关文章
- 【性能优化】优化笔记之一:图像RGB与YUV转换优化
本文主要介绍如何优化您自己的CODE,实现软件的加速.我们一个图象模式识别的项目,需要将RGB格式的彩色图像先转换成黑白图像.图像转换的公式如下: Y = 0.299 * R + 0.587 * G ...
- Android 音视频编解码——RGB与YUV格式转换
一.RGB模型与YUV模型 1.RGB模型 我们知道物理三基色分别是红(Red).绿(Green).蓝(Blue).现代的显示器技术就是通过组合不同强度的红绿蓝三原色,来达成几乎任何一种可见光的颜色. ...
- 音视频编解码——RGB与YUV格式转换
一.RGB模型与YUV模型 1.RGB模型 我们知道物理三基色分别是红(Red).绿(Green).蓝(Blue).现代的显示器技术就是通过组合不同强度的红绿蓝三原色,来达成几乎任何一种可见光的颜色. ...
- 多媒体编程基础之RGB和YUV
一.概念 1.什么是RGB? 对一种颜色进行编码的方法统称为“颜色空间”或“色域”.用最简单的话说,世界上任何一种颜色的“颜色空间”都可定义成一个固定的数字或变量.RGB(红.绿.蓝)只是众多颜色空间 ...
- LCD LED OLED区别 以及RGB、YUV和HSV颜色空间模型
led 液晶本身不发光,而是有背光作为灯源,白色是由红绿蓝三色组成,黑色是,液晶挡住了led灯光穿过显示器. lcd比led更薄. oled:显示黑色时,灯是灭的,所以显示黑色更深,效果更好. 这就不 ...
- 视音频数据处理入门:RGB、YUV像素数据处理
===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...
- [转载] 视音频数据处理入门:RGB、YUV像素数据处理
===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...
- RGB和YUV之比较【转】
转自:http://blog.csdn.net/qfnu08zzr/article/details/6763159 版权声明:本文为博主原创文章,未经博主允许不得转载. RGB 原理 RGB 是从颜色 ...
- 视音频数据处理入门:RGB、YUV像素数据处理【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/50534150 ==================================== ...
随机推荐
- PHP扩展-生命周期和内存管理
1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...
- mysql从身份证号中提取生日、性别
SELECT p.ID, p.IDCardNo, IF ( LENGTH(p.IDCardNo) , CAST( , ) AS DATETIME ), CAST( CONCAT( ', , ) ) A ...
- 浅谈android binder机制
binder机制 是谷歌优化在android上更适合终端的IPC(多进程通信方式),满足系统对通信方式,传输性能和安全性的要求. 特性: 1. 用驱动程序来推进进程间的通信.2. 通过共享内存来提高性 ...
- 批处理命令——set
[1]set命令简介 set,设置. [2]set命令使用 1. 打印系统环境变量.set命令可以打印系统所有的环境变量信息. 应用示例:新建文本文件,命名为set_sys,修改文件类型为bat,用N ...
- 快速搭建PHP开发环境(PhpStorm+EasyPHP)
写在开头,何为PHP(拍黄片)? P HP是一种开源的通用计算机脚本语言,尤其适用于网络开发并可嵌入HTML中使用(维基百科). 从上我们得出,何为PHP? 1.开源脚本语言. 2.用于网络开发可嵌入 ...
- Path Sum II——LeetCode
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given su ...
- java构造代码块,构造函数和普通函数的区别和调用时间
在这里我们谈论一下构造代码块,构造函数和普通函数的区别和调用时间.构造代码块:最早运行,比构造函数运行的时间好要提前,和构造函数一样,只在对象初始化的时候运行.构造函数:运行时间比构造代码块时间晚,也 ...
- How to make a simplest WCF service work on Win7 with VS2010
You know as a beginner to learn WCF, the first thing is to make a simplest WCF service work like a c ...
- poj3322 Bloxorz I
Home Problems Logout -11:24:01 Overview Problem Status Rank A B C D E F G H I J K L M N O ...
- 关于flume的filechannel的 full 问题
事务启动以后,批量向事务Transaction的一个putList的尾部写入,putlist是一个LinkedBlockingDeque . 事务提交的时候, 把putlist中的event批量移除, ...