数据压缩——rgb转yuv

RGB和YUV

  • RGB 分别表示红(R)、绿(G)、蓝(B),也就是三原色,将它们以不同的比例叠加,可以产生不同的颜色。
    一张 1920 * 1280 的图片,有 1920 * 1280 个像素点。采用 RGB 编码方式,每个像素点都有红、绿、蓝三个原色,每个原色占用 8 个字节,每个像素占用 24 个字节。
  • YUV 编码采用了明亮度和色度表示每个像素的颜色。其中 Y 表示明亮度,也就是灰阶值。U、V 表示色度,描述的是色调和饱和度。
  • YUV根据不同的采样格式,可以每个 Y 分量都对应自己的 UV 分量,也可以几个 Y 分量共用 UV 分量。相比 RGB,能够节约存储空间。

文章目录

  • RGB和YUV
  • RGB转YUV420思路
  • 一、转换公式
  • 二、代码
    • 1.rgb转换为yuv的处理
    • 2.截断处理部分
    • 3. 调用函数rgb24_yuv420
  • 结果
  • 参考


RGB转YUV420思路

  • 将rgb文件中的r,g,b像素读取
  • 读取一组根据转换公式转换一组
  • 判断y,u,v是否有溢出,若溢出则截断处理

一、转换公式

Y=0.299R+0.587G+0.114B+16 Cr=V=0.500R−0.419G−0.081B+128 Cb=U=−0.169R−0.331G+0.500B+128

二、代码

1.rgb转换为yuv的处理

代码如下:

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); //将yuvBuf初始化为0
	ptrY = yuvBuf; //420是planar format的储存格式先存放y,再u,再v
	ptrU = yuvBuf + w * h;
	ptrV = ptrU + (w * h * 1 / 4);
	//RGB24是packed,RGB打包成一个像素。YUV420P是planar,先将整张图像的Y存完才开始存U,最后V
	unsigned char y, u, v, r, g, b;
	for (int j = 0; j < h; j++) {
		ptrRGB = RgbBuf + w * j * 3; //rgb存储方式是packed打包存放,每包3个
		for (int i = 0; i < w; i++) {

			r = *(ptrRGB++);
			g = *(ptrRGB++);
			b = *(ptrRGB++);
			//rgb转yuv的公式
			y = 0.299 * r + 0.587 * g + 0.114 * b + 16;
			u = -0.1684 * r - 0.3316 * g + 0.5 * b + 128;
			v = 0.5 * r - 0.4187 * g - 0.0813 * b + 128;
			*(ptrY++) = clip_value(y, 0, 255); //判断y是否超出范围
			if (j % 2 == 0 && i % 2 == 0) {
				*(ptrU++) = clip_value(u, 0, 255);
				*(ptrV++) = clip_value(v, 0, 255);
			}//按照yuv420p的定义,一个2 * 2的矩形y对应一个u和v。即2 * 2的矩形计算出的u和v的值是一样的,都取第一个进行计算即可。这样改比较好理解。
		}
	}
	return true;
}

2.截断处理部分

代码如下:

//因YUV的范围是0~255因此在其范围外的数值都做截断处理
unsigned char clip_value(unsigned char x, unsigned char min_val, unsigned char  max_val) {
	if (x > max_val) {
		return max_val; //大于max_val的值记作max_val
	}
	else if (x < min_val) {
		return min_val;  //小于min_val的值记作min_val
	}
	else {
		return x; //在指定范围内,就保持不变
	}
}

3. 调用函数rgb24_yuv420

int rgb24_yuv420(const char* url_in, int w, int h, int num, const char* url_out) {
	FILE* fp = fopen(url_in, "rb+");
	FILE* fp1 = fopen(url_out, "wb+");
	//url_in是输入rgb的文件;
	//w为图像宽,h为图像高,num为图片数目
	//url_out为转换后的yuv文件

	unsigned char* pic_rgb24 = (unsigned char*)malloc(w * h * 3);
	unsigned char* pic_yuv420 = (unsigned char*)malloc(w * h * 3 / 2);

	for (int i = 0; i < num; i++) {
		fread(pic_rgb24, 1, w * h * 3, fp); //读rgb文件
		RGB24_TO_YUV420(pic_rgb24, w, h, pic_yuv420); //rgb到yuv文件转换
		fwrite(pic_yuv420, 1, w * h * 3 / 2, fp1); //转换后写入文件fp1
	}

	free(pic_rgb24);
	free(pic_yuv420);
	fclose(fp);
	fclose(fp1);

	return 0;
}
int main()
{
	rgb24_yuv420("F:\\大三下资料\\数据压缩\\shiyan3\\RGB_YUV\\test.rgb", 256, 256, 1, "F:\\大三下资料\\数据压缩\\shiyan3\\RGB_YUV\\output_test.yuv");
}

结果

数据压缩——rgb转yuv_第1张图片缺点:该方法耗时较长
改进:可将浮点运算改为整数移位运算;或者添加查找表,以空间换取时间。

参考

  1. https://blog.csdn.net/leixiaohua1020/article/details/50534150
  2. https://blog.csdn.net/fanyun_01/article/details/100068351
  3. https://blog.csdn.net/liyuanbhu/article/details/68951683

你可能感兴趣的:(数据压缩2022,c++)