2013-04-10 2 views
2

Я показываю живую камеру в SurfaceView с помощью camera.startPreview();. Любая идея о том, как я могу получить живые RGB-показания с камеры?Получить RGB из SurfaceView, отображающего живую камеру

Благодаря

+0

Возможный дубликат http://stackoverflow.com/questions/11761147/get-rgb-data-from-the-android-camera-in-stream – asloob

+0

Его близкий дубликат к этому вопросу. В вашем сообщении они запрашивают конкретную кодировку, где я спрашиваю о любой кодировке из SurfaceView. Не нужно ни смущать меня, ни по какой причине. – KingsInnerSoul

+0

Что вы попробовали еще раз? Ожидая, что люди напишут код для вас. То почему вы имеете downvote я догадываюсь. Я не отложил это с тех пор, как уже ответил. – Siddharth

ответ

3

Я думал, что могу преобразовать данные из 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(); 

Затем я называю setPreviewCallback и onPreviewFrame, чтобы получить входящий кадр, и преобразовать его в массив пикселей RGB. Затем я могу получить интенсивность каждого цвета в изображении, усредняя всю интенсивность пикселей, запустив массив myPixels через цикл for и проверив 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 мс для каждого кадра. Есть ли более быстрый способ сделать это?

+0

родной c/C++ ndk взять меньше, чем 15ms – SRedouane

+0

Можете ли вы опубликовать код с объяснением? – KingsInnerSoul

+0

ваш код в SDK, а не NDK: но не возвращайте массив, потому что он медленнее. Только decodeYUV420SP (rgb, data, frameWidth, frameHeight); Е/ОТЛАДКА onPreviewFrame: 13 Миллисек Е/ОТЛАДКА onPreviewFrame: 11 Миллисек Е/ОТЛАДКА onPreviewFrame: 13 Миллисек Е/ОТЛАДКА onPreviewFrame: 14 Миллисек Е/ОТЛАДКА onPreviewFrame: 11 Миллисек Е/ОТЛАДКА onPreviewFrame: 17 Миллисек Е/DEBUG onPreviewFrame: 10 millisec E/DEBUG onPreviewFrame: 11 millisec – matheszabi

3

Вы можете сделать подобное что-то вроде ниже

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); вызова методы времени захвата изображения, поэтому я думаю, что вам нужно сделать постоянно вызывать этот метод в то время как вы камера открыта.

+0

cana это решение используется для быстрого непрерывного мониторинга значений видео RGB? – KingsInnerSoul

+0

, вероятно, да, в этом случае вам не нужно сохранять захваченное изображение на SD-карте каждый раз – dhams

+0

Какой код мне нужно вызывать вместо 'onPictureTaken'? Если преобразование происходит внутри 'camera.setPreviewCallback (новый PreviewCallback() { @Override public void onPreviewFrame (байт [] данные, камера камеры) {' – KingsInnerSoul

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


      } 
    }; 
+0

Я пытаюсь реализовать ваше решение JNI, но я застрял bc в ок. строка 67, переменная 'data_uv' не определена. Можете ли вы мне помочь, что это может быть? Вот журнал ошибок: «... ошибка:« data_uv »не была объявлена ​​в этой области ...» –

+0

заменить data_uv данными – SRedouane