各种RGB转YUV的计算

// 按照opencv数据存储格式，函数传参顺序为b、g、r

void yuv2rgb_pixel(unsigned char b, unsigned char g, unsigned char r, unsigned char &y, unsigned char &u, unsigned char &v)
{
//rgb转yuv公式，参考资料<a target=_blank href="http://www.cnblogs.com/dwdxdy/p/3713990.html">http://www.cnblogs.com/dwdxdy/p/3713990.html</a>
y = 0.299 * r + 0.587 * g + 0.114 * b;
u = -0.1687 * r - 0.3313 * g + 0.5 * b + 128;
v = 0.5 * r - 0.4187 * g - 0.0813 * b + 128;
}

// rgb24转yuv422
void yuv2rgb_image(unsigned char *pRgb, unsigned char *pYuv, int width, int height)
{
//考虑到每两个rgb像素对应一个yuyv组合，因此，width应为2的倍数
int width1 = width = width / 2 * 2;

for (int h = 0; h < height; h++)
{
unsigned char *ptr1 = pRgb + h * width * 3;
unsigned char *ptr2 = pYuv + h * width * 2;

for (int w = 0; w < width1; w += 2)
{
unsigned char y1, u1, v1, y2, u2, v2;
yuv2rgb_pixel(*ptr1, *ptr1, *ptr1, y1, u1, v1);
yuv2rgb_pixel(*ptr1, *ptr1, *ptr1, y2, u2, v2);
//u、v分量取平均值
unsigned char u = (u1 + u2) / 2;
unsigned char v = (v1 + v2) / 2;
*ptr2 = y1;
*ptr2 = u;
*ptr2 = y2;
*ptr2 = v;
}
}
}

#define GetY(R,G,B) (0.257*(R)+0.504*(G)+0.98*(B)+16)
#define GetU(R,G,B) (0.148*(R)-0.291*(G)+0.439*(B)+128)
#define GetV(R,G,B) (0.439*(R)-0.368*(G)-0.071*(B)+128)

/*******************************************
yuv422Planar format 数据排列：
Y0Y1Y2Y3....
U0U2U4....
V1V3V5....
********************************************/
void  rgb2yuv422Planar(const unsigned char *rgbData, int height, int width, int widthstep, unsigned char*yuvData)
{
int i, j, temp;
unsigned char *lineUV = (unsigned char *)malloc(width * sizeof(unsigned char));//偶数下标位存U，奇数下标位存V
if (NULL == lineUV)
{
perror("malloc lineUV memory failed!");
exit(1);
}
memset(lineUV, 0, sizeof(width * sizeof(unsigned char)));
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++) //y
{
unsigned char b = rgbData[i*widthstep + 3 * j];
unsigned char g = rgbData[i*widthstep + 3 * j + 1];
unsigned char r = rgbData[i*widthstep + 3 * j + 2];
unsigned char *y = yuvData + i * width + j;
temp = (int)GetY(r, g, b);
*y = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);
if (0 == j % 2)
{
temp = (int)GetU(r, g, b);
lineUV[j] = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);

}
else
{
temp = (int)GetV(r, g, b);
lineUV[j] = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);
}
}
for (j = 0; j < width; j++) //u,v
{
if (0 == j % 2) //u
{
unsigned char *u = yuvData + height * width + i * width / 2 + j / 2;
*u = lineUV[j];
}
else //v
{
unsigned char *v = yuvData + height * width * 3 / 2 + i * width / 2 + (int)(j / 2);
*v = lineUV[j];
}
}
}

if (lineUV != NULL)
{
free(lineUV);
lineUV = NULL;
}

}
int  yuv422Packed2Planar(const unsigned char *packedData, unsigned char *planarData, int heigh, int width)
{
int index;
int i = 0;
int j = 0;
int k = 0;
unsigned char *y = planarData;
unsigned char *u = planarData + heigh * width;
unsigned char *v = planarData + heigh * width * 3 / 2;
bool flag = true;
for (index = 0; index < 2 * width*heigh;)
{
y[i++] = packedData[index++];
if (flag)
{
u[j++] = packedData[index++];
flag = false;
}
else
{
v[k++] = packedData[index++];
flag = true;
}
}
if (2 * width*heigh == index && width*heigh == i && width*heigh / 2 == j && j == k)
{
return 0;
}
else
{
return -1;
}
}

/*******************************
yuv422Packed format 数据排列：
Y0U0Y1V1Y2U2Y3V3.....
................
*******************************/
void  rgb2yuv422Packed(const unsigned char *rgbData, int height, int width, int widthstep, unsigned char *yuvData)
{
int i, j, temp;
int index = 0;

for (i = 0; i < height; i++)
{
bool bsetU = true;
for (j = 0; j < width; j++)
{
unsigned char r = rgbData[i*widthstep + 3 * j];
unsigned char g = rgbData[i*widthstep + 3 * j + 1];
unsigned char b = rgbData[i*widthstep + 3 * j + 2];
temp = (int)GetY(r, g, b);
yuvData[index++] = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);
if (bsetU) //
{
temp = (int)GetU(r, g, b);
yuvData[index++] = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);
bsetU = false;
}
else
{
temp = (int)GetV(r, g, b);
yuvData[index++] = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);
bsetU = true;
}
}
}

}

//************************************
// Method:    rgb24_to_yuv420p
// FullName:  rgb24_to_yuv420p
// Access:    public
// Returns:   int            返回值为0表示成功，否则失败
// Qualifier:                将RGB24格式图像转化为YUV420P格式，并进行相应的缩放
// Parameter: void * src    输入缓冲
// Parameter: int srcW        源宽
// Parameter: int srcH        源高
// Parameter: int srcSz        输入RGB图像数据大小=srcW*srcH*3
// Parameter: void * dst    输出缓冲
// Parameter: int dstW        目标宽
// Parameter: int dstH        目标高
// Parameter: int dstSz        输出的YUV图像数据大小=dstW*dstH*1.5
//************************************
int rgb24_to_yuv420p(void* src, int srcW, int srcH, int srcSz, void* dst, int dstW, int dstH, int dstSz)
{
if (!src || !dst || srcSz <= 0 || srcW <= 0 || srcH <= 0 || dstSz <= 0 || dstW <= 0 || dstH <= 0)
{
return -1;
}
if (srcSz != srcW * srcH * 3 || dstSz != dstW * dstH*1.5)
{
return -1;
}
auto* ctxt = sws_getContext(srcW, srcH, AV_PIX_FMT_BGR24, dstW, dstH, AV_PIX_FMT_YUV420P, 0, 0, 0, 0);
const int srcStride[1] = { 3 * srcW };
const int dstStride[4] = { dstW, dstW / 2, dstW / 2, 0 };
uint8_t * dstEx[4] = { 0 };
dstEx[0] = (uint8_t *)dst;
dstEx[1] = dstEx[0] + dstW * dstH;
dstEx[2] = dstEx[1] + dstW * dstH / 4;
sws_scale(ctxt, (const uint8_t * const *)&src, srcStride, 0, srcH, dstEx, dstStride);
sws_freeContext(ctxt);
return 0;
}

unsigned char clip_value(unsigned char x, unsigned char min_val, unsigned char  max_val) {
if (x > max_val) {
return max_val;
}
else if (x < min_val) {
return min_val;
}
else {
return x;
}
}

//RGB to YUV420
bool RGB24_TO_YUV420(unsigned char *RgbBuf, int w, int h, unsigned char *yuvBuf)
{
unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB;
memset(yuvBuf, 0, w*h * 3 / 2);
ptrY = yuvBuf;
ptrU = yuvBuf + w * h;
ptrV = ptrU + (w*h * 1 / 4);
unsigned char y, u, v, r, g, b;
for (int j = 0; j < h; j++) {
ptrRGB = RgbBuf + w * j * 3;
for (int i = 0; i < w; i++) {

r = *(ptrRGB++);
g = *(ptrRGB++);
b = *(ptrRGB++);
y = (unsigned char)((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = (unsigned char)((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = (unsigned char)((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
*(ptrY++) = clip_value(y, 0, 255);
if (j % 2 == 0 && i % 2 == 0) {
*(ptrU++) = clip_value(u, 0, 255);
}
else {
if (i % 2 == 0) {
*(ptrV++) = clip_value(v, 0, 255);
}
}
}
}
return true;
}

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客