2012-02-12 18 views
8

Sto lavorando a un progetto di robotica utilizzando un telefono Android come processore principale e la fotocamera per rilevare il movimento. Ho ricevuto il Android binary package from OpenCV e l'ho installato correttamente. Posso acquisire immagini usando la fotocamera nativa OpenCV e visualizzarle sullo schermo. Sto avendo problemi usando la classe di sottrazione dello sfondo, però. Posso creare un nuovo oggetto BackgroundSubtractorMOG nel costruttore, ma quando cerco di eseguire il codice qui sotto, forza l'uscita ottengo l'errore "Solo immagini a 8 e 3 canali a 8 bit sono supportate in BackgroundSubtractorMOG" dal codice nativo. Ho provato a cambiare Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA in Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB, e quindi non forza forzare la chiusura, ma tutto quello che ottengo è una schermata nera. Sono abbastanza sicuro che bmp è ancora nullo con FRAME_RGB, perché lo schermo rimane nero, e il contatore fps che stavo disegnando subito dopo la bitmap (rimosso dal codice postato di seguito per chiarezza e come passaggio per la risoluzione dei problemi) non viene visualizzato.OpenCV Android Background Sottrazione

Abbiamo esaminato il codice OpenCV C++ per questa funzione (line 388 here), e l'errore di tipo di immagine si verifica se il tipo di immagine non è CV_8UC1 o CV_8UC3, quindi provato usando l'CvType.CV_8UC3 java invece di Highgui. CV_CAP_ANDROID_COLOR_FRAME_RGBA in capture.retrieve(), ma forza chiusa e ho ottenuto un errore "Formato frame di output non supportato".

Immagino di avere appena avuto un problema di conversione di tipo, ma non riesco a capire per la vita di me dove i tipi di immagini specifiche di Android di OpenCV si adattano ai loro normali tipi di immagini documentati. Qualsiasi aiuto sarebbe apprezzato.

Le variabili:

private SurfaceHolder mHolder; 
private VideoCapture mCamera; 
private Mat mRgba; 
private Mat mFGMask; 
private BackgroundSubtractorMOG mBGSub; 

corsa di mia SurfaceView() funzione:

public void run() {  
    Bitmap bmp = null; 

    synchronized (this) { 
     if (mCamera == null) 
      break; 

     if (!mCamera.grab()) { 
      Log.e(TAG, "mCamera.grab() failed"); 
      break; 
     } 

     processFrame(mCamera); 
     bmp = Bitmap.createBitmap(mFGMask.cols(), mFGMask.rows(), Bitmap.Config.ARGB_8888); 
     Utils.matToBitmap(mFGMask, bmp); 
    } 

    if (bmp != null) { 
     Canvas canvas = mHolder.lockCanvas(); 
     if (canvas != null) { 
      canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth())/2, (canvas.getHeight() - bmp.getHeight())/2, null); 
      mHolder.unlockCanvasAndPost(canvas); 
     } 
     bmp.recycle(); 
    } 
} 

La funzione processFrame() fa riferimento nel run():

protected void processFrame(VideoCapture capture) { 
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); 
    mBGSub.apply(mRgba, mFGMask); 
} 

Edit:

La soluzione che ha finito per lavorare:

protected void processFrame(VideoCapture capture) { 
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB); 
    //GREY_FRAME also works and exhibits better performance 
    //capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_GREY_FRAME); 
    mBGSub.apply(mRgba, mFGMask, 0.1); 
    Imgproc.cvtColor(mFGMask, mRgba, Imgproc.COLOR_GRAY2BGRA, 4); 
} 

risposta

3

Hai provato a usare cvtColor con CV_RGB2RGBA e CV_RGBA2RGB. Quindi, magari prova a convertire il frame RGBA in RGB, quindi fai la sottrazione dello sfondo. Qualcosa di simile a questo:

protected void processFrame(VideoCapture capture) { 
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); 
    Mat rgb; 
    Imgproc.cvtColor(mRgba, rgb, Imgproc.COLOR_RGBA2RGB); 
    mBGSub.apply(rgb, mFGMask); 
} 

EDIT: Si potrebbe controllare l'unità di test OpenCV per BackgroundSubtractorMOG trova here. Tuttavia, il test ha fail("Not yet implemented"); nel caso di test principale.

Non sono sicuro se ciò significa che il test non è completo o il supporto per BackgroundSubtractorMOG non è implementato. Potresti provare a eseguire il codice contenuto in questo unit test per vedere se funziona effettivamente.

Inoltre, l'esempio di C++ segment_objects.cpp potrebbe essere utile come esempio di utilizzo.

Spero che questo aiuti! :)

+0

Questo mi avvicina. La sintassi esatta per la versione java è: 'Imgproc.cvtColor (mRgba, rgb, Imgproc.COLOR_RGBA2RGB);' per il primo convert, e il secondo non è necessario (non sto facendo nulla con l'immagine grezza dopo la sottrazione). Ora, ottengo uno schermo nero (nessuna forza chiusa). Se cambio il formato bitmap in Bitmap.Config.RGB_565, ottengo il mio contatore FPS, quindi so che è in esecuzione, ma è ancora uno schermo nero. Grazie per avermi fatto un po 'più avanti, però. – RedPeasant

+0

@RedPeasant Grazie per le informazioni sulla sintassi corretta. Ho aggiornato la mia risposta per includerla. La fotocamera è in movimento e lo schermo è ancora nero? – mevatron

+0

@RedPeasant Ho aggiornato la mia risposta per includere ulteriori informazioni su 'BackgroundSubtractorMOG'. – mevatron

1

Grazie ragazzi ragazzi! E per i futuri spettatori che visitano questa pagina, potrebbe essere necessario modificare questa conoscenza per far funzionare le cose. In SDK v2.4.4 l'ho applicato nel metodo onCameraFrame. Ricorda che il metodo riprende un frame di input dalla videocamera.Usa l'input e restituisci il frame che deve essere visualizzato sullo schermo del tuo dispositivo Android. Ecco un esempio:

//Assume appropriate imports  
private BackgroundSubtractorMOG sub = new BackgroundSubtractorMOG(3, 4, 0.8); 
private Mat mGray = new Mat(); 
private Mat mRgb = new Mat(); 
private Mat mFGMask = new Mat(); 

public Mat onCameraFrame(CvCameraViewFrame inputFrame) { 
    mGray = inputFrame.gray(); //I chose the gray frame because it should require less resources to process 
    Imgproc.cvtColor(mGray, mRgb, Imgproc.COLOR_GRAY2RGB); //the apply function will throw the above error if you don't feed it an RGB image 
    sub.apply(mRgb, mFGMask, learningRate); //apply() exports a gray image by definition 

    return mFGMask; 
} 

di ottenere attraverso il mio punto circa l'immagine grigia che viene fuori da applicare(), se si voleva fare una versione RGBA, potrebbe essere necessario utilizzare un cvtcolor dopo la chiamata ad applicare ():

private Mat mRgba = new Mat(); 

public Mat onCameraFrame(CvCameraViewFrame inputFrame) { 
    mRgba = inputFrame.rgba(); 
    Imgproc.cvtColor(mRgba, mRgb, Imgproc.COLOR_RGBA2RGB); //the apply function will throw the above error if you don't feed it an RGB image 
    sub.apply(mRgb, mFGMask, learningRate); //apply() exports a gray image by definition 
    Imgproc.cvtColor(mFGMask, mRgba, Imgproc.COLOR_GRAY2RGBA); 

    return mRgba; 
} 
+0

Non sono sicuro su come selezionare i valori per il costruttore BackgroundSubtractorMOG. Li ho visti su un altro thread. Assicurati di giocare con i valori per adattarsi meglio alla tua applicazione. – austin

0

anche con le più recenti OpenCV è necessario inizializzare con:

BackgroundSubtractorMOG2 private Sub = Video.createBackgroundSubtractorMOG2();