YUV与RGB的相互转换一直以来都是非常常用的基础算法,如何才能最高效的转换,成为一个难点问题,尤其是目前视频直播火热的时候,这些算法的优化也越发重要。
今天我结合自己的一些经验,给大家介绍一个简单的优化算法。
首先,我们看下最常用的YUV与RGB相互转换的算法公式,如下所示:
注意,RGB取值范围均为0-255:
1,RGB转YUV
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
2,YUV转RGB
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
我的优化方案如下:
优化1:看到上述算法,从算法优化角度来看,算法计算中,最好不要出现浮点运算,浮点运算比较耗时;
基于这一点,我们做如下操作:
Y * 256 = 0.299 * 256R + 0.587 * 256G + 0.114 * 256B
U * 256 = -0.147 * 256R - 0.289 * 256G + 0.436 * 256B
V * 256 = 0.615 * 256R - 0.515 * 256G - 0.100 * 256B
R * 256 = Y * 256 + 1.14 * 256V
G * 256 = Y * 256 - 0.39 * 256U - 0.58 * 256V
B * 256 = Y * 256 + 2.03 * 256U
简化上面的公式如下:
256Y = 76.544R + 150.272G + 29.184B
256U = -37.632R - 73.984G + 111.616B
256V = 157.44R - 131.84G - 25.6B
256R = 256Y + 291.84V
256G = 256Y - 99.84U - 148.48V
256B = 256Y + 519.68U
做到这一步,我这里要说明一下:我们这里的转换是有损的,适用于追求速度,而对效果要求不是100%准确的情况。
然后,我们就可以对上述公式进一步优化,彻底干掉小数:
256Y = 77R + 150G + 29B
256U = -38R - 74G + 112B
256V = 158R - 132G - 26B
256R = 256Y + 292V
256G = 256Y - 100U - 149V
256B = 256Y + 520U
实际上就是四舍五入,为什么要乘以256,这是实际上是为了缩小误差,当然你这个地方乘数越大,误差越小。
优化2:干掉所有乘法,用移位运算表示;
上述公式,我们可以用移位进行简单优化:
Y = (77R + 150G + 29B) >> 8
U = (-38R - 74G + 112B) >> 8
V = (158R - 132G - 26B) >> 8
R = (256Y + 292V) >> 8
G = (256Y - 100U - 149V) >> 8
B = (256Y + 520U) >> 8
做到此处,已经没有了浮点运算量了,但是我们发现虽然采用了移位运算,但是,公式中还有很多乘法运算,乘法跟移位运算相比,还是效率太低了,因此,我们将把所有乘法都改成移位运算。
如何将常数乘法改成移位运算?
这里给个例子:
Y=Y*9可以改为:Y=(Y<<3)+Y
因此,我们可以讲YUV的公式继续改为最简:
RGB转YUV:
Y = ((R << 6) + (R << 3) + (R << 2) + R + (G << 7) + (G << 4) + (G << 2) + (G << 1) + (B << 4) + (B << 3) + (B << 2) + B) >> 8;
U = (-((R << 5) + (R << 2) + (R << 1)) - ((G << 6) + (G << 3) + (G << 1)) + ((B << 6) + (B << 5) + (B << 4))) >> 8;
V = ((R << 7) + (R << 4) + (R << 3) + (R << 2) + (R << 1) - ((G << 7) + (G << 2)) - ((B << 4) + (B << 3) + (B << 1))) >> 8;
YUV转RGB:
R = ((Y << 8) + ((V << 8) + (V << 5) + (V << 2))) >> 8;
G = ((Y << 8) - ((U << 6) + (U << 5) + (U << 2)) - ((V << 7) + (V << 4) + (V << 2) + V)) >> 8;
B = ((Y << 8) + (U << 9) + (U << 3)) >> 8;
至此,YUV与RGB的相互转换公式就优化完毕了,这个优化,在移动端,速度会有很大的提高,至于一些测试数据,我就不列举了,只给个效果图吧,大家可以直接试一下就知道了,最后,给出C的代码如下:
static void RGBToYUV(int Red, int Green, int Blue, int* Y,int* U,int* V)
{
*Y = ((Red << 6) + (Red << 3) + (Red << 2) + Red + (Green << 7) + (Green << 4) + (Green << 2) + (Green << 1) + (Blue << 4) + (Blue << 3) + (Blue << 2) + Blue) >> 8;
*U = (-((Red << 5) + (Red << 2) + (Red << 1)) - ((Green << 6) + (Green << 3) + (Green << 1)) + ((Blue << 6) + (Blue << 5) + (Blue << 4))) >> 8;
*V = ((Red << 7) + (Red << 4) + (Red << 3) + (Red << 2) + (Red << 1) - ((Green << 7) + (Green << 2)) - ((Blue << 4) + (Blue << 3) + (Blue << 1))) >> 8;
};
static void YUVToRGB(int Y, int U, int V, int* Red, int* Green, int* Blue)
{
*Red = ((Y << 8) + ((V << 8) + (V << 5) + (V << 2))) >> 8;
*Green = ((Y << 8) - ((U << 6) + (U << 5) + (U << 2)) - ((V << 7) + (V << 4) + (V << 2) + V)) >> 8;
*Blue = ((Y << 8) + (U << 9) + (U << 3)) >> 8;
};
本篇博文接前篇自己思考出来的一种实现多线程交替工作的方式,给出来一个关于双线程协同工作的一种实际应用场景,实现的是RGB和YUV420的相互转换。主函数启两个线程,其中,一个线程用来读取RGB形式图片,并转成YUV格式数据存到申请的内存中;另一个线程用来读取内存数据,并把YUV格式转成RGB并显示。因为需要先进行线程1的读取转换存储,再进行线程2的读取内存和转换显示,两个线程交替工作,所以用到了前...
轮询算法(Round-Robin) 轮询算法是最简单的一种负载均衡算法。它的原理是把来自用户的请求轮流分配给内部的服务器:从服务器1开始,直到服务器N,然后重新开始循环。 算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。 假设有N台服务器:S = {S1, S2, …, Sn},一个指示变量i表示上一次选择的服务器ID。变量i被初始化为N-1。该算法的...
图形旋转好玩又有实用性, 这里介绍一种简单的图形旋转算法. 具体步骤如下: 1. 首先将原图和旋转图的坐标原点都变换到图形的中心位置处. 2. 历遍旋转图形中的每一个pixel, 将pixel的坐标(j,i)反向旋转映射到原图, 得到原图对应的坐标值(Xr,Yr). 3. 考虑到旋转图的尺寸可能大于原图,这时需要检测(Xr,Yr)是否在原图范围内,如果不是,则忽略下面步骤. 4. (Xr,Yr)通...
本文算法摘自opencv,可以说opencv是一个大宝库,里面有无穷无尽的算法,但是opencv里面的算法属于研究性质,只能解决“有”的问题,还不能解决“好”的问题。比如下面的简单白平衡算法,核心思想是:在rgb三通道上分别计算直方图,然后将1%的最大值和最小值设置为255和0,其余值映射到(0, 255)区间内,这样使得每个通道的值均匀分布,以实现...
提示:内附MATLAB代码及实验数据在文章结尾,希望各位看官在看完之后能给出您宝贵的建议,在此先谢谢各位看官! 文章目录 前言 一、经典模拟退火算法解决TSP问题的缺点 1、优化速度慢 2、无效代过多 二、解决方法 1.实验代码 初代版改进代码如下: 初代改进实验数据如下: 最优版改进代码如下: 最优版改进实验数据如下: 总结 前言 提示:经典模拟退火算法是一种鲁棒性强、设置参数少、具有较高容错率...
twitter等微博客的发展带动了一批short url应用的发展,目前网上也有好几种缩短url算法。 下面写的是我实际使用中的一种算法。 算法简述 属于递增方式,例如 我使用的域名为abc.com 那么我存储的短网址会有 http://abc.com/aaaa http://abc.com/aaab http://abc.com/aaac http://abc.com/aaad ....
这次的代码写了好久。。因为有一个问题一直没想透彻。要实现子列相对主列的相对移动,要移动的是子列的指针。。。我一直以为是主列需要一个缩进指针,所以改了好久。。更悲催的是前几次测试阴差阳错的全都对了呃呃呃呃。。后来就发现测试有问题。。。最后才想到。。 另外,在计算前缀值的那一步,我本来写了一个char***类型的数组,是一个char*类型的二维数组,想存子列各个前缀的内容。但是后来发现,第一因为存的是...
随机性 本算法以随机的方式对每张图像选取三种加雾算法中的一种,使得训练后的神经网络不容易出现过拟合现象 思路 在进行去雾算法实验的过程中我发现如果使用单一的加雾算法,得到的训练集进行训练后效果并不理想。之后在室友去噪实验的启发下,我尝试了这种方法,发现效果还不错。...
本文描述了一种可以应用在大分辨率图像上的连通域标记方法,该方法可以极大的简化图像标记的计算量,且对于标记的准确率和标记速度都是可控的。 1.整体思路 在任何一副图像中寻找连通域都是对不同区域的有效像素进行统计和关系判定,大多数连通域算法都需要做到整张图片的遍历和计算,有的需要多次遍历整张图片才能计算出准确的连通区域; 本文的思想是,一张图中并不是每个像素都需要计算的,使用一些具有代表性的像素判断某...
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 MATLAB代码 1.tent映射 2.完全离散的henon映射 3.henon映射的逆映射 4.加密步骤 5.解密步骤 6.相邻像素相关性分析 7.算法整体 MATLAB代码 1.tent映射 代码如下(示例): 2.完全离散的henon映射 代码如下(示例): 3.henon映射的逆映射 4.加密步骤 5.解密步骤 6...