I wrote an algorithm to convert a RGB image to a YUV420. I spend a long time trying to make it faster but I haven't find any other way to boost its efficiency, so now I turn to you so you can tell me if this is as good as I get, or if there's another more efficient way to do it (the algorithm is in C++ but C and assembler are also options)
namespace {
// lookup tables
int lookup_m_94[] = {
0, -94, -188, -282, -376, -470, -564, -658,
-752, -846, -940, -1034, -1128, -1222, -1316, -1410,
-1504, -1598, -1692, -1786, -1880, -1974, -2068, -2162,
-2256, -2350, -2444, -2538, -2632, -2726, -2820, -2914,
-3008, -3102, -3196, -3290, -3384, -3478, -3572, -3666,
-3760, -3854, -3948, -4042, -4136, -4230, -4324, -4418,
-4512, -4606, -4700, -4794, -4888, -4982, -5076, -5170,
-5264, -5358, -5452, -5546, -5640, -5734, -5828, -5922,
-6016, -6110, -6204, -6298, -6392, -6486, -6580, -6674,
-6768, -6862, -6956, -7050, -7144, -7238, -7332, -7426,
-7520, -7614, -7708, -7802, -7896, -7990, -8084, -8178,
-8272, -8366, -8460, -8554, -8648, -8742, -8836, -8930,
-9024, -9118, -9212, -9306, -9400, -9494, -9588, -9682,
-9776, -9870, -9964, -10058, -10152, -10246, -10340, -10434,
-10528, -10622, -10716, -10810, -10904, -10998, -11092, -11186,
-11280, -11374, -11468, -11562, -11656, -11750, -11844, -11938,
-12032, -12126, -12220, -12314, -12408, -12502, -12596, -12690,
-12784, -12878, -12972, -13066, -13160, -13254, -13348, -13442,
-13536, -13630, -13724, -13818, -13912, -14006, -14100, -14194,
-14288, -14382, -14476, -14570, -14664, -14758, -14852, -14946,
-15040, -15134, -15228, -15322, -15416, -15510, -15604, -15698,
-15792, -15886, -15980, -16074, -16168, -16262, -16356, -16450,
-16544, -16638, -16732, -16826, -16920, -17014, -17108, -17202,
-17296, -17390, -17484, -17578, -17672, -17766, -17860, -17954,
-18048, -18142, -18236, -18330, -18424, -18518, -18612, -18706,
-18800, -18894, -18988, -19082, -19176, -19270, -19364, -19458,
-19552, -19646, -19740, -19834, -19928, -20022, -20116, -20210,
-20304, -20398, -20492, -20586, -20680, -20774, -20868, -20962,
-21056, -21150, -21244, -21338, -21432, -21526, -21620, -21714,
-21808, -21902, -21996, -22090, -22184, -22278, -22372, -22466,
-22560, -22654, -22748, -22842, -22936, -23030, -23124, -23218,
-23312, -23406, -23500, -23594, -23688, -23782, -23876, -23970
};
int lookup_m_74[] = {
0, -74, -148, -222, -296, -370, -444, -518,
-592, -666, -740, -814, -888, -962, -1036, -1110,
-1184, -1258, -1332, -1406, -1480, -1554, -1628, -1702,
-1776, -1850, -1924, -1998, -2072, -2146, -2220, -2294,
-2368, -2442, -2516, -2590, -2664, -2738, -2812, -2886,
-2960, -3034, -3108, -3182, -3256, -3330, -3404, -3478,
-3552, -3626, -3700, -3774, -3848, -3922, -3996, -4070,
-4144, -4218, -4292, -4366, -4440, -4514, -4588, -4662,
-4736, -4810, -4884, -4958, -5032, -5106, -5180, -5254,
-5328, -5402, -5476, -5550, -5624, -5698, -5772, -5846,
-5920, -5994, -6068, -6142, -6216, -6290, -6364, -6438,
-6512, -6586, -6660, -6734, -6808, -6882, -6956, -7030,
-7104, -7178, -7252, -7326, -7400, -7474, -7548, -7622,
-7696, -7770, -7844, -7918, -7992, -8066, -8140, -8214,
-8288, -8362, -8436, -8510, -8584, -8658, -8732, -8806,
-8880, -8954, -9028, -9102, -9176, -9250, -9324, -9398,
-9472, -9546, -9620, -9694, -9768, -9842, -9916, -9990,
-10064, -10138, -10212, -10286, -10360, -10434, -10508, -10582,
-10656, -10730, -10804, -10878, -10952, -11026, -11100, -11174,
-11248, -11322, -11396, -11470, -11544, -11618, -11692, -11766,
-11840, -11914, -11988, -12062, -12136, -12210, -12284, -12358,
-12432, -12506, -12580, -12654, -12728, -12802, -12876, -12950,
-13024, -13098, -13172, -13246, -13320, -13394, -13468, -13542,
-13616, -13690, -13764, -13838, -13912, -13986, -14060, -14134,
-14208, -14282, -14356, -14430, -14504, -14578, -14652, -14726,
-14800, -14874, -14948, -15022, -15096, -15170, -15244, -15318,
-15392, -15466, -15540, -15614, -15688, -15762, -15836, -15910,
-15984, -16058, -16132, -16206, -16280, -16354, -16428, -16502,
-16576, -16650, -16724, -16798, -16872, -16946, -17020, -17094,
-17168, -17242, -17316, -17390, -17464, -17538, -17612, -17686,
-17760, -17834, -17908, -17982, -18056, -18130, -18204, -18278,
-18352, -18426, -18500, -18574, -18648, -18722, -18796, -18870
};
int lookup_m_38[] = {
0, -38, -76, -114, -152, -190, -228, -266,
-304, -342, -380, -418, -456, -494, -532, -570,
-608, -646, -684, -722, -760, -798, -836, -874,
-912, -950, -988, -1026, -1064, -1102, -1140, -1178,
-1216, -1254, -1292, -1330, -1368, -1406, -1444, -1482,
-1520, -1558, -1596, -1634, -1672, -1710, -1748, -1786,
-1824, -1862, -1900, -1938, -1976, -2014, -2052, -2090,
-2128, -2166, -2204, -2242, -2280, -2318, -2356, -2394,
-2432, -2470, -2508, -2546, -2584, -2622, -2660, -2698,
-2736, -2774, -2812, -2850, -2888, -2926, -2964, -3002,
-3040, -3078, -3116, -3154, -3192, -3230, -3268, -3306,
-3344, -3382, -3420, -3458, -3496, -3534, -3572, -3610,
-3648, -3686, -3724, -3762, -3800, -3838, -3876, -3914,
-3952, -3990, -4028, -4066, -4104, -4142, -4180, -4218,
-4256, -4294, -4332, -4370, -4408, -4446, -4484, -4522,
-4560, -4598, -4636, -4674, -4712, -4750, -4788, -4826,
-4864, -4902, -4940, -4978, -5016, -5054, -5092, -5130,
-5168, -5206, -5244, -5282, -5320, -5358, -5396, -5434,
-5472, -5510, -5548, -5586, -5624, -5662, -5700, -5738,
-5776, -5814, -5852, -5890, -5928, -5966, -6004, -6042,
-6080, -6118, -6156, -6194, -6232, -6270, -6308, -6346,
-6384, -6422, -6460, -6498, -6536, -6574, -6612, -6650,
-6688, -6726, -6764, -6802, -6840, -6878, -6916, -6954,
-6992, -7030, -7068, -7106, -7144, -7182, -7220, -7258,
-7296, -7334, -7372, -7410, -7448, -7486, -7524, -7562,
-7600, -7638, -7676, -7714, -7752, -7790, -7828, -7866,
-7904, -7942, -7980, -8018, -8056, -8094, -8132, -8170,
-8208, -8246, -8284, -8322, -8360, -8398, -8436, -8474,
-8512, -8550, -8588, -8626, -8664, -8702, -8740, -8778,
-8816, -8854, -8892, -8930, -8968, -9006, -9044, -9082,
-9120, -9158, -9196, -9234, -9272, -9310, -9348, -9386,
-9424, -9462, -9500, -9538, -9576, -9614, -9652, -9690
};
int lookup_m_18[] = {
0, -18, -36, -54, -72, -90, -108, -126,
-144, -162, -180, -198, -216, -234, -252, -270,
-288, -306, -324, -342, -360, -378, -396, -414,
-432, -450, -468, -486, -504, -522, -540, -558,
-576, -594, -612, -630, -648, -666, -684, -702,
-720, -738, -756, -774, -792, -810, -828, -846,
-864, -882, -900, -918, -936, -954, -972, -990,
-1008, -1026, -1044, -1062, -1080, -1098, -1116, -1134,
-1152, -1170, -1188, -1206, -1224, -1242, -1260, -1278,
-1296, -1314, -1332, -1350, -1368, -1386, -1404, -1422,
-1440, -1458, -1476, -1494, -1512, -1530, -1548, -1566,
-1584, -1602, -1620, -1638, -1656, -1674, -1692, -1710,
-1728, -1746, -1764, -1782, -1800, -1818, -1836, -1854,
-1872, -1890, -1908, -1926, -1944, -1962, -1980, -1998,
-2016, -2034, -2052, -2070, -2088, -2106, -2124, -2142,
-2160, -2178, -2196, -2214, -2232, -2250, -2268, -2286,
-2304, -2322, -2340, -2358, -2376, -2394, -2412, -2430,
-2448, -2466, -2484, -2502, -2520, -2538, -2556, -2574,
-2592, -2610, -2628, -2646, -2664, -2682, -2700, -2718,
-2736, -2754, -2772, -2790, -2808, -2826, -2844, -2862,
-2880, -2898, -2916, -2934, -2952, -2970, -2988, -3006,
-3024, -3042, -3060, -3078, -3096, -3114, -3132, -3150,
-3168, -3186, -3204, -3222, -3240, -3258, -3276, -3294,
-3312, -3330, -3348, -3366, -3384, -3402, -3420, -3438,
-3456, -3474, -3492, -3510, -3528, -3546, -3564, -3582,
-3600, -3618, -3636, -3654, -3672, -3690, -3708, -3726,
-3744, -3762, -3780, -3798, -3816, -3834, -3852, -3870,
-3888, -3906, -3924, -3942, -3960, -3978, -3996, -4014,
-4032, -4050, -4068, -4086, -4104, -4122, -4140, -4158,
-4176, -4194, -4212, -4230, -4248, -4266, -4284, -4302,
-4320, -4338, -4356, -4374, -4392, -4410, -4428, -4446,
-4464, -4482, -4500, -4518, -4536, -4554, -4572, -4590
};
int lookup25[] = {
0, 25, 50, 75, 100, 125, 150, 175,
200, 225, 250, 275, 300, 325, 350, 375,
400, 425, 450, 475, 500, 525, 550, 575,
600, 625, 650, 675, 700, 725, 750, 775,
800, 825, 850, 875, 900, 925, 950, 975,
1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
1200, 1225, 1250, 1275, 1300, 1325, 1350, 1375,
1400, 1425, 1450, 1475, 1500, 1525, 1550, 1575,
1600, 1625, 1650, 1675, 1700, 1725, 1750, 1775,
1800, 1825, 1850, 1875, 1900, 1925, 1950, 1975,
2000, 2025, 2050, 2075, 2100, 2125, 2150, 2175,
2200, 2225, 2250, 2275, 2300, 2325, 2350, 2375,
2400, 2425, 2450, 2475, 2500, 2525, 2550, 2575,
2600, 2625, 2650, 2675, 2700, 2725, 2750, 2775,
2800, 2825, 2850, 2875, 2900, 2925, 2950, 2975,
3000, 3025, 3050, 3075, 3100, 3125, 3150, 3175,
3200, 3225, 3250, 3275, 3300, 3325, 3350, 3375,
3400, 3425, 3450, 3475, 3500, 3525, 3550, 3575,
3600, 3625, 3650, 3675, 3700, 3725, 3750, 3775,
3800, 3825, 3850, 3875, 3900, 3925, 3950, 3975,
4000, 4025, 4050, 4075, 4100, 4125, 4150, 4175,
4200, 4225, 4250, 4275, 4300, 4325, 4350, 4375,
4400, 4425, 4450, 4475, 4500, 4525, 4550, 4575,
4600, 4625, 4650, 4675, 4700, 4725, 4750, 4775,
4800, 4825, 4850, 4875, 4900, 4925, 4950, 4975,
5000, 5025, 5050, 5075, 5100, 5125, 5150, 5175,
5200, 5225, 5250, 5275, 5300, 5325, 5350, 5375,
5400, 5425, 5450, 5475, 5500, 5525, 5550, 5575,
5600, 5625, 5650, 5675, 5700, 5725, 5750, 5775,
5800, 5825, 5850, 5875, 5900, 5925, 5950, 5975,
6000, 6025, 6050, 6075, 6100, 6125, 6150, 6175,
6200, 6225, 6250, 6275, 6300, 6325, 6350, 6375
};
int lookup66[] = {
0, 66, 132, 198, 264, 330, 396, 462,
528, 594, 660, 726, 792, 858, 924, 990,
1056, 1122, 1188, 1254, 1320, 1386, 1452, 1518,
1584, 1650, 1716, 1782, 1848, 1914, 1980, 2046,
2112, 2178, 2244, 2310, 2376, 2442, 2508, 2574,
2640, 2706, 2772, 2838, 2904, 2970, 3036, 3102,
3168, 3234, 3300, 3366, 3432, 3498, 3564, 3630,
3696, 3762, 3828, 3894, 3960, 4026, 4092, 4158,
4224, 4290, 4356, 4422, 4488, 4554, 4620, 4686,
4752, 4818, 4884, 4950, 5016, 5082, 5148, 5214,
5280, 5346, 5412, 5478, 5544, 5610, 5676, 5742,
5808, 5874, 5940, 6006, 6072, 6138, 6204, 6270,
6336, 6402, 6468, 6534, 6600, 6666, 6732, 6798,
6864, 6930, 6996, 7062, 7128, 7194, 7260, 7326,
7392, 7458, 7524, 7590, 7656, 7722, 7788, 7854,
7920, 7986, 8052, 8118, 8184, 8250, 8316, 8382,
8448, 8514, 8580, 8646, 8712, 8778, 8844, 8910,
8976, 9042, 9108, 9174, 9240, 9306, 9372, 9438,
9504, 9570, 9636, 9702, 9768, 9834, 9900, 9966,
10032, 10098, 10164, 10230, 10296, 10362, 10428, 10494,
10560, 10626, 10692, 10758, 10824, 10890, 10956, 11022,
11088, 11154, 11220, 11286, 11352, 11418, 11484, 11550,
11616, 11682, 11748, 11814, 11880, 11946, 12012, 12078,
12144, 12210, 12276, 12342, 12408, 12474, 12540, 12606,
12672, 12738, 12804, 12870, 12936, 13002, 13068, 13134,
13200, 13266, 13332, 13398, 13464, 13530, 13596, 13662,
13728, 13794, 13860, 13926, 13992, 14058, 14124, 14190,
14256, 14322, 14388, 14454, 14520, 14586, 14652, 14718,
14784, 14850, 14916, 14982, 15048, 15114, 15180, 15246,
15312, 15378, 15444, 15510, 15576, 15642, 15708, 15774,
15840, 15906, 15972, 16038, 16104, 16170, 16236, 16302,
16368, 16434, 16500, 16566, 16632, 16698, 16764, 16830
};
int lookup112[] = {
0, 112, 224, 336, 448, 560, 672, 784,
896, 1008, 1120, 1232, 1344, 1456, 1568, 1680,
1792, 1904, 2016, 2128, 2240, 2352, 2464, 2576,
2688, 2800, 2912, 3024, 3136, 3248, 3360, 3472,
3584, 3696, 3808, 3920, 4032, 4144, 4256, 4368,
4480, 4592, 4704, 4816, 4928, 5040, 5152, 5264,
5376, 5488, 5600, 5712, 5824, 5936, 6048, 6160,
6272, 6384, 6496, 6608, 6720, 6832, 6944, 7056,
7168, 7280, 7392, 7504, 7616, 7728, 7840, 7952,
8064, 8176, 8288, 8400, 8512, 8624, 8736, 8848,
8960, 9072, 9184, 9296, 9408, 9520, 9632, 9744,
9856, 9968, 10080, 10192, 10304, 10416, 10528, 10640,
10752, 10864, 10976, 11088, 11200, 11312, 11424, 11536,
11648, 11760, 11872, 11984, 12096, 12208, 12320, 12432,
12544, 12656, 12768, 12880, 12992, 13104, 13216, 13328,
13440, 13552, 13664, 13776, 13888, 14000, 14112, 14224,
14336, 14448, 14560, 14672, 14784, 14896, 15008, 15120,
15232, 15344, 15456, 15568, 15680, 15792, 15904, 16016,
16128, 16240, 16352, 16464, 16576, 16688, 16800, 16912,
17024, 17136, 17248, 17360, 17472, 17584, 17696, 17808,
17920, 18032, 18144, 18256, 18368, 18480, 18592, 18704,
18816, 18928, 19040, 19152, 19264, 19376, 19488, 19600,
19712, 19824, 19936, 20048, 20160, 20272, 20384, 20496,
20608, 20720, 20832, 20944, 21056, 21168, 21280, 21392,
21504, 21616, 21728, 21840, 21952, 22064, 22176, 22288,
22400, 22512, 22624, 22736, 22848, 22960, 23072, 23184,
23296, 23408, 23520, 23632, 23744, 23856, 23968, 24080,
24192, 24304, 24416, 24528, 24640, 24752, 24864, 24976,
25088, 25200, 25312, 25424, 25536, 25648, 25760, 25872,
25984, 26096, 26208, 26320, 26432, 26544, 26656, 26768,
26880, 26992, 27104, 27216, 27328, 27440, 27552, 27664,
27776, 27888, 28000, 28112, 28224, 28336, 28448, 28560
};
int lookup129[] = {
0, 129, 258, 387, 516, 645, 774, 903,
1032, 1161, 1290, 1419, 1548, 1677, 1806, 1935,
2064, 2193, 2322, 2451, 2580, 2709, 2838, 2967,
3096, 3225, 3354, 3483, 3612, 3741, 3870, 3999,
4128, 4257, 4386, 4515, 4644, 4773, 4902, 5031,
5160, 5289, 5418, 5547, 5676, 5805, 5934, 6063,
6192, 6321, 6450, 6579, 6708, 6837, 6966, 7095,
7224, 7353, 7482, 7611, 7740, 7869, 7998, 8127,
8256, 8385, 8514, 8643, 8772, 8901, 9030, 9159,
9288, 9417, 9546, 9675, 9804, 9933, 10062, 10191,
10320, 10449, 10578, 10707, 10836, 10965, 11094, 11223,
11352, 11481, 11610, 11739, 11868, 11997, 12126, 12255,
12384, 12513, 12642, 12771, 12900, 13029, 13158, 13287,
13416, 13545, 13674, 13803, 13932, 14061, 14190, 14319,
14448, 14577, 14706, 14835, 14964, 15093, 15222, 15351,
15480, 15609, 15738, 15867, 15996, 16125, 16254, 16383,
16512, 16641, 16770, 16899, 17028, 17157, 17286, 17415,
17544, 17673, 17802, 17931, 18060, 18189, 18318, 18447,
18576, 18705, 18834, 18963, 19092, 19221, 19350, 19479,
19608, 19737, 19866, 19995, 20124, 20253, 20382, 20511,
20640, 20769, 20898, 21027, 21156, 21285, 21414, 21543,
21672, 21801, 21930, 22059, 22188, 22317, 22446, 22575,
22704, 22833, 22962, 23091, 23220, 23349, 23478, 23607,
23736, 23865, 23994, 24123, 24252, 24381, 24510, 24639,
24768, 24897, 25026, 25155, 25284, 25413, 25542, 25671,
25800, 25929, 26058, 26187, 26316, 26445, 26574, 26703,
26832, 26961, 27090, 27219, 27348, 27477, 27606, 27735,
27864, 27993, 28122, 28251, 28380, 28509, 28638, 28767,
28896, 29025, 29154, 29283, 29412, 29541, 29670, 29799,
29928, 30057, 30186, 30315, 30444, 30573, 30702, 30831,
30960, 31089, 31218, 31347, 31476, 31605, 31734, 31863,
31992, 32121, 32250, 32379, 32508, 32637, 32766, 32895
};
}
void Bitmap2Yuv420p(boost::uint8_t *destination, boost::uint8_t *rgb,
const int &width, const int &height) {
boost::uint8_t *y;
boost::uint8_t *u;
boost::uint8_t *v;
boost::uint8_t *r;
boost::uint8_t *g;
boost::uint8_t *b;
std::size_t image_size = width * height;
std::size_t upos = image_size;
std::size_t vpos = upos + upos / 4;
for (std::size_t i = 0; i < image_size; ++i) {
r = rgb + 3 * i;
g = rgb + 3 * i + 1;
b = rgb + 3 * i + 2;
y = destination + i;
*y = ((lookup66[*r] + lookup129[*g] + lookup25[*b]) >> 8) + 16;
if (!((i / width) % 2) && !(i % 2)) {
u = destination + upos++;
v = destination + vpos++;
*u = ((lookup_m_38[*r] + lookup_m_74[*g] + lookup112[*b]) >> 8) + 128;
*v = ((lookup112[*r] + lookup_m_94[*g] + lookup_m_18[*b]) >> 8) + 128;
}
}
}
YUV color-spaces are a more efficient coding and reduce the bandwidth more than RGB capture can. Most video cards, therefore, render directly using YUV or luminance/chrominance images. The most important component for YUV capture is always the luminance, or Y component.
To convert from RGB to YUV or back, it is simplest to use RGB888 and YUV444. For YUV411, YUV422 and YUV420, the bytes need to be converted to YUV444 first.
From RGB to YUV Y = 0.299R + 0.587G + 0.114B U = 0.492 (B-Y) V = 0.877 (R-Y) It can also be represented as: Y = 0.299R + 0.587G + 0.114B U = -0.147R - 0.289G + 0.436B V = 0.615R - 0.515G - 0.100B From YUV to RGB R = Y + 1.140V G = Y - 0.395U - 0.581V B = Y + 2.032U.
YUV is not compressed RGB; rather, Y, B-Y and R-Y are the mathematical equivalent of RGB. See color space conversion and YUV/RGB conversion formulas.
Unroll your loop, and get rid of the if in the inner loop. But do not run over the image data 3 times, and it is even faster!
void Bitmap2Yuv420p_calc2(uint8_t *destination, uint8_t *rgb, size_t width, size_t height)
{
size_t image_size = width * height;
size_t upos = image_size;
size_t vpos = upos + upos / 4;
size_t i = 0;
for( size_t line = 0; line < height; ++line )
{
if( !(line % 2) )
{
for( size_t x = 0; x < width; x += 2 )
{
uint8_t r = rgb[3 * i];
uint8_t g = rgb[3 * i + 1];
uint8_t b = rgb[3 * i + 2];
destination[i++] = ((66*r + 129*g + 25*b) >> 8) + 16;
destination[upos++] = ((-38*r + -74*g + 112*b) >> 8) + 128;
destination[vpos++] = ((112*r + -94*g + -18*b) >> 8) + 128;
r = rgb[3 * i];
g = rgb[3 * i + 1];
b = rgb[3 * i + 2];
destination[i++] = ((66*r + 129*g + 25*b) >> 8) + 16;
}
}
else
{
for( size_t x = 0; x < width; x += 1 )
{
uint8_t r = rgb[3 * i];
uint8_t g = rgb[3 * i + 1];
uint8_t b = rgb[3 * i + 2];
destination[i++] = ((66*r + 129*g + 25*b) >> 8) + 16;
}
}
}
}
In my tests, this was about 25% faster than your accepted answer (VS 2010, depending on whether x86 or x64 is enabled.)
Do not access pointers more then once, copy the value to the stack and then use the value on the stack. (Aliasing)
...
int v_r = *r;
int v_g = *g;
int v_b = *b;
*y = ((lookup66[v_r] + lookup129[v_g] + lookup25[v_b]) >> 8) + 16;
...
On the other hand, you can do it in SSE without look-up tables and would do 8 pixels at once.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With