本篇文章采用的bmp图片为为24位色深。----24位深没有带调色板,同时每个像素是有代表R,G,B的三个字节组成。
YUV422的存储方式采用的是YUYV。----(YUV422格式按照U、V的排列可以有YUYV,YVYU,UYVY,VYUY四种)。
有关YUV422格式请参考:YUV422格式信号格式 入门视频采集与处理(学会分析YUV数据)
有关BMP图片格式请参考:BMP文件结构
这里需要注意:
(1) 在bmp数据开始部分开始的前三个字节是代表图片左下角的第一个像素的,并且RGB排列方式为(B,G,R)。
(2) YUYV的存储分布为:Y0U0Y1V0,这是一个宏像素,四个字节,对应两个像素,公用U0,V0,;U0,V0采用隔像素采
样的方式。
(3)这里使用的RGB->YUV公式为:
y = 0.257*red + 0.504*green + 0.098*blue + 16;
u = -0.148*red - 0.291*green + 0.439*blue + 128;
v = 0.439*red - 0.368*green - 0.071*blue + 128;
代码:
/*
*以24位深bmp图像为例。即不带调色板,一个像素又三个字节构成,图片分辨率800*600
*[0,1]bmp标示
*[5:2]文件大小
*[6:9]保留值=0
*[12:10]bmp数据起始地址:左下角第一个像素(B,G,R),左下角第二个像素
* */
#include
#include
#include
#include
#include
#define BMP_PATH "/Mywork/123.bmp" #define YUV_PATH "/Mywork/123.bin" int main(int argc,char **argv) { int fd; int length = 0; int i,n; char buf[1440000]; //有这么多个像素 600*800*3 char yuv_buf[960000]; //yuyv图像占的像素数 600*800*2 char begin_buf[] = {0x41,0x49,0x4d,0x47,0x10,0xa6,0x0e,0x00,0x20,0x03,0x58,0x02,0x01,0x01,0x00,0x00}; //自己添加的起始信息 fd = open(BMP_PATH,O_RDWR); if(fd < 0){ perror("open error"); } read(fd,buf,16);//先读取16字节数据 第10 11 12位描述的图像数据的起始地址 //如36 00 00 表示数据起始地址是00 00 36即0x36开始。 /*for(i = 0;i < 16;i++){ printf("%x |",(uint8_t)buf[i]); } */ //确定bmp图像数据地址 i = buf[10] + (buf[11]<<8) + (buf[12]<<16); lseek(fd,i,SEEK_SET); printf("begin :%x \n",i); for(i = 599;i >= 0;i--){ length += read(fd,buf + i*800*3,800*3); printf("length:%d\n",length); //Y0U0Y1V0 Y2U1Y3V1 每次处理两个像素 for(i = 0,n =0;i < length;i+=6,n+=4){ yuv_buf[n] = RGB_Convert_Y(buf[i+2],buf[i+1],buf[i]); yuv_buf[n+1] = RGB_Convert_U(buf[i+2],buf[i+1],buf[i]); yuv_buf[n+2] = RGB_Convert_Y(buf[i+5],buf[i+4],buf[i+3]); yuv_buf[n+3] = RGB_Convert_V(buf[i+2],buf[i+1],buf[i]); } close(fd); fd = open(YUV_PATH,O_RDWR|O_CREAT|O_TRUNC); if(fd < 0){ perror("error"); } write(fd,begin_buf,16); write(fd,yuv_buf,800*600*2); close(fd); }