最近做了yuv的图像处理,在这里来备个份
好的资料:
http://www.vckbase.com/document/viewdoc/?id=1780
http://blog.chinaunix.net/u2/87176/showart_2044517.html
里面基本有所有的概念,但我还是自我概括几点:
1.我的rgb图像是24位的,意味着一个像素点24位,也就是3个字节,这三个字节是R,G,B,注意了,这三个字节在内存中的排列式是: BGRBGRBGR......,而且bmp的前面54个字节是bmp信息头,别忘了略过
2.还有在linux中yuv的格式,y是16*16宏块的,uv的是8*16的组成小宏块,8个u,8个v,自己得到yuv之后再按linux的宏块格式排列
图貌似不大好上,挂在附件中
3.图的大小是720*576的,y宏块转换公式如下:
第一大行[0,45*256)的元素
0----(0/16)*256 + 0%16
1----(1/16)*256 + 1%16
......
16----(16/16)*256 + 16%16
17----(17/16)*256 + 17%16
......
x----(x/16)*256 + x%16
算上其他的大行:
x----( ( x%(45*16) )/16)*256 + ( x%(45*16) )%16+ ( x/(45*16) )*16
uv的计算方法可见程序
4.malloc函数如果报警 #include
memset函数如果报警 #include
5.不知道windows读bmp到底是从左上角开始读,还是怎么读,总觉得好像不确定似的,以后确定了,再来这里纠正
6.改的格式这里是4:2:2,也就说,每个像素点都有y值,每两个像素点一个u,一个v,那么在rgb转为yuv时,如何转换呢?其实基本是这样做的,隔一个像素点取个uv值,比如说,取了这个像素点的uv值,则下个像素点就不取了,下下个像素点再取
7.另有一个问题,yuv的存储格式各有不同,可是那些yuvviewer怎么看呢,比如4:2:2可以是uyvy,也可以是yuyv,我怀疑这个情况对于yuvviewer来说也比较恼火,估计这种作者是随便选了一种也就做了,至于大众情况下,选哪种,我在附件中介绍的yuvviewer显示的是哪种,我都不知道
郁闷,发现网速太卡,上传不了,暂且存在自己QQ上的网络硬盘上,取名为rgb_yuv,源码上下吧,免得不见了
//这个函数主要实现bmp转为我在linux特殊的能用的yuv格式
//由于我从网上下的转的uv能正确获取,但是y获取不全
//而我本人写的直接从bmp读uv又碰到读取秩序的问题
//所以自己写得到y,所以需要720*576深度为24的1.bmp图
//需要由附件中的bmpyuv转换后得到的1.yuv图4:2:2
//得到可以在linux上显示的2.yuv 4:2:2
#include
#include
#include
#include < string.h>
int main()
{
FILE *file_yuv1;
FILE *file_yuv2;
FILE *file_bmp;
char *file1_buffer;
char *file2_buffer;
char *bmp_buffer;
char *y_buffer;
char *u_buffer;
char *v_buffer;
char *uv_buffer;
int read_num;
int write_num;
int big_row_count;
int row_base_count;
int row_total_count;
int i,j,k,h;
//malloc函数要加stdlib.h, memset函数要加 string.h, 否则会报警
file1_buffer=malloc(720*576*2);
memset(file1_buffer,0x0,720*576*2);
bmp_buffer=malloc(720*576*3+54);
memset(bmp_buffer,0x0,720*576*3+54);
file2_buffer=malloc(720*576);
memset(file2_buffer,0x0,720*576);
y_buffer=malloc(720*576);
memset(y_buffer,0x0,720*576);
u_buffer=malloc(720*576/2);
memset(u_buffer,0x0,720*576/2);
v_buffer=malloc(720*576/2);
memset(v_buffer,0x0,720*576/2);
uv_buffer=malloc(720*576);
memset(uv_buffer,0x0,720*576);
//1.yuv是利用网上rgb转yuv的程序转图像1.bmp得来的,目的是用其uv
file_yuv1=fopen( "1.yuv", "rb");
//网上的uv并不好用,故自己从这个1.bmp中读取y
file_bmp=fopen( "1.bmp", "rb");
//输出的yuv
file_yuv2=fopen( "2.yuv", "wb");
read_num=fread(file1_buffer,1,720*576*2,file_yuv1);
printf( "read_num_yuv=%d\n",read_num);
read_num=fread(bmp_buffer,1,720*576*3+54,file_bmp);
printf( "read_num_bmp=%d\n",read_num);
int xx=0;
int uv=0;
while(xx<720*576)
{
y_buffer[720*576-1-xx]=0.299*bmp_buffer[54+xx*3+2]+0.587*bmp_buffer[54+xx*3+1]+0.114*bmp_buffer[54+xx*3];
/*
//尝试自己写uv,因为存在诸如y值的读取顺序的问题,
//所以这个尝试暂且是不成功的
if((xx%2)==0)
{
u_buffer[720*576/2-1-uv] = -0.1687*bmp_buffer[54+xx*3+2]-0.3313*bmp_buffer[54+xx*3+1]+0.5*bmp_buffer[54+xx*3]+128;
v_buffer[720*576/2-1-uv] = 0.5*bmp_buffer[54+xx*3+2]-0.4187*bmp_buffer[54+xx*3+1]-0.0813*bmp_buffer[54+xx*3]+128;
uv++;
}
*/
xx++;
}
int t;
for(j=0;j<576;j++)
{
for(i=0;i<=(45*16)/2;i++)
{
t=y_buffer[j*45*16+45*16-1-i];
y_buffer[j*45*16+45*16-1-i] = y_buffer[j*45*16+i];
y_buffer[j*45*16+i]=t;
}
}
/*
//这些都是准备自己调整uv写的,发现并不像y好调
for(j=0;j<576;j++)
{
for(i=0;i<=(45*8)/2;i++)
{
t=u_buffer[j*45*8+45*8-1-i];
u_buffer[j*45*8+45*8-1-i] = u_buffer[j*45*8+i];
u_buffer[j*45*8+i]=t;
}
}
for(j=0;j<576;j++)
{
for(i=0;i<=(45*8)/2;i++)
{
t=v_buffer[j*45*8+45*8-1-i];
v_buffer[j*45*8+45*8-1-i] = v_buffer[j*45*8+i];
v_buffer[j*45*8+i]=t;
}
}
*/
//把我用VC从bmp中读取的数据分为uv各自缓存
int temp;
int y_buffer_num=0;
int u_buffer_num=0;
int v_buffer_num=0;
for(temp=0;temp<720*576/2;temp++)
{
u_buffer[u_buffer_num]=file1_buffer[4*temp];u_buffer_num++;
//y_buffer[y_buffer_num]=file1_buffer[4*temp+1];y_buffer_num++;
v_buffer[v_buffer_num]=file1_buffer[4*temp+2];v_buffer_num++;
//y_buffer[y_buffer_num]=file1_buffer[4*temp+3];y_buffer_num++;
}
//实现U8V8的组合
int temp_uv=0,temp_u=0,temp_v=0;
while(temp_uv<720*576)
{
for(j=0;j<8;j++)
{
uv_buffer[temp_uv]=u_buffer[temp_u];temp_uv++;temp_u++;
}
for(j=0;j<8;j++)
{
uv_buffer[temp_uv]=v_buffer[temp_v];temp_uv++;temp_v++;
}
}
//把y转为16*16宏块,并且存完Y
for(i=0;i<36;i++)
{
row_base_count=i*45*256;
for(j=0;j<45*256;j++)//做好第一大行
{
h=(j/(45*16))*16\
+((j%(45*16))/16)*256\
+(j%(45*16))%16;
file2_buffer[row_base_count+h]=y_buffer[row_base_count+j];
}
}
write_num=fwrite(file2_buffer,1,720*576,file_yuv2);
printf( "write_num=%d\n",write_num);
//把uv转为8*16的宏块,存完UV
for(i=0;i<72;i++)
{
row_base_count=i*45*128;
for(j=0;j<45*128;j++)//做好第一大行
{ //这是告诉这是哪一个宏块,每个宏块的行基数要加16
h=(j/(45*16))*16\
+((j%(45*16))/16)*128\
+(j%(45*16))%16;
file2_buffer[/*720*576-1-*/(row_base_count+h)]=uv_buffer[(row_base_count+(/*45*256-1-*/j))];
}
}
write_num=fwrite(file2_buffer,1,720*576,file_yuv2);
printf( "write_num=%d\n",write_num);
free(file1_buffer);
free(file2_buffer);
free(y_buffer);
free(u_buffer);
free(v_buffer);
free(bmp_buffer);
fclose(file_yuv1);
fclose(file_yuv2);
}
//由于我从网上下的转的uv能正确获取,但是y获取不全
//而我本人写的直接从bmp读uv又碰到读取秩序的问题
//所以自己写得到y,所以需要720*576深度为24的1.bmp图
//需要由附件中的bmpyuv转换后得到的1.yuv图4:2:2
//得到可以在linux上显示的2.yuv 4:2:2
#include
#include
#include
#include < string.h>
int main()
{
FILE *file_yuv1;
FILE *file_yuv2;
FILE *file_bmp;
char *file1_buffer;
char *file2_buffer;
char *bmp_buffer;
char *y_buffer;
char *u_buffer;
char *v_buffer;
char *uv_buffer;
int read_num;
int write_num;
int big_row_count;
int row_base_count;
int row_total_count;
int i,j,k,h;
//malloc函数要加stdlib.h, memset函数要加 string.h, 否则会报警
file1_buffer=malloc(720*576*2);
memset(file1_buffer,0x0,720*576*2);
bmp_buffer=malloc(720*576*3+54);
memset(bmp_buffer,0x0,720*576*3+54);
file2_buffer=malloc(720*576);
memset(file2_buffer,0x0,720*576);
y_buffer=malloc(720*576);
memset(y_buffer,0x0,720*576);
u_buffer=malloc(720*576/2);
memset(u_buffer,0x0,720*576/2);
v_buffer=malloc(720*576/2);
memset(v_buffer,0x0,720*576/2);
uv_buffer=malloc(720*576);
memset(uv_buffer,0x0,720*576);
//1.yuv是利用网上rgb转yuv的程序转图像1.bmp得来的,目的是用其uv
file_yuv1=fopen( "1.yuv", "rb");
//网上的uv并不好用,故自己从这个1.bmp中读取y
file_bmp=fopen( "1.bmp", "rb");
//输出的yuv
file_yuv2=fopen( "2.yuv", "wb");
read_num=fread(file1_buffer,1,720*576*2,file_yuv1);
printf( "read_num_yuv=%d\n",read_num);
read_num=fread(bmp_buffer,1,720*576*3+54,file_bmp);
printf( "read_num_bmp=%d\n",read_num);
int xx=0;
int uv=0;
while(xx<720*576)
{
y_buffer[720*576-1-xx]=0.299*bmp_buffer[54+xx*3+2]+0.587*bmp_buffer[54+xx*3+1]+0.114*bmp_buffer[54+xx*3];
/*
//尝试自己写uv,因为存在诸如y值的读取顺序的问题,
//所以这个尝试暂且是不成功的
if((xx%2)==0)
{
u_buffer[720*576/2-1-uv] = -0.1687*bmp_buffer[54+xx*3+2]-0.3313*bmp_buffer[54+xx*3+1]+0.5*bmp_buffer[54+xx*3]+128;
v_buffer[720*576/2-1-uv] = 0.5*bmp_buffer[54+xx*3+2]-0.4187*bmp_buffer[54+xx*3+1]-0.0813*bmp_buffer[54+xx*3]+128;
uv++;
}
*/
xx++;
}
int t;
for(j=0;j<576;j++)
{
for(i=0;i<=(45*16)/2;i++)
{
t=y_buffer[j*45*16+45*16-1-i];
y_buffer[j*45*16+45*16-1-i] = y_buffer[j*45*16+i];
y_buffer[j*45*16+i]=t;
}
}
/*
//这些都是准备自己调整uv写的,发现并不像y好调
for(j=0;j<576;j++)
{
for(i=0;i<=(45*8)/2;i++)
{
t=u_buffer[j*45*8+45*8-1-i];
u_buffer[j*45*8+45*8-1-i] = u_buffer[j*45*8+i];
u_buffer[j*45*8+i]=t;
}
}
for(j=0;j<576;j++)
{
for(i=0;i<=(45*8)/2;i++)
{
t=v_buffer[j*45*8+45*8-1-i];
v_buffer[j*45*8+45*8-1-i] = v_buffer[j*45*8+i];
v_buffer[j*45*8+i]=t;
}
}
*/
//把我用VC从bmp中读取的数据分为uv各自缓存
int temp;
int y_buffer_num=0;
int u_buffer_num=0;
int v_buffer_num=0;
for(temp=0;temp<720*576/2;temp++)
{
u_buffer[u_buffer_num]=file1_buffer[4*temp];u_buffer_num++;
//y_buffer[y_buffer_num]=file1_buffer[4*temp+1];y_buffer_num++;
v_buffer[v_buffer_num]=file1_buffer[4*temp+2];v_buffer_num++;
//y_buffer[y_buffer_num]=file1_buffer[4*temp+3];y_buffer_num++;
}
//实现U8V8的组合
int temp_uv=0,temp_u=0,temp_v=0;
while(temp_uv<720*576)
{
for(j=0;j<8;j++)
{
uv_buffer[temp_uv]=u_buffer[temp_u];temp_uv++;temp_u++;
}
for(j=0;j<8;j++)
{
uv_buffer[temp_uv]=v_buffer[temp_v];temp_uv++;temp_v++;
}
}
//把y转为16*16宏块,并且存完Y
for(i=0;i<36;i++)
{
row_base_count=i*45*256;
for(j=0;j<45*256;j++)//做好第一大行
{
h=(j/(45*16))*16\
+((j%(45*16))/16)*256\
+(j%(45*16))%16;
file2_buffer[row_base_count+h]=y_buffer[row_base_count+j];
}
}
write_num=fwrite(file2_buffer,1,720*576,file_yuv2);
printf( "write_num=%d\n",write_num);
//把uv转为8*16的宏块,存完UV
for(i=0;i<72;i++)
{
row_base_count=i*45*128;
for(j=0;j<45*128;j++)//做好第一大行
{ //这是告诉这是哪一个宏块,每个宏块的行基数要加16
h=(j/(45*16))*16\
+((j%(45*16))/16)*128\
+(j%(45*16))%16;
file2_buffer[/*720*576-1-*/(row_base_count+h)]=uv_buffer[(row_base_count+(/*45*256-1-*/j))];
}
}
write_num=fwrite(file2_buffer,1,720*576,file_yuv2);
printf( "write_num=%d\n",write_num);
free(file1_buffer);
free(file2_buffer);
free(y_buffer);
free(u_buffer);
free(v_buffer);
free(bmp_buffer);
fclose(file_yuv1);
fclose(file_yuv2);
}