最近在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;

              v = ((112 * r - 94 * g - 18 * 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的探讨与实现的更多相关文章

  1. 【性能优化】优化笔记之一:图像RGB与YUV转换优化

    本文主要介绍如何优化您自己的CODE,实现软件的加速.我们一个图象模式识别的项目,需要将RGB格式的彩色图像先转换成黑白图像.图像转换的公式如下: Y = 0.299 * R + 0.587 * G ...

  2. Android 音视频编解码——RGB与YUV格式转换

    一.RGB模型与YUV模型 1.RGB模型 我们知道物理三基色分别是红(Red).绿(Green).蓝(Blue).现代的显示器技术就是通过组合不同强度的红绿蓝三原色,来达成几乎任何一种可见光的颜色. ...

  3. 音视频编解码——RGB与YUV格式转换

    一.RGB模型与YUV模型 1.RGB模型 我们知道物理三基色分别是红(Red).绿(Green).蓝(Blue).现代的显示器技术就是通过组合不同强度的红绿蓝三原色,来达成几乎任何一种可见光的颜色. ...

  4. 多媒体编程基础之RGB和YUV

    一.概念 1.什么是RGB? 对一种颜色进行编码的方法统称为“颜色空间”或“色域”.用最简单的话说,世界上任何一种颜色的“颜色空间”都可定义成一个固定的数字或变量.RGB(红.绿.蓝)只是众多颜色空间 ...

  5. LCD LED OLED区别 以及RGB、YUV和HSV颜色空间模型

    led 液晶本身不发光,而是有背光作为灯源,白色是由红绿蓝三色组成,黑色是,液晶挡住了led灯光穿过显示器. lcd比led更薄. oled:显示黑色时,灯是灭的,所以显示黑色更深,效果更好. 这就不 ...

  6. 视音频数据处理入门:RGB、YUV像素数据处理

    ===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...

  7. [转载] 视音频数据处理入门:RGB、YUV像素数据处理

    ===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...

  8. RGB和YUV之比较【转】

    转自:http://blog.csdn.net/qfnu08zzr/article/details/6763159 版权声明:本文为博主原创文章,未经博主允许不得转载. RGB 原理 RGB 是从颜色 ...

  9. 视音频数据处理入门:RGB、YUV像素数据处理【转】

    转自:http://blog.csdn.net/leixiaohua1020/article/details/50534150 ==================================== ...

随机推荐

  1. Java笔记2 : 泛型的体现,及其上限、下限、通配符

    Java中的泛型是在jdk5.0引入的,语法不难,但是需要注意的细节有很多,这里写一下备忘. 首先是最简单的泛型类,泛型方法,泛型接口: //泛型接口的定义 interface MyInter< ...

  2. 简谈Comparable和Comparator区别

    对于Comparable和Comparator这连个相似的接口,还是做一下比较比较好: Comparable Comparator (1)只包含一个compareTo()方法,此方法可以给两个对象排序 ...

  3. 关于Java(JDBC连接数据库)

    Processing SQL Statements with JDBC 处理JDBC中的SQL语句 这节主要是 JDBC 与数据库交互的基本步骤 JDBC的基石是DriverManager,通过它,J ...

  4. Web 安全之内容安全策略 (CSP)

    内容安全策略 (CSP, Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的攻击,包括跨站脚本攻击 (XSS) 和数据注入等攻击. 这些攻击可用于实现从 ...

  5. CISCO的HTTP/HTTPS/SSH配置测试完成

    按实验一步一步,倒是很容易的,也理解罗~~ START-CONFIG粗配置文件如下: r1#show run Building configuration... Current configurati ...

  6. matlab使用reshape时按照列优先原则取元素和摆放元素

    参考 http://blog.csdn.net/superdont/article/details/3992033 a=[1  2 3  4] 如果使用b=reshape(a,1,4),则得到的结果是 ...

  7. MySQL5.6 基于db的并行复制

    slave的几个类结构:      Master_info:用于IO线程的参数,包括连接master实例的信息.      Relay_log_info:用于sql线程,表示relay log相关的信 ...

  8. 使用Xcode Instruments Leak解决内存泄漏问题

    iOS 5.0之后apple引入了Xcode编译器特性ARC(Automatic Reference Counting,自动引用计数)来帮助开发者管理内存,但为了追求app的高性能与减少安装包大小,工 ...

  9. Colour your Log4Net events in your RichTextBox zz

    You’re most probably here because you have already read my article How to watch your log through you ...

  10. Oracle函数题

    Examine this function: CREATE OR REPLACE FUNCTION CALC_PLAYER_AVG (V_ID in PLAYER_BAT_STAT.PLAYER_ID ...