前言
将BMP文件转换成YUV文件
一、RGB到YUV格式的转换
RGB文件的格式为,每个像素占三个字节,依次为B G R三个分量。根据亮度方程,即可计算出每个像素对应的Y U V.
YUV图片的采样格式为4:2:0 如下表
⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ |
---|---|---|---|---|---|---|---|---|---|---|---|
✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ |
⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ | ⊗ | ✕ |
✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ |
所以UV所占的大小都为Y的四分之一。
yBufferOut = (unsigned char*)malloc(height * width);
uBufferOut = (unsigned char*)malloc(height * width /4);
vBufferOut = (unsigned char*)malloc(height * width /4);
按亮度方程计算三个分量,并写入新文件。
for (int i = 0; i < height * width; i++)
{
*(yBufferOut + i) = (int)(0.299 * ( * (rBufferIn + i)) + 0.587 *( * (gBufferIn + i) )+ 0.114 *( * (bBufferIn + i)));
}
for (int i = 0,j=0; i < height * width;j++)
{
*(uBufferOut + j) = ((-0.1684) * (*(rBufferIn + i)) + (-0.3316) * (*(gBufferIn + i)) + 0.5 * (*(bBufferIn + i)) + 128);
if (i % width == width - 2)
{
i = i + width + 2;
}
else
{
i = i + 2;
}
}
for (int i =0,j=0; i < height * width;j++ )
{
*(vBufferOut +j) = ((0.5) * *(rBufferIn + i + 256) + (-0.4187) * *(gBufferIn + i + 256) + (-0.0813) * *(bBufferIn + i + 256) + 128);
if (i % width == width - 2)
{
i = i + width + 2;
}
else
{
i = i + 2;
}
}
效果
二、BMP到YUV格式的转换
1.BMP文件的格式
典型的BMP图像文件由四部分组成:
(1)位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;
(2)位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;
(3)调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
(4)位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。
typedef struct tagBITMAPFILEHEADER
{
unsigned short int bfType; //位图文件的类型,必须为BM
unsigned long bfSize; //文件大小,以字节为单位
unsigned short int bfReserverd1; //位图文件保留字,必须为0
unsigned short int bfReserverd2; //位图文件保留字,必须为0
unsigned long bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER; //定义位图信息头块
typedef struct tagBITMAPINFOHEADER
{
long biSize; //该结构大小,字节为单位
long biWidth; //图形宽度以象素为单位
long biHeight; //图形高度以象素为单位
short int biPlanes; //目标设备的级别,必须为1
short int biBitcount; //颜色深度,每个象素所需要的位数
short int biCompression; //位图的压缩类型
long biSizeImage; //位图的大小,以字节为单位
long biXPelsPermeter; //位图水平分辨率,每米像素数
long biYPelsPermeter; //位图垂直分辨率,每米像素数
long biClrUsed; //位图实际使用的颜色表中的颜色数
long biClrImportant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER; //定义位图信息头块
typedef struct tagRGBQUAD
{
unsigned char rgbBlue; //指定蓝色分量
unsigned char rgbGreen; //指定绿色分量
unsigned char rgbRed; //指定红色分量
unsigned char rgbReserved; //保留, 指定为 0
} RGBQUAD;
typedef struct bmp
{
BITMAPFILEHEADER file; //文件信息区
BITMAPINFOHEADER info; //图象信息区
}bmp;
2.BMP中RGB数据的提取
首先我们要判断是几位的图片。如果是24位图,直接提取RGB数据即可。如果不是,则需要按照调色板来获取。
判断是否需要调色板
int JudgeQuad(BITMAPFILEHEADER FileHeader, BITMAPINFOHEADER InfoHeader, FILE* BmpFile, RGBQUAD* RGBQuadOut)
{
if ((FileHeader.bfbfOffBits-sizeof(BITMAPFILEHEADER)-InfoHeader.biSize)==sizeof(RGBQUAD)*pow(2,InfoHeader.biBitcount))
{
fseek(BmpFile, sizeof(BITMAPFILEHEADER) + InfoHeader.biSize, 0);
fread(RGBQuadOut, sizeof(RGBQUAD),(unsigned int)pow(2,(float)InfoHeader.biBitcount), BmpFile);
return 1;
}
else
{
return 0;
}
}
之后我们提取文件中的RGB数据,注意字节序,BMP的数据放到RGB中要反序
for (int k = 0; k < Height; k++)
{
for (int p = 0; p < Width; p++)
{
*(RGBBufferOut + k * Width + p) = *(BmpDataBuffer + (Height - 1 - k) * Width + p);
}
}
free(BmpDataBuffer);
得到RGB数据之后,我们再执行RGB到YUV 的转化就可以了。
下面是猫猫头效果图
文章来源:https://www.toymoban.com/news/detail-409501.html
主函数调用:文章来源地址https://www.toymoban.com/news/detail-409501.html
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
#include <malloc.h>
#include <stdlib.h>
#include"bmp.h"
bmp ReadBmpFile(char* file);
int bmp2rgb(BITMAPFILEHEADER FileHeader, BITMAPINFOHEADER InfoHeader, FILE* BmpFile, unsigned char* RGBBuffer);
int rgb2yuv(BITMAPINFOHEADER InfoHeader, unsigned char* RGBBufferIn, unsigned char* yBufferOut, unsigned char* uBufferOut, unsigned char* vBufferOut);
int main(int argc, char* argv[])
/*
1 out.yuv
2 frame
-----以下是文件------
3 bixin.bmp
4 gucci.bmp
5 daoren.bmp
6 zhenshi.bmp
7 zaoan.bmp
*/
{
FILE* fout = fopen(argv[1], "wb");
for (int i = 3; i < argc; i++)
{
FILE* fp;
bmp temp = ReadBmpFile(argv[i]);
fp = fopen(argv[i], "rb");
unsigned long Width, Height; //图像的宽(像素数)与高(像素数)
Height = temp.info.biHeight;
Width = temp.info.biWidth;
printf("%d\n", Height);
unsigned char* RGBBuffer;
RGBBuffer = (unsigned char*)malloc(3 * Width * Height);
bmp2rgb(temp.file, temp.info, fp, RGBBuffer);
printf("已转化成rgb");
unsigned char* yBufferOut;
unsigned char* uBufferOut;
unsigned char* vBufferOut;
yBufferOut = (unsigned char*)malloc(Width * Height);
uBufferOut = (unsigned char*)malloc(Width * Height / 4);
vBufferOut = (unsigned char*)malloc(Width * Height / 4);
rgb2yuv(temp.info, RGBBuffer, yBufferOut, uBufferOut, vBufferOut);
for (int j = 0; j < atoi(argv[2]); j++)
{
fwrite(yBufferOut, sizeof(unsigned char), Width * Height, fout);
fwrite(uBufferOut, sizeof(unsigned char), Width * Height / 4, fout);
fwrite(vBufferOut, sizeof(unsigned char), Width * Height / 4, fout);
}
free(yBufferOut);
free(uBufferOut);
free(vBufferOut);
fclose(fp);
}
return 0;
}
到了这里,关于BMP到YUV的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!