圖片顏色處理/ 關於RGB轉換YUV的探討與實現


 
http://topic.csdn.net/u/20120418/16/f4981bb0-e816-4d2b-ab4b-723bc0ef7e49.html

rgb的可以直接

   
   
   
           
byte []rgb = new byte [width * height * 2 ];

ByteBuffer bufferRGB = ByteBuffer.wrap(rgb);//將 byte 數組包裝到Buffer緩沖區中

Bitmap VideoBit = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);//創建一個指定大小格式的Bitmap對象


然后再
   
   
   
           
VideoBit.copyPixelsFromBuffer(bufferRGB); // 從buffer緩沖區復制位圖像素,從當前位置開始覆蓋位圖的像素

canvas.drawBitmap(VideoBit, 0, 0, null);


///////////////////////////////////////////////

http://user.qzone.qq.com/314154775/infocenter#!app=2&via=QZ.HashRefresh&pos=1335403809
 

最近在Android手機上使用相機識別條形碼工作取得了比較理想的進展,自動識別功能基本完成,然而在手動識別指定條形碼圖片時遇到困難,由於Zxing開源Jar包識別圖片的顏色編碼式為YUV,而普通的圖片使用RGB顏色分量來保存顏色信息。非壓縮的24位的BMP圖像就采用RGB空間來保存圖像。一個像素24位,每8位保存一種顏色強度(0-255),例如紅色保存為 0xFF0000經過兩天的探索與查閱相關YUVRGB資料后,嘗試編寫了RGB轉換為YUV代碼,幾番調試后終於轉換成功。下面就作一些簡單介紹,然后貼出代碼。

YUV是被歐洲電視系統所采用的一種顏色編碼方法。其中“Y”表示明亮度(LuminanceLuma),也就是灰階值;而“U”“V”表示的則是色度(ChrominanceChroma)。在彩色的廣播電視中,並不是直接傳送RGB三基色信號,而是把三基色經過轉換成可以代表三基色信號的新的三個基本參量YUV來傳輸的。YUV格式通常有兩大類,打包格式和平面格式。打包格式有以下幾種:YUV2格式,YUYV格式, YVYU格式, UYVY格式。平面格式有IF09格式,IYUV格式,YVU9格式。Android攝像頭預覽的視頻流色彩編碼方案默認為YCbCr420,其中420表示21的水平下采樣,21的垂直下采樣,體現為以下分布。

詳見:http://blog.csdn.net/SearchSun/article/details/2443867

 

 

圖片

 

 

                   

我以我理解的方式來表示來RGBYCbCr420的對應關系,請看下圖。

 

圖片

 

 

如上圖所示為一張(寬X高)為(6 *4),即len=6×4的RGB編碼位圖,圖中的每一個小球代表一個像素點。在便攜式視頻設備(MPEG-4)中,YCbCr420是最常用的格式,表示每4個像素有4個亮度分量,2個色度分量(YYYYCbCr)。從圖上,可以直觀地看出4個像素點共享UV分量(顏色標志相同的小球),也即21的水平下采樣,21的垂直下采樣。接下來,申請一個字節數組來保存YUV數據,該YUV的數組長度為len×3/2,Y分量占len長度字節,UV分別占len/4長度字節。

 

代碼:

len = width * height;

byte[] yuv = new byte[len * 3 / 2];

 

上圖中的坐標值表示該分量在在YUV數組中位置index。現在給出index計算方式:

   Y_index = (i * width + j);

   U_index= (len + (i >> 1) * width + (j & ~1) + 0)

   V_index=(len + (i >> 1) * width + (j & ~1) + 1)

 

YUV分量與RGB分量的對應關系為:

y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;     

u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;

              v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;

              r = 1.166f * (y - 16) + 1.596f * (v - 128);

              g = 1.164f * (y - 16) - 0.813f * (v - 128)- 0.391f * (u - 128);

              b = 1.164f * (y - 16) + 2.018f * (u - 128);

 

因此代碼很容易就可寫出:假定已獲取到像素值,如果是一張圖片,你可以通過代碼先獲得該圖片的像素值整型數組,然后傳入該數組,以及該圖片的寬度和高度調用以下方法即可獲取YCbCr420格式數組。

    

    public byte[] rgb2YCbCr420(int[] pixels, int width, int height) {

       int len = width * height;

       //yuv格式數組大小,y亮度占len長度,u,v各占len/4長度。

       byte[] yuv = new byte[len * 3 / 2];          

       int y, u, v;

       for (int i = 0; i < height; i++) {

           for (int j = 0; j < width; j++) {

//屏蔽ARGB的透明度值

              int rgb = pixels[i * width + j] & 0x00FFFFFF; 

              //像素的顏色順序為bgr,移位運算。

int r = rgb & 0xFF;                          

              int g = (rgb >> 8) & 0xFF;

              int b = (rgb >> 16) & 0xFF;

              //套用公式

y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;     

u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;

              v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;

              //調整

              y = y < 16 ? 16 : (y > 255 ? 255 : y);       

              u = u < 0 ? 0 : (u > 255 ? 255 : u);

              v = v < 0 ? 0 : (v > 255 ? 255 : v);

              //賦值

              yuv[i * width + j] = (byte) y;        

              yuv[len + (i >> 1) * width + (j & ~1) + 0] = (byte) u;

              yuv[len + +(i >> 1) * width + (j & ~1) + 1] = (byte) v;

           }

       }

       return yuv;

}

 

再附上YCbCr420轉換成RGB的代碼,可以通過該代碼還原RGB位圖。

  

  public void yCbCr2Rgb (byte[] yuv, int width, int height) {

       int frameSize = width * height;

       int[] rgba = new int[frameSize];

       for (int i = 0; i < height; i++){

           for (int j = 0; j < width; j++) {

              int y = (0xff & ((int) yuv[i * width + j]));

              int u = (0xff & ((int) yuv [frameSize + (i >> 1) * width

                     + (j & ~1) + 0]));

              int v = (0xff & ((int) yuv [frameSize + (i >> 1) * width

                     + (j & ~1) + 1]));

 

              y = y < 16 ? 16 : y;

 

              int r = Math.round(1.166f * (y - 16) + 1.596f * (v - 128));

              int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128)

                     - 0.391f * (u - 128));

              int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));

 

              r = r < 0 ? 0 : (r > 255 ? 255 : r);

              g = g < 0 ? 0 : (g > 255 ? 255 : g);

              b = b < 0 ? 0 : (b > 255 ? 255 : b);

 

              rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;

           }

         }    

       Bitmap bmp = Bitmap.createBitmap(width, height,

              Bitmap.Config.ARGB_8888);

       bmp.setPixels(rgba, 0, width, 0, 0, width, height);

       String bmpName = "test.jpg";

       String path = Environment.getExternalStorageDirectory()

              .getAbsolutePath() + "/scan_test";

        // 文件目錄

       File root = new File(path);

       if (!root.isDirectory() || !root.exists()) {

           root.mkdirs();

       }

       File myCaptureFile = new File(path, bmpName);

       try {

           myCaptureFile.createNewFile();

       } catch (IOException e1) {

           // TODO Auto-generated catch block

           e1.printStackTrace();

       }

       try {

           BufferedOutputStream bos = new BufferedOutputStream(

                  new FileOutputStream(myCaptureFile));

           // 采用壓縮轉檔方法

           bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);

           bos.flush();

           bos.close();

 

       } catch (Exception e) {

           myCaptureFile.delete();

       }    

   }

}
 
參考資料:
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM