概念解析
YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大。
RGB是一种颜色编码方法
RGB 三个字母分别代表了 红、绿、蓝,这三种颜色作为三个基底颜色,将它们以不同的比例相加,可以产生多种多样的颜色。RGB 图像中,每个像素点都有红、绿、蓝三个基底颜色,其中每种原色都占用 8 bit,也就是一个字节(0-255),那么一个像素点也就占用 24 bit,也就是3个字节。
在图像显示中,一张 1280 * 720 大小的图片,就代表着它有 1280 * 720 个像素点。也就是一个矩阵,其中每一个像素点的颜色显示都采用 RGB 编码方法,将 RGB 分别取不同的值,就会展示不同的颜色, 就占用 1280 * 720 * 3(Byte) / 1024 / 1024 = 2.63 MB 存储空间。
对于图像显示器来说,它是通过 RGB 模型来显示图像的,也就是某个图片,我们可以查看他的属性,很多都是RGB模式显示的。而在传输图像数据时又是使用 YUV 模型,这是因为 YUV 模型可以节省带宽。 因此就需要采集图像时将 RGB 模型转换到 YUV 模型,显示时再将 YUV 模型转换为 RGB 模型。
转换
RGB 到 YUV 的转换,就是将图像所有像素点的 R、G、B 分量转换到 Y、U、V 分量。 每个像素点有三个分量。也就是三个变量的值。 下面是互转公式
C++代码
#include <iostream>
#include <fstream>
using namespace std;
#define IN_IMG_FILE_NAME "3.yuv"
#define OUT_IMG_FILE_NAME "test.bmp"
#define IMAGE_SIZE_WIDTH 1920
#define IMAGE_SIZE_HEIGHT 1080
#define IMAGE_SIZE_COEFF 3
typedef unsigned char U8;
typedef struct
{
unsigned int bfsize;
unsigned short reserved1;
unsigned short reserved2;
unsigned int bfoffBits;
} Bitmapfileheader;
typedef struct
{
unsigned int bisize;
int biwidth;
int biheight;
unsigned short biplanes;
unsigned short bibitcount;
unsigned int bicompression;
unsigned int bisizeimage;
int bixpels;
int biypels;
unsigned int biclrused;
unsigned int biclrim;
} Bitmapinfoheader;
int readImgFile(const char *filename, unsigned char *buff, ssize_t size)
{
int err = 0;
ifstream in_img(filename, ios::in);
do
{
if (!in_img.is_open())
{
cout << "open img file" << filename << "error" << endl;
err = 1;
break;
}
in_img.read(static_cast<char*>(static_cast<void*>(buff)), size);
in_img.close();
} while (0);
return err;
}
bool Yuv420ToRgb(U8* pYUV, U8* pRGB, int width, int height)
{
U8* pY = pYUV;
U8* pU = pYUV + height*width;
U8* pV = pU + (height*width / 4);
U8* pBGR = NULL;
U8 R = 0;
U8 G = 0;
U8 B = 0;
U8 Y = 0;
U8 U = 0;
U8 V = 0;
double temp = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
pBGR = pRGB + i*width * 3 + j * 3;
Y = *(pY + i*width + j);
U = *pU;
V = *pV;
temp = Y + ((1.773) * (U - 128));
B = temp < 0 ? 0 : (temp>255 ? 255 : (U8)temp);
temp = (Y - (0.344) * (U - 128) - (0.714) * (V - 128));
G = temp < 0 ? 0 : (temp>255 ? 255 : (U8)temp);
temp = (Y + (1.403)*(V - 128));
R = temp < 0 ? 0 : (temp>255 ? 255 : (U8)temp);
*pBGR = B;
*(pBGR + 1) = G;
*(pBGR + 2) = R;
if (j % 2 != 0)
{
*pU++;
*pV++;
}
}
if (i % 2 == 0)
{
pU = pU - width / 2;
pV = pV - width / 2;
}
}
return true;
}
void saveBmpFile(const char *filename, unsigned char *buff, const ssize_t size)
{
Bitmapfileheader file_header = { 0 };
Bitmapinfoheader info_header = { 0 };
unsigned short file_type = 0X4d42;
file_header.reserved1 = 0;
file_header.reserved2 = 0;
file_header.bfsize = 2 + sizeof(short) + sizeof(Bitmapinfoheader) + sizeof(Bitmapfileheader) + size*3;
file_header.bfoffBits = 0X36;
info_header.bisize = sizeof(Bitmapinfoheader);
info_header.biwidth = IMAGE_SIZE_WIDTH;
info_header.biheight = -IMAGE_SIZE_HEIGHT;
info_header.biplanes = 1;
info_header.bibitcount = 24;
info_header.bicompression = 0;
info_header.bisizeimage = 0;
info_header.bixpels = 5000;
info_header.biypels = 5000;
info_header.biclrused = 0;
info_header.biclrim = 0;
ofstream img(filename, ios::out | ios::trunc);
if (!img.is_open())
{
cout << "open bmp file error" <<endl;
exit(0);
}
img.write(static_cast<const char*>(static_cast<void*>(&file_type)), sizeof(file_type));
img.write(static_cast<const char*>(static_cast<void*>(&file_header)), sizeof(file_header));
img.write(static_cast<const char*>(static_cast<void*>(&info_header)), sizeof(info_header));
img.write(static_cast<char*>(static_cast<void*>(buff)), size);
img.close();
}
int main()
{
int err = 0;
ssize_t size = 0;
unsigned char *img_yuv = NULL;
unsigned char *img_rgb = NULL;
size = IMAGE_SIZE_WIDTH *IMAGE_SIZE_WIDTH * 2;
cout << "file size is : IMAGE_SIZE_WIDTH *IMAGE_SIZE_WIDTH * 2 = "<< size <<endl;
img_yuv = (unsigned char*)malloc(size);
img_rgb = (unsigned char*)malloc(size);
err = readImgFile(IN_IMG_FILE_NAME, img_yuv, size);
if (0 != err)
{
cout << "read img file error" <<endl;
exit(0);
}
Yuv420ToRgb(img_yuv, img_rgb, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT);
saveBmpFile(OUT_IMG_FILE_NAME, img_rgb, size);
return 0;
}
参考链接
https://blog.csdn.net/qq_41554005/article/details/100147657
|