代码之家  ›  专栏  ›  技术社区  ›  KingsInnerSoul

从显示实时相机的SurfaceView获取RGB

  •  4
  • KingsInnerSoul  · 技术社区  · 13 年前

    我正在中显示实时摄像机 SurfaceView 使用 camera.startPreview(); 。你知道我如何从相机中获得实时RGB读数吗?

    谢谢

    3 回复  |  直到 13 年前
        1
  •  5
  •   KingsInnerSoul    13 年前

    我想我可以从 SurfaceView 。但最好的使用方法是:

    • 将相机的方向设置为90度。
    • 将输出格式设置为NV21(即 guranteed 在所有设备上都支持)。
    • 设置为打开闪光灯。
    • 在中开始预览 曲面视图 .

    列表项目

    camera = Camera.open();
    cameraParam = camera.getParameters();
    cameraParam.setPreviewFormat(ImageFormat.NV21);
    camera.setDisplayOrientation(90);
    camera.setParameters(cameraParam);
    cameraParam = camera.getParameters();
    camera.setPreviewDisplay(surfaceHolder);
    cameraParam.setFlashMode(Parameters.FLASH_MODE_TORCH);
    camera.setParameters(cameraParam);
    camera.startPreview();
    

    然后,我打电话给 setPreviewCallback onPreviewFrame 以获取传入帧,并将其转换为RGB像素阵列。然后,我可以通过运行myPixels数组来平均所有像素的强度,从而获得图片中每种颜色的强度 for 循环和检查 Color.red(myPixels[i]) 对于每个所需的颜色(在 on预览框架 ).

    camera.setPreviewCallback(new PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            int frameHeight = camera.getParameters().getPreviewSize().height;
            int frameWidth = camera.getParameters().getPreviewSize().width;
            // number of pixels//transforms NV21 pixel data into RGB pixels  
            int rgb[] = new int[frameWidth * frameHeight];
            // convertion
            int[] myPixels = decodeYUV420SP(rgb, data, frameWidth, frameHeight);
        }
    }
    

    哪里 decodeYUV420SP 已找到 here .

    我将此操作的时间定为每帧花费约200毫秒。 有没有更快的方法?

        2
  •  4
  •   dharmendra    13 年前

    你可以做类似的事情,如下所示

    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
    
        jpegCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            FileOutputStream outStream = null;
            try {
                Bitmap bitmap = BitmapFactory.decodeByteArray(data, offset, length);
    
             int[] pix = new int[picw * pich];
             bitmap.getPixels(pix, 0, picw, 0, 0, picw, pich);
    
             int R, G, B,Y;
    
             for (int y = 0; y < pich; y++){
             for (int x = 0; x < picw; x++)
                 {
                 int index = y * picw + x;
                 int R = (pix[index] >> 16) & 0xff;     //bitwise shifting
                 int G = (pix[index] >> 8) & 0xff;
                 int B = pix[index] & 0xff;
    
                 pix[index] = 0xff000000 | (R << 16) | (G << 8) | B;
                 }}
    
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
         }
    };
    

    在这里 camera.takePicture(shutterCallback, rawCallback, jpegCallback); 方法调用图像捕获时间,所以我认为你需要在相机打开时不断调用这个方法。

        3
  •  3
  •   SRedouane    11 年前

    如这里所要求的是使用NDK的快速解码(在快速设备上小于10ms):

    首先是本地人

    #include <jni.h>
    #ifndef native_H
    #define native_H
    extern "C" {
    JNIEXPORT jbyteArray JNICALL Com_example_MainActivity_nativeSetIamgeFromCamera(JNIEnv* jenv, jobject obj,jbyteArray array,jint length,jint x,jint y);
    };
    #endif
    

    本地.cpp

        #include <stdint.h>
            #include <jni.h>
            #include <stdlib.h>
            #include <string.h>
            #include <stdio.h>
            #include <android/native_window.h>
            #include <android/native_window_jni.h>
            #include <sys/types.h>
            #include <stdio.h>
            #include <string.h>
            #include <sys/types.h>
            #include <time.h>
            #include "native.h"
    
    void Resize_and_decodyuv(unsigned char * data,int _width,int _height, unsigned char *out, int newWidth, int newHeight);
    
    JNIEXPORT jbyteArray JNICALL Com_example_MainActivity_nativeSetIamgeFromCamera(JNIEnv* jenv, jobject obj,jbyteArray array,jint length,jint x,jint y)
        {
        //-----jbyteArray array contain the data from the camera passed by the java function
        //-----length represent the size of jbyteArray in byte
        //-----x,y respectively resolutionx and resolutiony of the image in jbyteArray array
    
        unsigned char * buffImgCamera=(unsigned char *)malloc(length);
    
        //----- copy the buffer from java array to c/c++ char * buffImgCamera
        jenv->GetByteArrayRegion(array, 0, length, (jbyte*)buffImgCamera);
    
       int width=400,height=600;//screen reso of the surface(400,800 is just an example)
       unsigned char * buffOut=(unsigned char *)malloc(width*height*4);//prepare the result buffer where 4 represent R G B A(Alpha transparency channel).
    
    
        //--- to gain time i decode and resize the image to fit the surface screen in one loop
        Resize_and_decodyuv(buffImgCamera,x,y,buffOut,width,height);
        //---copy the result to a jbytearray and return it to java function
        jbyteArray result=env->NewByteArray(width*height*4);
        env->SetByteArrayRegion( result, 0, width*height*4, buffOut);
    
        return result;
        }
    
    
    
    void Resize_and_decodyuv(unsigned char * data,int _width,int _height, unsigned char *out, int newWidth, int newHeight)
        {
    
    
    int Colordeep=4;//RGBA; in the case of Qt Frame Work or Borland just put 3and the code should work;
    
            float scaleWidth =  (float)newWidth / (float)_width;
            float scaleHeight = (float)newHeight / (float)_height;
    
    
            for(int cy = 0; cy < newHeight; cy++)
            {
                for(int cx = 0; cx < newWidth; cx++)
                {
                    int pixel = (cy * (newWidth *Colordeep)) + (cx*Colordeep);
                    int nearestMatch =  ((((int)(cy / scaleHeight)) *_width) + (int)(cx /scaleWidth));
    
                    int cxa=cx/scaleWidth;
                    int cya=cy/scaleHeight; cya/=2;
                    int nearestMatch1 =(cya *_width) + (int)(cxa);
    
    
    
    
                    int y =  ( data[nearestMatch]);
    
                          int v = data[data_uv+(nearestMatch1)];
                          int u = data[data_uv+(nearestMatch1)+1];
    
    
    
                          int r = (int) (1164 * (y - 16) + 1596 * (v - 128));
                          int g = (int) (1164 * (y - 16) - 813 * (v - 128) - 391 * (u - 128));
                          int b = (int) (1164 * (y - 16) + 2018 * (u - 128));
              r/=1000;
              g/=1000;
              b/=1000;
                          r = r < 0 ? 0 : (r > 255 ? 255 : r);
                          g = g < 0 ? 0 : (g > 255 ? 255 : g);
                          b = b < 0 ? 0 : (b > 255 ? 255 : b);
    
    
    
                    out[pixel ] = r;
                    out[pixel  +1  ] =  g;
                    out[pixel + 2] =  b;
                    if(Colordeep==4)out[pixel + 3] =  255;
    
    
                }
            }
    
    
        }
    

    java代码

    PreviewCallback previewCallback = new PreviewCallback () {
    
    
                public void onPreviewFrame(byte[] data, Camera camera) {
                    //nativeSetIamgeFromCamera return a byte array  
                    nativeSetIamgeFromCamera(data,data.length,camera.getParameters().getPreviewSize().width,camera.getParameters().getPreviewSize().height);
    
    
                }
        };