2017-06-04 17:34:29 qq_29859497 阅读数 2194

对图像划分为8*8的像素块并进行DCT变换


经过上一篇博文(http://blog.csdn.net/qq_29859497/article/details/72860023)将一张图片进行转换颜色空间并将各个通道进行分离后,我们可以取得各个通道如亮度Y、饱和度Cb、色度Cr通道,对他们进行DCT变换处理。


DCT变换在当前的图像分析已经压缩领域有着极为广大的用途,我们常见的JPEG静态图像编码以及MJPEG、MPEG动态编码等标准中都使用了DCT变换。相应公式可自行百度~


DCT变换(JAVA):


public static double[][] DCTconvertion(double[][] f) {           
      int sizeX = f.length;
      int sizeY = f[0].length;
      double[][] F = new double[sizeX][sizeY];
      int u, v, x, y;
      for(int xx = 0; xx < sizeX; xx += 8){
          for(int yy = 0; yy < sizeY; yy += 8){                 
              for(int u1 = xx; u1 < xx + 8; u1++){
                  u = u1 - xx;
                  for(int v1 = yy; v1 < yy + 8; v1++){
                      v = v1 - yy;
                      double subSum = 0.0;
                      for(int x1 = xx; x1 < xx + 8; x1++){
                          x = x1 - xx;
                          for(int y1 = yy; y1 < yy + 8; y1++){
                              y = y1 - yy;
                              subSum += Math.cos(((2.0*x + 1.0)*u*Math.PI)/(16.0)) * Math.cos(((2.0*y + 1.0)*v*Math.PI)/(16.0)) * f[x1][y1];;
                          }
                       }
                  F[u1][v1] = Math.max(Math.min(((Cfunc(u) * Cfunc(v)) / 4.0) * subSum, 1024.0), -1024.0);
              }
          }   
        }
    }   
    return F;
}

可用一个二维数组保存DCT变换后的数据,当然可以在控制台将数据打印出来,打印二维数组printArray方法:


public static void printArray(int[][] F){
      int X = F.length;
      int Y = F[0].length;
      for(int y = 0; y < Y; y++){
          for(int x = 0; x < X; x++){
               System.out.print(F[x][y] + "  ");
               System.out.print("\t");
          }
          System.out.println("");
      }   
      System.out.println("");
 }

运行效果如下图:



这里写图片描述
这里写图片描述
这里写图片描述


这里写图片描述
这里写图片描述


(o゜▽゜)o☆[BINGO!]这里是小屋,欢迎戳(o゜▽゜)o☆[BINGO!]

2018-06-19 08:51:51 weixin_38730901 阅读数 184

网上大多数关于YUV420的资料都是关于YUV420P的,很少有YUV420SP的,因为YUV420SP的UV是交错存放的,处理起来相对麻烦点,但是YUV420SP也是一种常见格式,因此,在这里,我将关于YUV420SP格式数据的处理总结下,方便有需要的同志。


一、YUV420格式数据介绍

       YUV,分为三个分量,“Y”表示明亮度,也就是灰度值;“U"和”V"表示的则是色度,作用是描述影像色彩饱和度,用于指定像素的颜色。YUV主流的采样方式有三种:YUV4:4:4,YUV4:2:2,YUV4:2:0,这里主要介绍下YUV420。

        在YUV420中,一个像素点对应一个Y,一个2X2的小方块对应一个U和V。对于所有YUV420图像,它们的Y值排列是完全相同的,因为只有Y的图像就是灰度图像。YUV420又分为YUV420SP与YUV420P这两种,这两种格式的Y分布是相同的,区别在于UV:YUV420p它是先把U存放完后,再存放V,也就是说UV它们是连续的;而YUV420sp它是UV、UV这样交替存放的。(他们的内存分布图如下,左是YUV420sp,右是YUV420p)
               

二、从YUV内存中取数据组方法

       注意YUV是每四个Y对应一个UV,并且YUV420P和YUV420SP的UV的存放格式不同,取法也不同,总的来说,YUV420P的取法简单,YUV420SP的取法相对复杂点。

1、YUV420SP

  1. for(int j=0;j<DataHeight;j++)     
  2. {    
  3.     for(int i=0;i<DataWidth;i++)    
  4.     {    
  5.         y=ybase[i + j * DataWidth];// 每四个y对应一个uv    
  6.         u=ubase[j/2 * DataWidth+(i/2)*2];    
  7.         v=ubase[j/2 * DataWidth+(i/2)*2+1];  //一定要注意是u+1        
  8.     }    
  9. }   


2、YUV420P

  1. for(int j=0;j<DataHeight;j++)     
  2. {    
  3.     for(int i=0;i<DataWidth;i++)    
  4.     {    
  5.         //yyyyyy ... uuuu ...vvv  
  6.         y=ybase[i + j * DataWidth];  
  7.         u=ubase[j/2 * DataWidth/2+(i/2)];    
  8.         v=vbase[j/2 * DataWidth/2+(i/2)];    
  9.     }    
  10. }   

上面代码里,ybase就是YUV中Y的起始地址,ubase就是u的起始地址,vbase就是v的起始地址。而YUV420SP格式中,V就是U的地址加一;YUV420P中U和V都是连续的。按照上面方法,我们就可以得到每一组YUV数据,然后自己可以将每一组数据保存下来,再进行处理。


三、YUV420转换为RGB数据

1、转换公式

R=Y+1.4075*(V-128)
G=Y-0.3455*(U-128) – 0.7169*(V-128)
B=Y+1.779*(U-128)

2.转换方法

YUV420SP

  1. for(int j=0;j<DataHeight;j++)     
  2. {    
  3.     for(int i=0;i<DataWidth;i++)    
  4.     {    
  5.         unsigned char r,g,b;    
  6.         y=ybase[i + j * DataWidth];  
  7.         u=ubase[j/2 * DataWidth+(i/2)*2];    
  8.         v=ubase[j/2 * DataWidth+(i/2)*2+1];        
  9.   
  10.         b=(unsigned char)(y+1.779*(u- 128));    
  11.         g=(unsigned char)(y-0.7169*(v - 128)-0.3455*(u - 128));      
  12.         r=(unsigned char)(y+ 1.4075*(v - 128));*/    
  13.     }    
  14. }    

YUV420P

  1. for(int j=0;j<DataHeight;j++)     
  2. {    
  3.     for(int i=0;i<DataWidth;i++)    
  4.     {    
  5.         unsigned char r,g,b;    
  6.         
  7.         y=ybase[i + j * DataWidth];  
  8.         u=ubase[j/2 * DataWidth/2+(i/2)];    
  9.         v=vbase[j/2 * DataWidth/2+(i/2)];    
  10.   
  11.         b=(unsigned char)(y+1.779*(u- 128));    
  12.         g=(unsigned char)(y-0.7169*(v - 128)-0.3455*(u - 128));      
  13.         r=(unsigned char)(y+ 1.4075*(v - 128));*/    
  14.     }    
  15. }   


四、RGB数据存储为图片

注意rgb数据存储为bmp和jpg时的不同,将RBG数据存储为bmp时,数据是逆序存放,并且不是rgb,而是bgr;当将rgb数据存储为jpg时,则不用,不用逆序,数据也还是rgb。

1、存储为BMP图片

请看另一篇博客,RGB TO BMP

2、存储为JPG图片

存储为JPG图片要用到一个开运库,libjpeg,或者libjpeg-turbo,我用的是libjpeg,网上关于这两个开源库的资料很多,可以从这个下载编译好的包,LIBJPEG包

封装的存储方法如下:

  1. int rgb2jpeg(const char * filename, unsigned char* rgbData,int image_width,int image_height,int quality)    
  2. {    
  3.     struct jpeg_compress_struct jpeg;  //identify a compress object  
  4.     struct jpeg_error_mgr jerr;  //error information  
  5.   
  6.     jpeg.err = jpeg_std_error(&jerr);    
  7.     jpeg_create_compress(&jpeg);  //init compress object  
  8.   
  9.     FILE* pFile;  
  10.     fopen_s(&pFile,filename,"wb" );    
  11.     if( !pFile )  return 0;    
  12.     jpeg_stdio_dest(&jpeg, pFile);    
  13.   
  14.     //compress param set,i just did a simple param set  
  15.     jpeg.client_data=(void*)&pFile;  
  16.     jpeg.image_width = image_width;    
  17.     jpeg.image_height = image_height;    
  18.     jpeg.input_components  = 3;    
  19.     jpeg.in_color_space = JCS_RGB;     
  20.     jpeg_set_defaults(&jpeg);     
  21.     //// 指定亮度及色度质量    
  22.     jpeg.q_scale_factor[0] = jpeg_quality_scaling(100);    
  23.     jpeg.q_scale_factor[1] = jpeg_quality_scaling(100);    
  24.     //// 图像采样率,默认为2 * 2    
  25.     jpeg.comp_info[0].v_samp_factor = 2;    
  26.     jpeg.comp_info[0].h_samp_factor = 2;    
  27.     //// set jpeg compress quality    
  28.     jpeg_set_quality(&jpeg, quality, TRUE);  //100 is the highest  
  29.   
  30.     //start compress  
  31.     jpeg_start_compress(&jpeg, TRUE);    
  32.   
  33.     JSAMPROW row_pointer[1];    
  34.   
  35.     //from up to down ,set every pixel  
  36.     for( unsigned int i=0;i<jpeg.image_height;i++ )    
  37.     {    
  38.         row_pointer[0] = rgbData+i*jpeg.image_width*3;    
  39.         jpeg_write_scanlines( &jpeg,row_pointer,1 );    
  40.     }    
  41.     //stop compress  
  42.     jpeg_finish_compress(&jpeg);    
  43.   
  44.     fclose( pFile );    
  45.     pFile = NULL;    
  46.     jpeg_destroy_compress(&jpeg);    
  47.     return 0;    
  48. }    

五、YUV数据存储为JPG

网上有不少关于YUV420数据存储为JPG的代码和博客,但是我用他们的代码,老是不成功,不是运行不起来,就是效果不好,不过还是表示万分感谢。

1、YUV420SP

  1. int yuv420p_to_jpeg(const char * filename, const char* pdata,int image_width,int image_height, int quality)  
  2. {     
  3.     struct jpeg_compress_struct cinfo;    
  4.     struct jpeg_error_mgr jerr;    
  5.     cinfo.err = jpeg_std_error(&jerr);    
  6.     jpeg_create_compress(&cinfo);    
  7.   
  8.     FILE * outfile;    // target file    
  9.     if ((outfile = fopen(filename, "wb")) == NULL) {    
  10.         fprintf(stderr, "can't open %s\n", filename);    
  11.         exit(1);    
  12.     }    
  13.     jpeg_stdio_dest(&cinfo, outfile);    
  14.   
  15.     cinfo.image_width = image_width;  // image width and height, in pixels    
  16.     cinfo.image_height = image_height;    
  17.     cinfo.input_components = 3;    // # of color components per pixel    
  18.     cinfo.in_color_space = JCS_YCbCr;  //colorspace of input image    
  19.     jpeg_set_defaults(&cinfo);    
  20.     jpeg_set_quality(&cinfo, quality, TRUE );    
  21.   
  22.     //////////////////////////////    
  23.     //  cinfo.raw_data_in = TRUE;    
  24.     cinfo.jpeg_color_space = JCS_YCbCr;    
  25.     cinfo.comp_info[0].h_samp_factor = 2;    
  26.     cinfo.comp_info[0].v_samp_factor = 2;    
  27.     /////////////////////////    
  28.   
  29.     jpeg_start_compress(&cinfo, TRUE);    
  30.   
  31.     JSAMPROW row_pointer[1];  
  32.   
  33.     unsigned char *yuvbuf;  
  34.     if((yuvbuf=(unsigned char *)malloc(image_width*3))!=NULL)  
  35.         memset(yuvbuf,0,image_width*3);  
  36.   
  37.     unsigned char *ybase,*ubase;  
  38.     ybase=pdata;  
  39.     ubase=pdata+image_width*image_height;    
  40.     int j=0;  
  41.     while (cinfo.next_scanline < cinfo.image_height)   
  42.     {  
  43.         int idx=0;  
  44.         for(int i=0;i<image_width;i++)  
  45.         {   
  46.             yuvbuf[idx++]=ybase[i + j * image_width];  
  47.             yuvbuf[idx++]=ubase[j/2 * image_width+(i/2)*2];  
  48.             yuvbuf[idx++]=ubase[j/2 * image_width+(i/2)*2+1];      
  49.         }  
  50.         row_pointer[0] = yuvbuf;  
  51.         jpeg_write_scanlines(&cinfo, row_pointer, 1);  
  52.         j++;  
  53.     }  
  54.     jpeg_finish_compress(&cinfo);    
  55.     jpeg_destroy_compress(&cinfo);    
  56.     fclose(outfile);    
  57.     return 0;    
  58. }  


2、YUV420P

其实YUV420P和YUV420SP主要区别就是取数据方式不同,前面对于YUV420P如何取数据已经讲得很清楚了,YUV420P存储为JPG只需要在上面YUV420SP存储为JPG的基础上改改取数据方法就好了。


效果:


这是一张1280X720的图片,大小385kb,因为是USB摄像头,所以图片质量感觉不是很高,总的来说效果不错!


六、YUV420SP 与 YUV420P相互转换

       知道了YUV420SP以及YUV420P的内存格式后,互相转换就不是难事了。

1、YUV420SP TO YUV420P

  1. int yuv420sp_to_yuv420p(unsigned char * yuv420sp,unsigned char* yuv420p,int width,int height)  
  2. {  
  3.     if(yuv420sp==NULL)  
  4.         return;  
  5.     int i=0,j=0;  
  6.     //Y  
  7.     for(i=0;i<width*height;i++)  
  8.     {  
  9.         yuv420p[i]=yuv420sp[i];  
  10.     }  
  11.     //U  
  12.     for(int j=0,i=0;j<width*height/2;j+=2,i++)  
  13.     {  
  14.         yuv420p[i + width*height] = yuv420sp[j+width*height];  
  15.     }  
  16.       
  17.     //V  
  18.     for(i=0,j=1,j<width*height/2;j+=2,i++)  
  19.     {  
  20.         yuv420p[i+width*height*5/4] = yuv420sp[j+width*height];  
  21.     }  
  22. }  

2、YUV420P TO YUV420SP

  1. int yuv420p_to_yuv420sp(unsigned char * yuv420p,unsigned char* yuv420sp,int width,int height)  
  2. {  
  3.     if(yuv420p==NULL)  
  4.         return;  
  5.     int i=0,j=0;  
  6.     //Y  
  7.     for(i=0;i<width*height;i++)  
  8.     {  
  9.         yuv420sp[i]=yuv420p[i];  
  10.     }  
  11.   
  12.     int m=0,n=0;  
  13.     for(int j=0;j<width*height/2;j++)  
  14.     {  
  15.         if(j%2==0)  
  16.            yuv420sp[j+width*height]=yuv420p[m++];  
  17.         else  
  18.            yuv420sp[j+width*height]=yuv420p[n++];  
  19.     }  
  20. }  

七、参考博客

没有更多推荐了,返回首页