Я показываю живую камеру в SurfaceView
с помощью camera.startPreview();
. Любая идея о том, как я могу получить живые RGB-показания с камеры?Получить RGB из SurfaceView, отображающего живую камеру
Благодаря
Я показываю живую камеру в SurfaceView
с помощью camera.startPreview();
. Любая идея о том, как я могу получить живые RGB-показания с камеры?Получить RGB из SurfaceView, отображающего живую камеру
Благодаря
Я думал, что могу преобразовать данные из SurfaceView
. Но лучший способ использования:
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 мс для каждого кадра. Есть ли более быстрый способ сделать это?
родной c/C++ ndk взять меньше, чем 15ms – SRedouane
Можете ли вы опубликовать код с объяснением? – KingsInnerSoul
ваш код в 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
Вы можете сделать подобное что-то вроде ниже
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);
вызова методы времени захвата изображения, поэтому я думаю, что вам нужно сделать постоянно вызывать этот метод в то время как вы камера открыта.
cana это решение используется для быстрого непрерывного мониторинга значений видео RGB? – KingsInnerSoul
, вероятно, да, в этом случае вам не нужно сохранять захваченное изображение на SD-карте каждый раз – dhams
Какой код мне нужно вызывать вместо 'onPictureTaken'? Если преобразование происходит внутри 'camera.setPreviewCallback (новый PreviewCallback() { @Override public void onPreviewFrame (байт [] данные, камера камеры) {' – KingsInnerSoul
в соответствии с просьбой здесь, является быстрое декодирование с использованием 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, но я застрял bc в ок. строка 67, переменная 'data_uv' не определена. Можете ли вы мне помочь, что это может быть? Вот журнал ошибок: «... ошибка:« data_uv »не была объявлена в этой области ...» –
заменить data_uv данными – SRedouane
Возможный дубликат http://stackoverflow.com/questions/11761147/get-rgb-data-from-the-android-camera-in-stream – asloob
Его близкий дубликат к этому вопросу. В вашем сообщении они запрашивают конкретную кодировку, где я спрашиваю о любой кодировке из SurfaceView. Не нужно ни смущать меня, ни по какой причине. – KingsInnerSoul
Что вы попробовали еще раз? Ожидая, что люди напишут код для вас. То почему вы имеете downvote я догадываюсь. Я не отложил это с тех пор, как уже ответил. – Siddharth