前言
提示:书写目的是为对YUV与RGB存储格式的了解,该代码可以直接用,也存在待优化的地方,后续优化,还请大家多多指点
编译环境:
LINUX下编译的,有gcc编译工具即可
看图工具:
后续附上
文件列表
- app_main.c 主函数
- rgbtoyuv.c 处理文件
- rgbtoyuv.h 头文件
- Makefile 编译规则
1、主函数app_main.c
#include <stdio.h>
#include <stdlib.h>
#include "rgbtoyuv.h"
int main()
{
//make_rgb24_colorbar();
char *RGBfilename = "rgb888.rgb";
char *DstRGBfilename_1 = "dst_rgb888_1.rgb";
char *DstRGBfilename_2 = "dst_rgb888_2.rgb";
char *DstRGBfilename_3 = "dst_rgb888_3.rgb";
char *DstRGBfilename_4 = "dst_rgb888_4.rgb";
char *DstRGBfilename_5 = "dst_rgb888_5.rgb";
char *DstRGBfilename_6 = "dst_rgb888_6.rgb";
char *YUV420p_I420_filename = "yuv420p_I420.yuv";
char *YUV420p_YV12_filename = "yuv420p_YV12.yuv";
char *YUV422p_YU16_filename = "yuv422p_YU16.yuv";
char *YUV422p_YV16_filename = "yuv422p_YV16.yuv";
char *YUV444p_I444_filename = "yuv444p_I444.yuv";
char *YUV444p_YV24_filename = "yuv444p_YV24.yuv";
int iRgbSize = 0;
int iRet = 0, i = 0;
unsigned char c;
FILE *fp_rgb = fopen(RGBfilename, "wb+");
FILE *fp_rgb_dst_1 = fopen(DstRGBfilename_1, "wb+");
FILE *fp_rgb_dst_2 = fopen(DstRGBfilename_2, "wb+");
FILE *fp_rgb_dst_3 = fopen(DstRGBfilename_3, "wb+");
FILE *fp_rgb_dst_4 = fopen(DstRGBfilename_4, "wb+");
FILE *fp_rgb_dst_5 = fopen(DstRGBfilename_5, "wb+");
FILE *fp_rgb_dst_6 = fopen(DstRGBfilename_6, "wb+");
FILE *fp_YUV420p_I420 = fopen(YUV420p_I420_filename, "wb+");
FILE *fp_yuv420p_YV12 = fopen(YUV420p_YV12_filename, "wb+");
FILE *fp_yuv422p_YU16 = fopen(YUV422p_YU16_filename, "wb+");
FILE *fp_yuv422p_YV16 = fopen(YUV422p_YV16_filename, "wb+");
FILE *fp_yuv444p_I444 = fopen(YUV444p_I444_filename, "wb+");
FILE *fp_yuv444p_YV24 = fopen(YUV444p_YV24_filename, "wb+");
//-----------------------1、生成 RGB888 图像 -----------------------------
iRgbSize = iamge_creat_rgb24(fp_rgb, IMAGE_W, IMAGE_H);
if (iRgbSize == ERROR)
{
printf(" iamge_creat_rgb24 error \n");
return 0;
}
fflush(fp_rgb);
//---打印RGB实际数据
/*
fseek(fp_rgb, 0, SEEK_SET);
for (i = 0; i < IMAGE_W*IMAGE_H * 3; i++)
{
if (i % (IMAGE_W * 3) == 0)
printf("\n");
fread(&c, 1, 1, fp_rgb);
printf("%3d ",c);
}
*/
printf("-----------write file %s totle is %d bit \n", RGBfilename, iRgbSize);
//-------------------------------- 2、图像转换 RGB_TO_YUV -----------------------------
//---YUV420p
iRet = image_rgb888_to_yuv420p(fp_rgb, fp_YUV420p_I420, IMAGE_W, IMAGE_H, YUV420P_I420);
if(iRet == ERROR)
{
printf(" image_rgb88_to_yuv420p error \n");
goto RELASE;
}
fflush(fp_YUV420p_I420);
printf(" [%d] image_rgb888_to_yuv420p finish !!!!! \n",__LINE__);
iRet = image_rgb888_to_yuv420p(fp_rgb, fp_yuv420p_YV12, IMAGE_W, IMAGE_H, YUV420P_YV12);
if (iRet == ERROR)
{
printf(" image_rgb88_to_yuv420p error \n");
goto RELASE;
}
fflush(fp_yuv420p_YV12);
printf(" [%d] image_rgb888_to_yuv420p finish !!!!! \n",__LINE__);
//---YUV422p
iRet = image_rgb888_to_yuv422p(fp_rgb, fp_yuv422p_YU16, IMAGE_W, IMAGE_H, YUV422P_YU16);
if (iRet == ERROR)
{
printf(" image_rgb88_to_yuv420p error \n");
goto RELASE;
}
fflush(fp_yuv422p_YU16);
printf(" [%d] image_rgb888_to_yuv422p finish !!!!! \n",__LINE__);
iRet = image_rgb888_to_yuv422p(fp_rgb, fp_yuv422p_YV16, IMAGE_W, IMAGE_H, YUV422P_YV16);
if (iRet == ERROR)
{
printf(" image_rgb888_to_yuv422p error \n");
goto RELASE;
}
fflush(fp_yuv422p_YV16);
printf(" [%d] image_rgb888_to_yuv422p finish !!!!! \n",__LINE__);
iRet = image_rgb888_to_yuv444p(fp_rgb, fp_yuv444p_I444, IMAGE_W, IMAGE_H, YUV444P_I444);
if (iRet == ERROR)
{
printf(" image_rgb888_to_yuv444p error \n");
goto RELASE;
}
fflush(fp_yuv444p_I444);
iRet = image_rgb888_to_yuv444p(fp_rgb, fp_yuv444p_YV24, IMAGE_W, IMAGE_H, YUV444P_YV24);
if (iRet == ERROR)
{
printf(" image_rgb888_to_yuv444p error \n");
goto RELASE;
}
fflush(fp_yuv444p_YV24);
//--------------------------------------------------------------------------------------------
//-------------------------------------- YUV to RGB------------------------------------------------
iRet = image_yuv444p_to_rgb888(fp_yuv444p_YV24, fp_rgb_dst_1, IMAGE_W, IMAGE_H, YUV444P_YV24);
if (iRet == ERROR)
{
printf(" image_yuv444p_to_rgb888 error \n");
goto RELASE;
}
fflush(fp_rgb_dst_1);
iRet = image_yuv444p_to_rgb888(fp_yuv444p_I444, fp_rgb_dst_2, IMAGE_W, IMAGE_H, YUV444P_I444);
if (iRet == ERROR)
{
printf(" image_yuv444p_to_rgb888 error \n");
goto RELASE;
}
fflush(fp_rgb_dst_2);
iRet = image_yuv420p_to_rgb888(fp_yuv420p_YV12, fp_rgb_dst_3, IMAGE_W, IMAGE_H, YUV420P_YV12);
if (iRet == ERROR)
{
printf(" image_yuv420p_to_rgb888 error \n");
goto RELASE;
}
fflush(fp_rgb_dst_3);
iRet = image_yuv420p_to_rgb888(fp_YUV420p_I420, fp_rgb_dst_4, IMAGE_W, IMAGE_H, YUV420P_I420);
if (iRet == ERROR)
{
printf(" image_yuv420p_to_rgb888 error \n");
goto RELASE;
}
fflush(fp_rgb_dst_4);
iRet = image_yuv422p_to_rgb888(fp_yuv422p_YV16, fp_rgb_dst_5, IMAGE_W, IMAGE_H, YUV422P_YV16);
if (iRet == ERROR)
{
printf(" image_yuv422p_to_rgb888 error \n");
goto RELASE;
}
fflush(fp_rgb_dst_5);
iRet = image_yuv422p_to_rgb888(fp_yuv422p_YU16, fp_rgb_dst_6, IMAGE_W, IMAGE_H, YUV422P_YU16);
if (iRet == ERROR)
{
printf(" image_yuv422p_to_rgb888 error \n");
goto RELASE;
}
fflush(fp_rgb_dst_6);
printf("---------------------image change OK \n");
fclose(fp_rgb);
fclose(fp_YUV420p_I420);
fclose(fp_yuv420p_YV12);
fclose(fp_yuv422p_YU16);
fclose(fp_yuv422p_YV16);
fclose(fp_yuv444p_I444);
fclose(fp_yuv444p_YV24);
fclose(fp_rgb_dst_1);
fclose(fp_rgb_dst_2);
fclose(fp_rgb_dst_3);
fclose(fp_rgb_dst_4);
fclose(fp_rgb_dst_5);
fclose(fp_rgb_dst_6);
return OK;
//----------------------------- 3、关闭句柄 -------------------------------------
RELASE:
fclose(fp_rgb);
fclose(fp_YUV420p_I420);
fclose(fp_yuv420p_YV12);
fclose(fp_yuv422p_YU16);
fclose(fp_yuv422p_YV16);
fclose(fp_yuv444p_I444);
fclose(fp_yuv444p_YV24);
fclose(fp_rgb_dst_1);
fclose(fp_rgb_dst_2);
fclose(fp_rgb_dst_3);
fclose(fp_rgb_dst_4);
fclose(fp_rgb_dst_5);
fclose(fp_rgb_dst_6);
return 0;
}
2、处理文件rgbtoyuv.c
/******************************************************************
*
* 待优化:
* 1、转换函数中的写操作fread操作的参数
* 2、malloc改为申请大空间 ,让程序不需要自己计算不同YUV格式需要的空间大小
*
*
*
*
*
*
*
*************************************************************/
#include "rgbtoyuv.h"
#define IMAGE_PTR_CHEAK(p) \
{\
if(p == NULL)\
{ \
printf(" p == NULL !!!!!!");\
return ERROR; \
} \
}
#define IMAGE_ERROR(str) \
{\
printf("[%s] [%d] : IMAGE_ERROR : %s \n", __FUNCTION__, __LINE__, str);\
}
#define IMAGE_YUV420_SIZE(w, h) ((w) * (h) * 3 / 2) /**<---根据数据格式来判断大小 YUV420 按照 w * h * 3 * (3/6)*/
#define IMAGE_YUV422_SIZE(w, h) ((w) * (h) * 2) /**<---根据数据格式来判断大小 YUV422 按照 w * h * 3 * (4/6)*/
#define IMAGE_YUV444_SIZE(w, h) ((w) * (h) * 3) /**<---根据数据格式来判断大小 YUV444 按照 w * h * 3 * (3/3)*/
/**
* @brief 限幅像素的取值范围(内部函数)
* @param [in] val 被限幅的像素值
* @param [in] min_val 限幅最低值,建议最低为0
* @param [in] max_val 限幅最高值,建议最高为255
* @return 返回限幅后的像素值
*/
static inline unsigned char image_clip_value(unsigned char val, unsigned char min_val, unsigned char max_val)
{
/*
if (val > max_val)
{
return max_val;
}
else if (val < min_val)
{
return min_val;
}
else
{
return val;
}
*/
return val > max_val ? max_val : (val < min_val ? min_val : val);
}
/**
* @brief 将RGB24 图像转换 YUV420p YUV数据(内部函数)
* @param [out] pYUVBuf 输出的YUV420p图像数据
* @param [in] YUVsize 输出的YUV420p图像数据
* @param [in] RGBBuf 输入的RGB图像数据
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV420P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
static int rgb_to_yuv420p(unsigned char *pYUVBuf, unsigned int YUVsize, unsigned char *RGBBuf, int w, int h, YUV420P_MODE_E mode)
{
int i = 0, j = 0;
unsigned char y, u, v, r, g, b;
unsigned char *ptrY, *ptrU, *ptrV, *ptrRGB;
IMAGE_PTR_CHEAK(pYUVBuf);
IMAGE_PTR_CHEAK(RGBBuf);
if (YUVsize < (unsigned int)IMAGE_YUV420_SIZE(w, h))
{
printf("YUVsize too small ,YUVsize = [%d], need size > [%d]\n", YUVsize, (unsigned int)IMAGE_YUV420_SIZE(w, h));
return ERROR;
}
//---YUV420p存储V、U的两种方式区分:(每4个Y,公用一个U和V分量)
ptrY = pYUVBuf;
if (mode == YUV420P_I420)
{
ptrU = pYUVBuf + w*h;
ptrV = ptrU + (w*h * 1 / 4);
}
else if(mode == YUV420P_YV12)
{
ptrV = pYUVBuf + w*h;
ptrU = ptrV + (w*h * 1 / 4);
}
else
{
IMAGE_ERROR(" ------YUV420p mode dismatch !!!!!! ");
return ERROR;
}
//---数据转换
for (j = 0; j < h; j++)
{
ptrRGB = RGBBuf + w*j*3;
for (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) = image_clip_value(y, 0, 255);
printf("Y");
ptrY++;
//---根据数据格式给每个像素上填充对应的Y、U、V分量
if (j % 2 == 0 && i % 2 == 0)
{
*(ptrU) = image_clip_value(u, 0, 255);
printf("U");
ptrU++;
}
else
{
if (i % 2 == 0)
{
*(ptrV) = image_clip_value(v, 0, 255);
printf("V");
ptrV++;
}
}
}
printf(" [j = %d] \n", j);
}
return OK;
}
/**
* @brief 将RGB24 图像转换 YUV422p YUV数据(内部函数)
* @param [out] pYUVBuf 输出的YUV420p图像数据
* @param [in] YUVsize 输出的YUV420p图像数据
* @param [in] RGBBuf 输入的RGB图像数据
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV422P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
static int rgb_to_yuv422p(unsigned char *pYUVBuf, unsigned int YUVsize, unsigned char *RGBBuf, int w, int h, YUV422P_MODE_E mode)
{
int i = 0, j = 0;
unsigned char y, u, v, r, g, b;
unsigned char *ptrY, *ptrU, *ptrV, *ptrRGB;
IMAGE_PTR_CHEAK(pYUVBuf);
IMAGE_PTR_CHEAK(RGBBuf);
if (YUVsize < (unsigned int)IMAGE_YUV422_SIZE(w, h))
{
printf("YUVsize too small ,YUVsize = [%d], need size > [%d]\n", YUVsize, (unsigned int)IMAGE_YUV422_SIZE(w, h));
return ERROR;
}
//---YUV422p存储V、U的两种方式区分:(每2个Y,公用一个U和V分量)
ptrY = pYUVBuf;
if (mode == YUV422P_YU16)
{
ptrU = pYUVBuf + w*h;
ptrV = ptrU + (w*h / 2);
}
else if (mode == YUV422P_YV16)
{
ptrV = pYUVBuf + w*h;
ptrU = ptrV + (w*h / 2);
}
else
{
IMAGE_ERROR(" ------YUV422p mode dismatch !!!!!! ");
return ERROR;
}
//---数据转换
for (j = 0; j < h; j++)
{
ptrRGB = RGBBuf + w*j * 3;
for (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) = image_clip_value(y, 0, 255);
printf("Y");
ptrY++;
//---根据数据格式给每个像素上填充对应的Y、U、V分量
if (i % 2 == 0)
{
*(ptrV) = image_clip_value(v, 0, 255);
printf("V");
ptrV++;
*(ptrU) = image_clip_value(u, 0, 255);
printf("U");
ptrU++;
}
}
printf(" [j = %d] \n", j);
}
return OK;
}
/**
* @brief 将RGB24 图像转换 YUV444p YUV数据(内部函数)
* @param [out] pYUVBuf 输出的YUV420p图像数据
* @param [in] YUVsize 输出的YUV420p图像数据
* @param [in] RGBBuf 输入的RGB图像数据
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV444P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
static int rgb_to_yuv444p(unsigned char *pYUVBuf, unsigned int YUVsize, unsigned char *RGBBuf, int w, int h, YUV444P_MODE_E mode)
{
int i = 0, j = 0;
unsigned char y, u, v, r, g, b;
unsigned char *ptrY, *ptrU, *ptrV, *ptrRGB;
IMAGE_PTR_CHEAK(pYUVBuf);
IMAGE_PTR_CHEAK(RGBBuf);
if (YUVsize < (unsigned int)IMAGE_YUV444_SIZE(w, h))
{
printf("YUVsize too small ,YUVsize = [%d], need size > [%d]\n", YUVsize, (unsigned int)IMAGE_YUV444_SIZE(w, h));
return ERROR;
}
//---YUV444p存储V、U的两种方式区分:(不丢失信息,无损)
ptrY = pYUVBuf;
if (mode == YUV444P_I444)
{
ptrU = pYUVBuf + w*h;
ptrV = ptrU + (w*h);
}
else if (mode == YUV444P_YV24)
{
ptrV = pYUVBuf + w*h;
ptrU = ptrV + (w*h);
}
else
{
IMAGE_ERROR(" ------YUV444p mode dismatch !!!!!! ");
return ERROR;
}
//---数据转换
for (j = 0; j < h; j++)
{
ptrRGB = RGBBuf + w*j * 3;
for (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) = image_clip_value(y, 0, 255);
printf("Y");
ptrY++;
//---根据数据格式给每个像素上填充对应的Y、U、V分量
*(ptrV) = image_clip_value(v, 0, 255);
printf("V");
ptrV++;
*(ptrU) = image_clip_value(u, 0, 255);
printf("U");
ptrU++;
}
printf(" [j = %d] \n", j);
}
return OK;
}
/**
* @brief 将YUV422p 图像转换 RGB888(内部函数)
* @param [out] RGBBuf 输出的RGB图像数据
* @param [in] pYUVBuf 输入的YUV422p图像数据BUFF
* @param [in] YUVsize 输入的YUV422p图像数据BUFF大小
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV420P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
static int yuv420p_to_rgb888(unsigned char *RGBBuf, unsigned char *pYUVBuf, unsigned int YUVsize, int w, int h, YUV420P_MODE_E mode)
{
int i = 0, j = 0;
unsigned char *ptrY, *ptrU, *ptrV;
unsigned char y, u, v;
unsigned char r, g, b;
unsigned int nv_index = 0, rgb_index = 0;
IMAGE_PTR_CHEAK(pYUVBuf);
IMAGE_PTR_CHEAK(RGBBuf);
if (YUVsize < (unsigned int)IMAGE_YUV420_SIZE(w, h))
{
printf("YUVsize too small ,YUVsize = [%d], need size > [%d]\n", YUVsize, (unsigned int)IMAGE_YUV420_SIZE(w, h));
return ERROR;
}
//---YUV420p存储V、U的两种方式区分:(每4个Y,公用一个U和V分量)
ptrY = pYUVBuf;
if (mode == YUV420P_I420)
{
ptrU = pYUVBuf + w*h;
ptrV = ptrU + (w*h * 1 / 4);
}
else if(mode == YUV420P_YV12)
{
ptrV = pYUVBuf + w*h;
ptrU = ptrV + (w*h * 1 / 4);
}
else
{
IMAGE_ERROR(" ------YUV420p mode dismatch !!!!!! ");
return ERROR;
}
//---行扫描的方式
for (i = 0; i < h; i++)
{
for (j = 0; j < w ; j++, rgb_index++ )
{
nv_index = (i / 2) * (w / 2) + (j / 2);
y = *(ptrY++);
u = *(ptrU + nv_index);
v = *(ptrV + nv_index);
r = y + ((351 * (v - 128)) >> 8); //r
g = y - ((179 * (v - 128) + 86 * (u - 128)) >> 8); //g
b = y + ((443 * (u - 128)) >> 8); //b
r = image_clip_value(r, 0, 255);
g = image_clip_value(g, 0, 255);
b = image_clip_value(b, 0, 255);
RGBBuf[rgb_index * 3 + 0] = b;
RGBBuf[rgb_index * 3 + 1] = g;
RGBBuf[rgb_index * 3 + 2] = r;
}
}
}
/**
* @brief 将YUV422p 图像转换 RGB888(内部函数)
* @param [out] RGBBuf 输出的RGB图像数据
* @param [in] pYUVBuf 输入的YUV422p图像数据BUFF
* @param [in] YUVsize 输入的YUV422p图像数据BUFF大小
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV422P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
static int yuv422p_to_rgb888(unsigned char *RGBBuf, unsigned char *pYUVBuf, unsigned int YUVsize, int w, int h, YUV422P_MODE_E mode)
{
int i = 0, j = 0;
unsigned char *ptrY, *ptrU, *ptrV;
unsigned char y, u, v;
unsigned char r, g, b;
unsigned int nv_index = 0, rgb_index = 0;
//---YUV422p存储V、U的两种方式区分:(每4个Y,公用一个U和V分量)
ptrY = pYUVBuf;
if (mode == YUV422P_YU16)
{
ptrU = pYUVBuf + w*h;
ptrV = ptrU + (w*h * 1 / 2);
}
else if(mode == YUV422P_YV16)
{
ptrV = pYUVBuf + w*h;
ptrU = ptrV + (w*h * 1 / 2);
}
else
{
IMAGE_ERROR(" ------YUV422p mode dismatch !!!!!! ");
return ERROR;
}
//---行扫描的方式
for (i = 0; i < h; i++)
{
for (j = 0; j < w ; j++, rgb_index++ )
{
nv_index = (i) * (w / 2) + (j / 2);
y = *(ptrY++);
u = *(ptrU + nv_index);
v = *(ptrV + nv_index);
r = y + ((351 * (v - 128)) >> 8); //r
g = y - ((179 * (v - 128) + 86 * (u - 128)) >> 8); //g
b = y + ((443 * (u - 128)) >> 8); //b
r = image_clip_value(r, 0, 255);
g = image_clip_value(g, 0, 255);
b = image_clip_value(b, 0, 255);
RGBBuf[rgb_index * 3 + 0] = b;
RGBBuf[rgb_index * 3 + 1] = g;
RGBBuf[rgb_index * 3 + 2] = r;
}
}
}
/**
* @brief 将YUV444p 图像转换 RGB888(内部函数)
* @param [-ut] RGBBuf 输出的RGB图像数据
* @param [in] pYUVBuf 输入的YUV444p图像数据BUFF
* @param [in] YUVsize 输入的YUV444p图像数据BUFF大小
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV444P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
static int yuv444p_to_rgb888(unsigned char *RGBBuf, unsigned char *pYUVBuf, unsigned int YUVsize, int w, int h, YUV444P_MODE_E mode)
{
int i = 0, j = 0;
unsigned char *ptrY, *ptrU, *ptrV;
unsigned char y, u, v;
unsigned char r, g, b;
unsigned int nv_index = 0, rgb_index = 0;
//---YUV444p存储V、U的两种方式区分:(每4个Y,公用一个U和V分量)
ptrY = pYUVBuf;
if (mode == YUV444P_I444)
{
ptrU = pYUVBuf + w*h;
ptrV = ptrU + (w*h);
}
else if(mode == YUV444P_YV24)
{
ptrV = pYUVBuf + w*h;
ptrU = ptrV + (w*h);
}
else
{
IMAGE_ERROR(" ------YUV444p mode dismatch !!!!!! ");
return ERROR;
}
//---行扫描的方式
for (i = 0; i < h; i++)
{
for (j = 0; j < w ; j++, rgb_index++ )
{
y = *(ptrY++);
u = *(ptrU++);
v = *(ptrV++);
r = y + ((351 * (v - 128)) >> 8); //r
g = y - ((179 * (v - 128) + 86 * (u - 128)) >> 8); //g
b = y + ((443 * (u - 128)) >> 8); //b
r = image_clip_value(r, 0, 255);
g = image_clip_value(g, 0, 255);
b = image_clip_value(b, 0, 255);
RGBBuf[rgb_index * 3 + 0] = b;
RGBBuf[rgb_index * 3 + 1] = g;
RGBBuf[rgb_index * 3 + 2] = r;
}
}
}
/**
* @brief 生成RGB24的图像
* @param [in] filename 图像文件名 .rgb格式
* @param [in] imageW 生成图像的宽度
* @param [in] imageH 生成图像的高度
* @return 成功返回图像的大小
*/
int iamge_creat_rgb24(FILE *fp_rgb, int imageW, int imageH)
{
int i = 0, imageSize = 0;
unsigned char chr = 0;
IMAGE_PTR_CHEAK(fp_rgb);
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
for (i = 0; i < imageW * imageH; i++)
{
if (i < imageW * imageH / 3)
{
chr = 0;
fwrite(&chr, 1, 1, fp_rgb);
chr = 0;
fwrite(&chr, 1, 1, fp_rgb);
chr = 255;
fwrite(&chr, 1, 1, fp_rgb);
}
else if (i < imageW * imageH * 2 / 3)
{
chr = 0;
fwrite(&chr, 1, 1, fp_rgb);
chr = 255;
fwrite(&chr, 1, 1, fp_rgb);
chr = 0;
fwrite(&chr, 1, 1, fp_rgb);
}
else
{
chr = 255;
fwrite(&chr, 1, 1, fp_rgb);
chr = 0;
fwrite(&chr, 1, 1, fp_rgb);
chr = 0;
fwrite(&chr, 1, 1, fp_rgb);
}
imageSize++;
}
//---返回RGB 888 对应的大小 imageSize*3等价于w * h * 3
return imageSize*3;
}
/**
* @brief rgb888 (rgb24) 转换为yuv420p
* @param [in] fp_rgb RGB图像文件句柄
* @param [in] fp_yuv YUV图像文件句柄
* @param [in] imageW 生成图像的宽度
* @param [in] imageH 生成图像的高度
* @param [in] YUV420P_MODE_E YUV420p的格式
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_rgb888_to_yuv420p(FILE *fp_rgb, FILE *fp_yuv, int imageW, int imageH, YUV420P_MODE_E YUVmode)
{
unsigned char *pYUVBuff;
int iRet = -1;
unsigned int i = 0;
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
if (fp_rgb == NULL || fp_yuv == NULL)
{
IMAGE_ERROR("fp_rgb or fp_yuv open failed !!!!!!!");
return ERROR;
}
//---1、获取数据 (从开始位置读全部大小写入到转换函数RGB24_TO_YUV420P()的输入数组中)
memset(s_uRGB, 0, sizeof(s_uRGB));
fseek(fp_rgb, 0, SEEK_SET);
iRet = fread(s_uRGB, 1, imageW * imageH * 3, fp_rgb);
//---2、动态申请存放YUV的BUFF
pYUVBuff = (unsigned char *)malloc(IMAGE_YUV420_SIZE(imageW, imageH)+1);
if (pYUVBuff == NULL)
{
IMAGE_ERROR("malloc pYUVBuff failed !!!!!!!!!");
return ERROR;
}
//---3、调用对应转换函数
iRet = rgb_to_yuv420p(pYUVBuff, imageW * imageH * 3 / 2, s_uRGB, imageW, imageH, YUVmode);
if(iRet == ERROR)
{
IMAGE_ERROR("rgb_to_yuv420p failed !!!!!!!!!");
free(pYUVBuff);
return ERROR;
}
//---4、将YUV数据写入文件
fseek(fp_yuv, 0, SEEK_SET);
fwrite(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
//---5、再次读文件,验证数据
/*
memset(pYUVBuff, 0, imageW * imageH * 3 / 2);
fseek(fp_yuv, 0, SEEK_SET);
fread(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
for(i = 0; i < imageW * imageH * 3 / 2 ;i++)
{
if (i % imageW == 0)
printf("\n");
printf("%3d ", pYUVBuff[i]);
}printf("\n");
*/
free(pYUVBuff);
return OK;
}
/**
* @brief rgb888 (rgb24) 转换为yuv422p
* @param [in] fp_rgb RGB图像文件句柄
* @param [in] fp_yuv YUV图像文件句柄
* @param [in] imageW 生成图像的宽度
* @param [in] imageH 生成图像的高度
* @param [in] YUV422P_MODE_E YUV422p的格式
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_rgb888_to_yuv422p(FILE *fp_rgb, FILE *fp_yuv, int imageW, int imageH, YUV422P_MODE_E YUVmode)
{
unsigned char *pYUVBuff;
int iRet = -1;
unsigned int i = 0;
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
if (fp_rgb == NULL || fp_yuv == NULL)
{
IMAGE_ERROR("fp_rgb or fp_yuv open failed !!!!!!!");
return ERROR;
}
//---1、获取数据 (从开始位置读全部大小写入到转换函数RGB24_TO_YUV420P()的输入数组中)
memset(s_uRGB, 0, sizeof(s_uRGB));
fseek(fp_rgb, 0, SEEK_SET);
iRet = fread(s_uRGB, 1, imageW * imageH * 3, fp_rgb); //--------------待优化!!!!!!!!!
//---2、动态申请存放YUV的BUFF
pYUVBuff = (unsigned char *)malloc(((unsigned int)IMAGE_YUV422_SIZE(imageW, imageH))+1);
if (pYUVBuff == NULL)
{
IMAGE_ERROR("malloc pYUVBuff failed !!!!!!!!!");
return ERROR;
}
//---3、调用对应转换函数
iRet = rgb_to_yuv422p(pYUVBuff, (unsigned int)IMAGE_YUV422_SIZE(imageW, imageH), s_uRGB, imageW, imageH, YUVmode); //----待优化输入数据大小
if (iRet == ERROR)
{
IMAGE_ERROR("rgb_to_yuv422p failed !!!!!!!!!");
free(pYUVBuff);
return ERROR;
}
//---4、将YUV数据写入文件
fseek(fp_yuv, 0, SEEK_SET);
fwrite(pYUVBuff, 1, imageW * imageH * 2, fp_yuv);
//---5、再次读文件,验证数据
/*
memset(pYUVBuff, 0, imageW * imageH * 3 / 2);
fseek(fp_yuv, 0, SEEK_SET);
fread(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
for(i = 0; i < imageW * imageH * 3 / 2 ;i++)
{
if (i % imageW == 0)
printf("\n");
printf("%3d ", pYUVBuff[i]);
}printf("\n");
*/
free(pYUVBuff);
return OK;
}
/**
* @brief rgb888 (rgb24) 转换为yuv444p
* @param [in] fp_rgb RGB图像文件句柄
* @param [in] fp_yuv YUV图像文件句柄
* @param [in] imageW 生成图像的宽度
* @param [in] imageH 生成图像的高度
* @param [in] YUV444P_MODE_E YUV444p的格式
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_rgb888_to_yuv444p(FILE *fp_rgb, FILE *fp_yuv, int imageW, int imageH, YUV444P_MODE_E YUVmode)
{
unsigned char *pYUVBuff;
int iRet = -1;
unsigned int i = 0;
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
if (fp_rgb == NULL || fp_yuv == NULL)
{
IMAGE_ERROR("fp_rgb or fp_yuv open failed !!!!!!!");
return ERROR;
}
//---1、获取数据 (从开始位置读全部大小写入到转换函数RGB24_TO_YUV444P()的输入数组中)
memset(s_uRGB, 0, sizeof(s_uRGB));
fseek(fp_rgb, 0, SEEK_SET);
iRet = fread(s_uRGB, 1, imageW * imageH * 3, fp_rgb); //--------------待优化!!!!!!!!!
//---2、动态申请存放YUV的BUFF
pYUVBuff = (unsigned char *)malloc(IMAGE_YUV444_SIZE(imageW, imageH)+1);
if (pYUVBuff == NULL)
{
IMAGE_ERROR("malloc pYUVBuff failed !!!!!!!!!");
return ERROR;
}
//---3、调用对应转换函数
iRet = rgb_to_yuv444p(pYUVBuff, imageW * imageH * 3, s_uRGB, imageW, imageH, YUVmode);
if (iRet == ERROR)
{
IMAGE_ERROR("rgb_to_yuv422p failed !!!!!!!!!");
free(pYUVBuff);
return ERROR;
}
//---4、将YUV数据写入文件
fseek(fp_yuv, 0, SEEK_SET);
fwrite(pYUVBuff, 1, imageW * imageH * 3, fp_yuv);
//---5、再次读文件,验证数据
/*
memset(pYUVBuff, 0, imageW * imageH * 3 / 2);
fseek(fp_yuv, 0, SEEK_SET);
fread(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
for(i = 0; i < imageW * imageH * 3 / 2 ;i++)
{
if (i % imageW == 0)
printf("\n");
printf("%3d ", pYUVBuff[i]);
}printf("\n");
*/
free(pYUVBuff);
return OK;
}
/**
* @brief yuv420p 转换为 rgb888 (rgb24)
* @param [in] fp_yuv RGB图像文件句柄
* @param [in] fp_rgb YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV420P_MODE_E 输入图片的YUV420p的格式类型
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_yuv420p_to_rgb888(FILE *fp_yuv, FILE *fp_rgb, int imageW, int imageH, YUV420P_MODE_E YUVmode)
{
unsigned char *pRGBBuff;
int iRet = -1;
unsigned int i = 0;
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
if (fp_rgb == NULL || fp_yuv == NULL)
{
IMAGE_ERROR("fp_rgb or fp_yuv open failed !!!!!!!");
return ERROR;
}
//---1、获取数据 (从开始位置读全部大小写入到转换函数 yuv420p_to_rgb888() 的输入数组中)
memset(s_uYUV, 0, sizeof(s_uYUV));
fseek(fp_yuv, 0, SEEK_SET);
iRet = fread(s_uYUV, 1, (uint32)(imageW * imageH * 3 / 2), fp_yuv); //--------------待优化!!!!!!!!!
//---2、动态申请存放RGB的BUFF
pRGBBuff = (unsigned char *)malloc(imageW * imageH * 3 + 1);
if (pRGBBuff == NULL)
{
IMAGE_ERROR("malloc pRGBBuff failed !!!!!!!!!");
return ERROR;
}
//---3、调用对应转换函数
iRet = yuv420p_to_rgb888(pRGBBuff, s_uYUV, sizeof(s_uYUV), imageW, imageH, YUVmode);
if (iRet == ERROR)
{
IMAGE_ERROR("yuv420p_to_rgb888 failed !!!!!!!!!");
free(pRGBBuff);
return ERROR;
}
//---4、将RGB数据写入文件
fseek(fp_rgb, 0, SEEK_SET);
fwrite(pRGBBuff, 1, imageW * imageH * 3, fp_rgb);
//---5、再次读文件,验证数据
/*
memset(pYUVBuff, 0, imageW * imageH * 3 / 2);
fseek(fp_yuv, 0, SEEK_SET);
fread(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
for(i = 0; i < imageW * imageH * 3 / 2 ;i++)
{
if (i % imageW == 0)
printf("\n");
printf("%3d ", pYUVBuff[i]);
}printf("\n");
*/
free(pRGBBuff);
return OK;
}
/**
* @brief yuv422p 转换为 rgb888 (rgb24)
* @param [in] fp_yuv RGB图像文件句柄
* @param [in] fp_rgb YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV422P_MODE_E 输入图片的YUV422p的格式类型
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_yuv422p_to_rgb888(FILE *fp_yuv, FILE *fp_rgb, int imageW, int imageH, YUV422P_MODE_E YUVmode)
{
unsigned char *pRGBBuff;
int iRet = -1;
unsigned int i = 0;
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
if (fp_rgb == NULL || fp_yuv == NULL)
{
IMAGE_ERROR("fp_rgb or fp_yuv open failed !!!!!!!");
return ERROR;
}
//---1、获取数据 (从开始位置读全部大小写入到转换函数 yuv420p_to_rgb888() 的输入数组中)
memset(s_uYUV, 0, sizeof(s_uYUV));
fseek(fp_yuv, 0, SEEK_SET);
iRet = fread(s_uYUV, 1, imageW * imageH * 2, fp_yuv); //--------------待优化!!!!!!!!!
//---2、动态申请存放RGB的BUFF
pRGBBuff = (unsigned char *)malloc(imageW * imageH * 3 + 1);
if (pRGBBuff == NULL)
{
IMAGE_ERROR("malloc pRGBBuff failed !!!!!!!!!");
return ERROR;
}
//---3、调用对应转换函数
iRet = yuv422p_to_rgb888(pRGBBuff, s_uYUV, sizeof(s_uYUV), imageW, imageH, YUVmode);
if (iRet == ERROR)
{
IMAGE_ERROR("yuv422p_to_rgb888 failed !!!!!!!!!");
free(pRGBBuff);
return ERROR;
}
//---4、将RGB数据写入文件
fseek(fp_rgb, 0, SEEK_SET);
fwrite(pRGBBuff, 1, imageW * imageH * 3, fp_rgb);
//---5、再次读文件,验证数据
/*
memset(pYUVBuff, 0, imageW * imageH * 3 / 2);
fseek(fp_yuv, 0, SEEK_SET);
fread(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
for(i = 0; i < imageW * imageH * 3 / 2 ;i++)
{
if (i % imageW == 0)
printf("\n");
printf("%3d ", pYUVBuff[i]);
}printf("\n");
*/
free(pRGBBuff);
return OK;
}
/**
* @brief yuv444p 转换为 rgb888 (rgb24)
* @param [in] fp_yuv RGB图像文件句柄
* @param [in] fp_rgb YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV444P_MODE_E 输入图片的YUV444p的格式类型
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_yuv444p_to_rgb888(FILE *fp_yuv, FILE *fp_rgb, int imageW, int imageH, YUV444P_MODE_E YUVmode)
{
unsigned char *pRGBBuff;
int iRet = -1;
unsigned int i = 0;
if (imageW == 0 || imageH == 0)
{
IMAGE_ERROR("imageW = 0 or imageH = 0");
return ERROR;
}
if (fp_rgb == NULL || fp_yuv == NULL)
{
IMAGE_ERROR("fp_rgb or fp_yuv open failed !!!!!!!");
return ERROR;
}
//---1、获取数据 (从开始位置读全部大小写入到转换函数 yuv420p_to_rgb888() 的输入数组中)
memset(s_uYUV, 0, sizeof(s_uYUV));
fseek(fp_yuv, 0, SEEK_SET);
iRet = fread(s_uYUV, 1, imageW * imageH * 3, fp_yuv); //--------------待优化!!!!!!!!!
//---2、动态申请存放RGB的BUFF
pRGBBuff = (unsigned char *)malloc(imageW * imageH * 3 + 1);
if (pRGBBuff == NULL)
{
IMAGE_ERROR("malloc pRGBBuff failed !!!!!!!!!");
return ERROR;
}
//---3、调用对应转换函数
iRet = yuv444p_to_rgb888(pRGBBuff, s_uYUV, sizeof(s_uYUV), imageW, imageH, YUVmode);
if (iRet == ERROR)
{
IMAGE_ERROR("yuv444p_to_rgb888 failed !!!!!!!!!");
free(pRGBBuff);
return ERROR;
}
//---4、将RGB数据写入文件
fseek(fp_rgb, 0, SEEK_SET);
fwrite(pRGBBuff, 1, imageW * imageH * 3, fp_rgb);
//---5、再次读文件,验证数据
/*
memset(pYUVBuff, 0, imageW * imageH * 3 / 2);
fseek(fp_yuv, 0, SEEK_SET);
fread(pYUVBuff, 1, imageW * imageH * 3 / 2, fp_yuv);
for(i = 0; i < imageW * imageH * 3 / 2 ;i++)
{
if (i % imageW == 0)
printf("\n");
printf("%3d ", pYUVBuff[i]);
}printf("\n");
*/
free(pRGBBuff);
return OK;
}
3、处理函数头文件rgbtoyuv.h
#ifndef _RGB_TO_YUV_H
#define _RGB_TO_YUV_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IMAGE_W 352 //---图像宽度
#define IMAGE_H 288 //---图像高度
#define IMAGE_CHAL 3 //---通道
#define ERROR -1
#define OK 0
typedef unsigned char uint8_t;
typedef unsigned int uint32;
static unsigned char s_rgb[IMAGE_W][IMAGE_H][IMAGE_CHAL] = { 0 };
static unsigned char s_uRGB[IMAGE_W * IMAGE_H * IMAGE_CHAL] = { 0 }; /** <存放RGB图像数据的数组,用于RGB to YUV */
static unsigned char s_uYUV[IMAGE_W * IMAGE_H * IMAGE_CHAL] = { 0 }; /** <存放YUV图像数据的数组, 用于YUV to RGB */
typedef enum
{
YUV420P_I420 = 0, //I420 数据格式——YYYY U V
YUV420P_YV12 = 1, //YV12 数据格式——YYYY V U
}YUV420P_MODE_E;
typedef enum
{
YUV422P_YU16 = 0, //YU16 数据格式——YY U V
YUV422P_YV16 = 1, //YV16 数据格式——YY V U
}YUV422P_MODE_E;
typedef enum
{
YUV444P_I444 = 0, //I444 数据格式——YY UU VV
YUV444P_YV24 = 1, //YV24 数据格式——YY VV UU
}YUV444P_MODE_E;
/**
* @brief 生成RGB24的图像
* @param [in] fp_rgb 图像文件名句柄
* @param [in] imageW 生成图像的宽度
* @param [in] imageH 生成图像的高度
* @return 成功返回图像的大小
*/
int iamge_creat_rgb24(FILE *fp_rgb, int imageW, int imageH);
/**
* @brief 将RGB24 图像转换 YUV420p YUV数据(内部函数)
* @param [in] fp_rgb RGB图像文件句柄
* @param [in] fp_yuv YUV图像文件句柄s
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] mode 参考YUV420P_MODE_E 枚举变量
* @return OK / ERROR 成功/失败
*/
int image_rgb888_to_yuv420p(FILE *fp_rgb, FILE *fp_yuv, int imageW, int imageH, YUV420P_MODE_E YUVmode);
/**
* @brief rgb888 (rgb24) 转换为yuv422p
* @param [in] fp_rgb RGB图像文件句柄
* @param [in] fp_yuv YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度s
* @param [in] YUV422P_MODE_E YUV422p的格式
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_rgb888_to_yuv422p(FILE *fp_rgb, FILE *fp_yuv, int imageW, int imageH, YUV422P_MODE_E YUVmode);
/**
* @brief rgb888 (rgb24) 转换为yuv444p
* @param [in] fp_rgb RGB图像文件句柄
* @param [in] fp_yuv YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV444P_MODE_E YUV444p的格式
* @return 返回转换结果 OK/ERROR 成功/失败
*/
int image_rgb888_to_yuv444p(FILE *fp_rgb, FILE *fp_yuv, int imageW, int imageH, YUV444P_MODE_E YUVmode);
/**
* @brief rgb888 (rgb24) 转换为yuv420p
* @param [in] fp_yuv RGB图像文件句柄
* @param [in] fp_rgb YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV420P_MODE_E 输入图片的YUV420p的格式类型
* @return [return]OK or ERROR 返回转换结果成功 or 失败
*/
int image_yuv420p_to_rgb888(FILE *fp_yuv, FILE *fp_rgb, int imageW, int imageH, YUV420P_MODE_E YUVmode);
/**
* @brief rgb888 (rgb24) 转换为yuv422p
* @param [in] fp_yuv RGB图像文件句柄
* @param [in] fp_rgb YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV422P_MODE_E 输入图片的YUV422p的格式类型
* @return [return]OK or ERROR 返回转换结果成功 or 失败
*/
int image_yuv422p_to_rgb888(FILE *fp_yuv, FILE *fp_rgb, int imageW, int imageH, YUV422P_MODE_E YUVmode);
/**
* @brief rgb888 (rgb24) 转换为yuv444p
* @param [in] fp_yuv RGB图像文件句柄
* @param [in] fp_rgb YUV图像文件句柄
* @param [in] w 输入图像的宽度
* @param [in] h 输入图像的高度
* @param [in] YUV444P_MODE_E 输入图片的YUV444p的格式类型
* @return [return]OK or ERROR 返回转换结果成功 or 失败
*/
int image_yuv444p_to_rgb888(FILE *fp_yuv, FILE *fp_rgb, int imageW, int imageH, YUV444P_MODE_E YUVmode);
#endif
4、Makefile 编译规则
app_main:rgbtoyuv.o app_main.o
gcc -o app_main rgbtoyuv.o app_main.o
app_main.o:app_main.c rgbtoyuv.h
gcc -c app_main.c
rgbtoyuv.o:rgbtoyuv.c
gcc -c rgbtoyuv.c
clean:
rm *.yuv *.rgb app_main
执行方式
四文件在同级目录下,执行Makefile生成执行程序app_main :
make clean
make && ./app_main