2016-07-03 3 views
0

Я изо всех сил пытался реализовать приложение для Android, которое применяет DFT прямо на экране камеры. Выполнение исследований на StackOverflow, я мог бы найти в следующих разделах:Android Real Time DFT в режиме просмотра камеры с использованием OpenCV

SOLVED - Load Image in Mat and Display after DFT process

SOLVED - Load Image in Mat and Display after DFT process

Convert OpenCv DCT to Android

Я также пробовал различные решения с использованием JNI: http://allaboutee.com/2011/11/12/discrete-fourier-transform-in-android-with-opencv/

И то я мог бы реализовать свой основной вид деятельности:

package ch.hepia.lsn.opencv_native_androidstudio; 

import android.app.Activity; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.SurfaceView; 
import android.view.WindowManager; 
import org.opencv.android.BaseLoaderCallback; 
import org.opencv.android.CameraBridgeViewBase; 
import android.hardware.Camera; 
import org.opencv.android.LoaderCallbackInterface; 
import org.opencv.android.OpenCVLoader; 
import org.opencv.core.Core; 
import org.opencv.core.CvType; 
import org.opencv.core.Mat; 
import org.opencv.core.Rect; 
import org.opencv.core.Size; 
import org.opencv.imgproc.Imgproc; 

import java.util.ArrayList; 
import java.util.List; 

public class MainActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 { 
    private static final String TAG = "OCVSample::Activity"; 

    private CameraBridgeViewBase mOpenCvCameraView; 

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { 
     @Override 
     public void onManagerConnected(int status) { 
      switch (status) { 
       case LoaderCallbackInterface.SUCCESS: { 
        Log.i(TAG, "OpenCV loaded successfully"); 
        mOpenCvCameraView.enableView(); 
       } 
       break; 
       default: { 
        super.onManagerConnected(status); 
       } 
      } 
     } 
    }; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // Load ndk built module, as specified 
     // in moduleName in build.gradle 
     System.loadLibrary("native"); 

     getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 

     setContentView(R.layout.activity_main); 

     mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.main_surface); 
     mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); 
     mOpenCvCameraView.setCvCameraViewListener(this); 
    } 

    @Override 
    public void onPause() { 
     super.onPause(); 
     disableCamera(); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     if (!OpenCVLoader.initDebug()) { 
      Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization"); 
      OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback); 
     } else { 
      Log.d(TAG, "OpenCV library found inside package. Using it!"); 
      mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); 
     } 
    } 

    public void onDestroy() { 
     super.onDestroy(); 
     disableCamera(); 
    } 

    public void disableCamera() { 
     if (mOpenCvCameraView != null) 
      mOpenCvCameraView.disableView(); 
    } 

    public void onCameraViewStarted(int width, int height) { 
    } 

    public void onCameraViewStopped() { 
    } 

    private Mat getDFT(Mat singleChannel) { 

     singleChannel.convertTo(singleChannel, CvType.CV_64FC1); 

     int m = Core.getOptimalDFTSize(singleChannel.rows()); 
     int n = Core.getOptimalDFTSize(singleChannel.cols()); // on the border 
     // add zero 
     // values 
     // Imgproc.copyMakeBorder(image1, 
     // padded, 0, m - 
     // image1.rows(), 0, n 

     Mat padded = new Mat(new Size(n, m), CvType.CV_64FC1); // expand input 
     // image to 
     // optimal size 

     Core.copyMakeBorder(singleChannel, padded, 0, m - singleChannel.rows(), 0, 
       n - singleChannel.cols(), Core.BORDER_CONSTANT); 

     List<Mat> planes = new ArrayList<Mat>(); 
     planes.add(padded); 
     planes.add(Mat.zeros(padded.rows(), padded.cols(), CvType.CV_64FC1)); 

     Mat complexI = Mat.zeros(padded.rows(), padded.cols(), CvType.CV_64FC2); 

     Mat complexI2 = Mat 
       .zeros(padded.rows(), padded.cols(), CvType.CV_64FC2); 

     Core.merge(planes, complexI); // Add to the expanded another plane with 
     // zeros 

     Core.dft(complexI, complexI2); // this way the result may fit in the 
     // source matrix 

     // compute the magnitude and switch to logarithmic scale 
     // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) 
     Core.split(complexI2, planes); // planes[0] = Re(DFT(I), planes[1] = 
     // Im(DFT(I)) 

     Mat mag = new Mat(planes.get(0).size(), planes.get(0).type()); 

     Core.magnitude(planes.get(0), planes.get(1), mag);// planes[0] 
     // = 
     // magnitude 

     Mat magI = mag; 
     Mat magI2 = new Mat(magI.size(), magI.type()); 
     Mat magI3 = new Mat(magI.size(), magI.type()); 
     Mat magI4 = new Mat(magI.size(), magI.type()); 
     Mat magI5 = new Mat(magI.size(), magI.type()); 

     Core.add(magI, Mat.ones(padded.rows(), padded.cols(), CvType.CV_64FC1), 
       magI2); // switch to logarithmic scale 
     Core.log(magI2, magI3); 

     Mat crop = new Mat(magI3, new Rect(0, 0, magI3.cols() & -2, 
       magI3.rows() & -2)); 

     magI4 = crop.clone(); 

     // rearrange the quadrants of Fourier image so that the origin is at the 
     // image center 
     int cx = magI4.cols()/2; 
     int cy = magI4.rows()/2; 

     Rect q0Rect = new Rect(0, 0, cx, cy); 
     Rect q1Rect = new Rect(cx, 0, cx, cy); 
     Rect q2Rect = new Rect(0, cy, cx, cy); 
     Rect q3Rect = new Rect(cx, cy, cx, cy); 

     Mat q0 = new Mat(magI4, q0Rect); // Top-Left - Create a ROI per quadrant 
     Mat q1 = new Mat(magI4, q1Rect); // Top-Right 
     Mat q2 = new Mat(magI4, q2Rect); // Bottom-Left 
     Mat q3 = new Mat(magI4, q3Rect); // Bottom-Right 

     Mat tmp = new Mat(); // swap quadrants (Top-Left with Bottom-Right) 
     q0.copyTo(tmp); 
     q3.copyTo(q0); 
     tmp.copyTo(q3); 

     q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) 
     q2.copyTo(q1); 
     tmp.copyTo(q2); 

     Core.normalize(magI4, magI5, 0, 255, Core.NORM_MINMAX); 

     Mat realResult = new Mat(magI5.size(), CvType.CV_8UC1); 

     magI5.convertTo(realResult, CvType.CV_8UC1); 

     return realResult; 
    } 

    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { 
     //System.out.print("teste"); 
     Mat matGray = inputFrame.gray(); 
     return getDFT(inputFrame.gray()); 
    } 
} 

Но проблема, я все еще получаю эту ошибку:

07-03 22:46:46.205 13700-28322/ch.hepia.lsn.opencv_native_androidstudio A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x10 in tid 28322 (Thread-9802)

который я думаю, что это из-за какой-то обработки ограничения, так как я просто скопировал код, который работал с другими пользователями, используя общие изображения.

Мои вопросы:

  • Как я могу проверить, если эта ошибка из-за ограничение обработки?

  • Есть ли другой способ реализовать его с помощью OpenCV или другой библиотеки?

Спасибо.

+0

Это происходит кратковременно или через какое-то время, как в этом вопросе: http://stackoverflow.com/questions/33052806/error-fatal-signal-11-sigsegv-code-1-when-passing -mat-object-from-java-to, а второй вопрос: работает ли ваш код без DFT? Если это ошибка, то в DFT. Если он не работает даже без DFT, тогда ошибка находится где-то в другом месте. – Lubo

+0

Приложение похоже на крах сразу, но если я посмотрю на журнал, я вижу, что он работает как 3 ~ 5 раз, а затем сбой. Он работал без DFT, если я делаю вывод только в рамке серого цвета, он отлично работает. –

+0

Тогда проблема заключается в освобождении ресурсов. Вы создаете много матриц, но вы не освобождаете память. Даже java не выпускает его для вас, потому что он не знает о выделенных ресурсах в native lib. Поэтому обязательно вызовите метод relase перед возвратом на каждый мат, который вы создали, за исключением того, который вы возвращаете. – Lubo

ответ

1

Я портировал код, который я изначально разместил в Android Studio (от Eclipse) и OpenCV 3.1.0. Я думаю, что есть проблема с функцией Core.add() в этой версии openCV - см. Сообщение here

Я использовал, как предложил Core.addWeighted(), и я мог бы хотя бы получить dft для отображения, но не очень задолго до того, как у него закончилась память. Я думаю, что функции, подобные split, также используют add(), поэтому я думаю, что нам нужно искать исправление для этой проблемы в openCV.

Код, который я опубликовал, может быть улучшен, чтобы лучше использовать ресурсы, например, сохранять статические распределения ключевых массивов, не продолжать вызывать размер(), но снова удерживать это статически, уменьшить количество выделенных матов и т. Д. . Кроме того, можно уменьшить размер захваченного изображения в качестве Маты могут получить огромный на более современных телефонов (у меня есть Samsung S6), поэтому использование

mOpenCvCameraView.setMaxFrameSize(176, 152); 

или любой другой размер более управляемым.

Если вы хотите уменьшить количество кадров, то сохраняйте статический счетчик, который вы увеличиваете при каждом захвате кадра, и вызываете только getDFT(), если счетчик делится на 5, 10 или любой другой, чтобы обрабатывать только эти 5 , 10-й кадр и т. Д.

+0

Hi Timegalore, Прежде всего, спасибо за ответ. Использование addWeighted решило проблему, но в результате моя функция дает мне черный кадр. Мне интересно, возвращаю ли я неправильную матрицу в функции getDFT, в этом случае я возвращаюсь: realResult. –

+0

Как вы делаете addWeighted? Я использовал: Core.addWeighted (magI, 1, Mat.ones (padded.rows(), padded.cols(), CvType.CV_64FC1), 1, 0, magI2); – timegalore

+0

Я с теми же параметрами, в середине кода я получил эту ошибку: http://pastebin.com/G0fF5Hah Единственное, что я добавил иначе, чем core.addWeighted был: mOpenCvCameraView.setMaxFrameSize (176, 152); Я также использую samsung s6. –

 Смежные вопросы

  • Нет связанных вопросов^_^