【问题标题】:Get RGB from a SurfaceView displaying Live camera从显示 Live 摄像头的 SurfaceView 获取 RGB
【发布时间】:2013-04-01 20:12:06
【问题描述】:

我正在使用camera.startPreview();SurfaceView 中显示实时摄像机。关于如何从相机获取实时 RGB 读数的任何想法?

谢谢

【问题讨论】:

  • 它与该问题几乎重复。在您的帖子中,他们要求提供特定的编码,我在其中询问来自 SurfaceView 的任何编码。没有必要无缘无故地抨击我。
  • 你又尝试了什么?期待人们为您编写代码。这就是我猜你有反对票的原因。自从它已经回答以来,我还没有投反对票。

标签: android colors camera rgb surfaceholder


【解决方案1】:

你可以做类似下面的事情

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); 方法调用图像捕获时间,所以我认为你需要在相机打开时不断调用这个方法。

【讨论】:

  • 该解决方案能否用于快速连续监控视频 RGB 值?
  • 可能是的,这样你就不需要每次都将捕获的图像保存在SD卡上
  • 我应该调用哪个代码而不是onPictureTaken?如果转换发生在camera.setPreviewCallback(new PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) {
  • 看来需要在时间间隔内调用这一行 camera.takePicture(shutterCallback, rawCallback, jpegCallback);
【解决方案2】:

我想我可以得到从SurfaceView 转换的数据。但最好的使用方法是:

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

列表项

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

然后,我调用setPreviewCallbackonPreviewFrame 来获取传入帧,并将其转换为RGB 像素阵列。然后,我可以通过通过for 循环运行 myPixels 数组并检查Color.red(myPixels[i]) 的每种所需颜色(在onPreviewFrame 内)来平均所有像素强度,从而获得图片中每种颜色的强度。

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 毫秒。 有没有更快的方法?

【讨论】:

  • 原生 c/c++ ndk 耗时不到 15 毫秒
  • 你在 SDK 中的代码,不是 NDK:但不要返回数组,因为它更慢。仅 decodeYUV420SP(rgb, data, frameWidth, frameHeight); E/DEBUG onPreviewFrame:13 毫秒 E/DEBUG onPreviewFrame:11 毫秒 E/DEBUG onPreviewFrame:13 毫秒 E/DEBUG onPreviewFrame:14 毫秒 E/DEBUG onPreviewFrame:11 毫秒 E/DEBUG onPreviewFrame:17 毫秒 E/DEBUG onPreviewFrame:10 毫秒 E /DEBUG onPreviewFrame: 11 毫秒
  • @matheszabi,您是否期待 3 年前的完全优化代码?我什么时候才开始学习 Android 编程?仅供参考,技术已经改变 - 编程风格也发生了变化......
【解决方案3】:

这里要求的是使用 NDK 的快速解码(在快速设备上少于 10 毫秒):

这里首先是native.h

#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

native.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);


            }
    };

【讨论】:

  • 我正在尝试实施您的 JNI 解决方案,但我在 ca.第 67 行未定义“data_uv”变量。你能帮我看看它可能是什么吗?这是错误日志:“...错误:'data_uv' 未在此范围内声明...”
  • 用数据替换data_uv
猜你喜欢
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多