最近在做Android上图片编辑的软件,我用Android自带的Bitmap.getPixels()函数获得了图片原始数据的数组int[] data.
这个整形数组每一个int就代表图像一个像素的argb,也就是获得的原始数据为ARGB24格式。现在要把这个整形数组转为YUV420格式的数组。找了网上的资料,几天都没搞出来,只找到了YUV420转为RGB24的函数(在后面附上)。我现在的需求类似这个函数,只是要把RGB24转YUV420而已,函数的原型为public void decodeRGB24(byte[] rgbBuf, byte[] yuv420sp, int width, int height) { ... }.哪位高手指教一下啊,不胜感激啊附上YUV420转为RGB24的函数:public void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) {    final int frameSize = width * height;   
if (rgbBuf == null)    throw new NullPointerException("buffer 'rgbBuf' is null");   
if (rgbBuf.length < frameSize * 3)    throw new IllegalArgumentException("buffer 'rgbBuf' size "
              + rgbBuf.length + " < minimum " + frameSize * 3);    if (yuv420sp == null)    throw new NullPointerException("buffer 'yuv420sp' is null");    if (yuv420sp.length < frameSize * 3 / 2)    throw new IllegalArgumentException("buffer 'yuv420sp' size " + yuv420sp.length   
              + " < minimum " + frameSize * 3 / 2);   
int i = 0, y = 0;    int uvp = 0, u = 0, v = 0;    int y1192 = 0, r = 0, g = 0, b = 0;   
for (int j = 0, yp = 0; j < height; j++) {   
          uvp = frameSize + (j >> 1) * width;   
          u = 0;   
          v = 0;    for (i = 0; i < width; i++, yp++) {   
              y = (0xff & ((int) yuv420sp[yp])) - 16;    if (y < 0) y = 0;    if ((i & 1) == 0) {   
                  v = (0xff & yuv420sp[uvp++]) - 128;   
                  u = (0xff & yuv420sp[uvp++]) - 128;   
              }                  y1192 = 1192 * y;   
              r = (y1192 + 1634 * v);   
              g = (y1192 - 833 * v - 400 * u);   
              b = (y1192 + 2066 * u);   
if (r < 0) r = 0; else
if (r > 262143) r = 262143;    if (g < 0) g = 0; else
if (g > 262143) g = 262143;    if (b < 0) b = 0; else
if (b > 262143) b = 262143;                  rgbBuf[yp * 3] = (byte)(r >> 10);   
              rgbBuf[yp * 3 + 1] = (byte)(g >> 10);   
              rgbBuf[yp * 3 + 2] = (byte)(b >> 10);   
          }   
      }   
    }   

解决方案 »

  1.   

    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);吧
      

  2.   

    楼上的想法不错,继续寻找最佳答案,因为我现在的要把RGB转为YUV,然后将YUV原始数据进行编码。。
      

  3.   

    基本实现了转换
    http://user.qzone.qq.com/314154775/infocenter#!app=2&pos=1335403809
      

  4.   


    我用了,但是不能转换为原图,图片失真了。把我的测试代码粘上。我用你的函数获得一个yuv数组后,然后把这个数组写到一个文件,最后用elecard yuv viewer(下载地址http://www.onlinedown.net/softdown/98570_2.htm,该软件传入yuv原始数据可以观看图片)打开这个文件,发现图片与原图不一样。。不知道是哪里出了问题,请多多指教啊,非常谢谢!public void onCreate(Bundle savedInstanceState)
        { 
            super.onCreate(savedInstanceState);
    //在drawable文件夹中加入一张名为rgb的图片。
            Bitmap map = ((BitmapDrawable)getResources().getDrawable(R.drawable.rgb)).getBitmap();
            int width = map.getWidth();
            int height = map.getHeight();
            System.out.println(width);
            System.out.println(height);
            int[] buffer = new int[width*height];
            map.getPixels(buffer, 0, width, 0, 0, width, height);
            byte[] yuv = rgb2YCbCr420(buffer,width,height);
            FileOutputStream out;
    try {
    out = new FileOutputStream("/sdcard/yuvchange");
    for(byte a:yuv){
    //byte的范围为-128到127,要将-128到-1转为0到255.
    if(a>=(-128) && a<=(-1) ){
    int b = 127-(-128-a-1); 
    out.write(b);
    }   
    else out.write(a);
     
    }
    } catch (Exception e) {

    e.printStackTrace();
    }
    }
    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;
    }运行的过程比较慢,最后在Eclipse中导出yuvchange文件用elecard yuv viewer打开就可以看到转换后的图片效果。请各位指教。
      

  5.   

    你读取的图片是什么格式的,换成非压缩的bmp格式看看
      

  6.   


    换了,我换了png,bmp,jpg还是不行。。麻烦写一个类似我上面的操作(9楼)的demo啊。。谢谢了!!
      

  7.   

    对楼上的一点疑问:
    pixe:像素为32为 int[]
    yuv :为8为     byte[]pixe存储方式为: 11111111 11111111 11111111 11111111
                    透明通道   r         g       b
    yuv存储方式为 : 11111111
                   如何存放呢?
    //-------------------------------------------------------------
     VideoBit.copyPixelsFromBuffer(bufferRGB);
    bufferRGB 为byte 那他存储格式呢?
      

  8.   

    //屏蔽ARGB的透明度值
    int rgb = pixels[i * width + j] & 0x00FFFFFF; 
    //像素的颜色顺序为bgr,移位运算。
    int r = rgb & 0xFF;                          
    int g = (rgb >> 8) & 0xFF;
    int b = (rgb >> 16) & 0xFF;
    ---------------------------------------
    pixe存储方式为: 11111111 11111111 11111111 11111111
                    透明通道   r         g       b所以位移为
    int b = rgb & 0xFF;                          
    int g = (rgb >> 8) & 0xFF;
    int r = (rgb >> 16) & 0xFF;
      

  9.   

    这样的操作建议用JNI来实现。C做这样的大循环操作比java快多了而且我现在用c实现这样的格式转换的开源代码很多