最近做了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);
}