2017-09-21 1 views
0

Je veux montrer la caméra et les lignes que j'ai détectées en temps réel (en utilisant i.MX6 et Android 4.4). J'utilise l'appareil photo Android .addCallbackBuffer pour obtenir l'image et utiliser TextureView pour afficher l'aperçu de la caméra.Puis-je utiliser TextureView pour afficher l'aperçu de la caméra et la ligne détectée en même temps?

JNI (C++): obtenir cadre Buffer-> convertir octet [] à Mat-> que l'utilisation OpenCV pour faire du traitement d'image

JNI peut retourner Mat (utiliser .getNativeObjAddr()) qui attirent déjà des lignes sur elle ou renvoyer deux coordonnées qui sont les points de départ et de fin de la ligne

Ce code nouveau Mat dans JNI et espère juste retourner deux coordonnées. Si cette méthode ne peut pas fonctionner, je vais ajouter Mat dans JAVA et envoyer .getNativeObjAddr() à JNI, puis retourner Mat. Afficher Mat dans TextureView? Comment afficher l'aperçu de la caméra et la ligne détectée en même temps en utilisant TextureView?

Dans MainActivity.java

public class MainActivity extends Activity implements TextureView.SurfaceTextureListener, PreviewCallback { 
protected Camera mCamera; 
private TextureView mTextureView; 
public byte[][] cameraBuffer; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
    setContentView(R.layout.activity_main); 

    mTextureView = new TextureView(this); 
    mTextureView.setSurfaceTextureListener(this); 
    setContentView(mTextureView); 
} 
.... 
@Override 
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 
    mCamera = Camera.open(0); 
    int bufferSize = mCamera.getParameters().getPictureSize().width * mCamera.getParameters().getPictureSize().height 
      * ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat())/8; 
    cameraBuffer = new byte[3][bufferSize]; 

    thread = new getFrameThread(this, kCameraWidth, kCameraHeight); 
    for (int i = 0; i < 3; ++i) 
     mCamera.addCallbackBuffer(cameraBuffer[i]); 

    mCamera.setPreviewCallbackWithBuffer(this);    
    thread.start(); 

    if (mCamera == null) { 
     throw new RuntimeException("Default camera not available"); 
    } 
    try { 
     mCamera.setPreviewTexture(surface); 
     mCamera.startPreview(); 
    } catch (IOException ioe) { 
     // Something bad happened 
    } 
} 

@Override 
public void onPreviewFrame(byte[] data, Camera camera) { 
    // TODO Auto-generated method stub 
    camera.addCallbackBuffer(data);//callback data to cameraBuffer 
    thread.refresh(data, countFrame);//send new frame data to JNI 
} 
.... 
static { 
    System.loadLibrary("opencv_java"); //load opencv_java lib 
    System.loadLibrary("testLib"); 
} 
public native void getRawFrame(byte[] data,int width, int height, int count); 

} 

Dans getFrameThread (thread à exécuter la fonction JNI 'getRawFrame')

public class getFrameThread extends Thread{ 
    public byte[] data; 
    { 
    ..... 
    mainActivity.getRawFrame(data, 480, 720); 
    ..... 
    } 

    public void refresh(byte[] data, int countFrame){ 
     this.data = data; 
    } 
} 

Dans JNI

#include <jni.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include <opencv2/opencv.hpp> 
using namespace cv; 

extern"C" 
{ 
..... 
JNIEXPORT void JNICALL Java_com_example_adas_MainActivity_getRawFrame(JNIEnv* env, jobject thisobject, 
    jbyteArray data, jint width, jint height){ 

    int length = env->GetArrayLength(data); 
    unsigned char *bufferIn = (unsigned char*) env->GetPrimitiveArrayCritical(data, NULL); 

    yuvMat = Mat(height * 3/2, width, CV_8UC1, bufferIn); 
    cvtColor(yuvMat, grayMat, cv::COLOR_YUV2GRAY_I420); 


    //Do lines detected 
    ..... 
    env->ReleasePrimitiveArrayCritical(data, bufferIn, JNI_ABORT); 
} 

Répondre

0

Vous pouvez superposer la caméra en direct TextureView avec une vue d'image, il est possible que cette image soit partiellement transparente. Mais ce n'est pas une bonne solution pour la réalité augmentée. La raison en est que le contenu généré par OpenCV est livré avec un délai. Ce délai peut ne pas être très significatif, mais il peut être très ennuyeux pour l'utilisateur.

Le résultat est bien meilleur si vous masquez le flux de caméra en direct et affichez l'image (provenant de onPreviewFrame()) modifiée par le traitement OpenCV. Le RA affiché sur l'écran sera retardé de quelques millisecondes (par rapport à la vue en direct de la caméra), mais la scène sera cohérente avec les lignes détectées. J'ai trouvé un bon exemple (et des instructions de programmation détaillées) dans ce blog post.

Vous avez toujours besoin de TextureView, car l'API de l'appareil Android exige que vous disposiez d'un aperçu en direct pour recevoir les rappels onPreviewFrame(). Pour cacher cela, vous pouvez le superposer avec d'autres vues, ou manipuler la texture au niveau d'OpenGL.

Vous pouvez également utiliser OpenGL pour afficher le résultat d'OpenCV: souvent, la performance d'un tel flux de travail est bien meilleure que d'utiliser d'autres moyens pour afficher les images.

Vous pouvez également utiliser OpenGL pour dessiner les lignes - les résultats du traitement OpenCV - sous la forme bitmap et utiliser l'aperçu de la caméra comme texture distincte.

+0

Merci, je vais essayer 'OpenGL pour afficher le résultat de OpenCV' cette méthode. –

+0

Pouvez-vous me donner un indice ou une fonction pour utiliser OpenGL pour afficher le résultat d'OpenCV? Merci. –

+0

Je peux recommander [graphika] (https://github.com/google/grafika) comme un bon point de départ pour apprendre la relation OpenGL avec la caméra Android. Vous pouvez également trouver ce [article] (http://www.anandmuralidhar.com/blog/android/corners/) utile. Il illustre mon point principal: les points rouges sont épinglés aux pixels corrects sur l'écran, même si le flux entier est un peu retardé. –