Могу ли я использовать TextureView для одновременного отображения предварительного просмотра камеры и обнаруженной линии?

Я хочу показать камеру и линии, которые я обнаружил в режиме реального времени (используя i.MX6 и Android 4.4). Я использую камеру Android .addCallbackBuffer для получения кадра и использую TextureView для отображения предварительного просмотра камеры.

JNI (C++): получить кадровый буфер-> преобразовать byte[] в Mat-> чем использовать OpenCV для обработки изображений

JNI может возвращать Mat (использовать .getNativeObjAddr()), который уже рисует на нем линии, или возвращать две координаты, которые являются начальной и конечной точками линии.

Этот код создает новый мат в JNI и надеется просто вернуть две координаты. Если этот метод не сработает, я создам новый Mat в JAVA и отправлю .getNativeObjAddr() в JNI, а затем верну Mat. Показать мат в TextureView?

Вопрос: Как одновременно показать предварительный просмотр камеры и обнаруженную линию с помощью TextureView?

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

}

В getFrameThread (поток для запуска функции 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;
  }
}

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

person Julia Ding    schedule 21.09.2017    source источник


Ответы (1)


Вы можете наложить TextureView в реальном времени с камеры на изображение, это нормально, если это изображение будет частично прозрачным. Но это не лучшее решение для дополненной реальности. Причина в том, что контент, сгенерированный из OpenCV, приходит с задержкой. Эта задержка может быть не очень существенной, но может сильно раздражать пользователя.

Результат будет намного лучше, если вы скроете прямой поток с камеры и отобразите изображение (исходящее из onPreviewFrame()), измененное обработкой OpenCV. AR, отображаемый на экране, будет отставать на несколько миллисекунд (по сравнению с просмотром камеры в реальном времени), но сцена будет соответствовать обнаруженным линиям. Я нашел хороший пример (и подробные инструкции по программированию) в этом сообщении в блоге.

Вам по-прежнему нужен TextureView, потому что Android Camera API требует, чтобы у вас был предварительный просмотр в реальном времени для получения onPreviewFrame() обратных вызовов. Чтобы скрыть это, вы можете наложить его на некоторые другие представления или манипулировать текстурой на уровне OpenGL.

Вы также можете использовать OpenGL для отображения результата OpenCV: часто производительность такого рабочего процесса намного выше, чем при использовании других способов отображения изображений.

Вы также можете использовать OpenGL для рисования линий — результатов обработки OpenCV — не в виде bitmap, а использовать предварительный просмотр камеры как отдельную текстуру.

person Alex Cohn    schedule 21.09.2017
comment
Спасибо, я попробую «OpenGL для отображения результата OpenCV» этим методом. - person Julia Ding; 22.09.2017
comment
Можете ли вы дать мне подсказку или функцию для использования OpenGL для отображения результата OpenCV? Спасибо. - person Julia Ding; 22.09.2017
comment
Я могу порекомендовать graphika как хорошую отправную точку для изучения связи OpenGL с камерой Android. Вы также можете найти эту статью полезной. Это иллюстрирует мою основную мысль: красные точки закреплены на правильных пикселях на экране, даже если весь поток немного задерживается. - person Alex Cohn; 22.09.2017
comment
Спасибо еще раз. В статье очень подробно описано. - person Julia Ding; 25.09.2017