2011-06-23 46 views
6

我想製作一個使用相機的Android應用程序,並在預覽畫面上應用圖像處理過濾器。Android,Manupulate相機預覽畫面

package alex.filter; 

import java.io.IOException; 

import android.content.Context; 
import android.graphics.Canvas; 
import android.hardware.Camera; 
import android.hardware.Camera.PreviewCallback; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 

class Preview extends SurfaceView implements SurfaceHolder.Callback { 

    SurfaceHolder mHolder; 
    public Camera camera; 

    Preview(Context context) { 
     super(context); 
     mHolder = getHolder(); 
     mHolder.addCallback(this); 
     mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    } 

    public void surfaceCreated(SurfaceHolder holder) {   
     camera = Camera.open();   

     try { 
      camera.setPreviewDisplay(holder); 

      camera.setPreviewCallback(new PreviewCallback() { 
       public void onPreviewFrame(byte[] data, Camera arg1) {      
        for(int i = 0 ; i < data.length ; i ++){ 
         data[ i] = 0; // or some sirius filter 
        }                
        Preview.this.invalidate(); 
       } 
      }); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     } 

    public void surfaceDestroyed(SurfaceHolder holder) {   
     camera.stopPreview();   
     camera = null; 
    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {   
     Camera.Parameters parameters = camera.getParameters(); 
     parameters.setPreviewSize(w, h); 
     camera.setParameters(parameters); 
     camera.startPreview(); 
    } 

    @Override 
    public void draw(Canvas canvas) { 
     super.draw(canvas);   
    } 
} 

但是,無論我在onPreviewFrame方法中做什麼,我都看不到模擬器中的更改。

+1

+1,我也想知道是否可以直接操作預覽幀。 –

回答

1

那是因爲您在回調中獲得的預覽緩衝區只是預覽緩衝區的副本,因此您所做的任何修改都不會顯示,因爲您獲得的緩衝區是您的副本。在Android SDK中提到here

我不知道如何做到這一點,但我一直在給它如何去這件事,這裏的一些想法是什麼,我認爲應該做的事 -

  • 註冊預覽緩衝區
  • 禁用默認的預覽顯示
    • 如果不預覽顯示設置爲一個面,那麼你不應該得到任何顯示(但我不知道是否會工作 - 在某些人閱讀論壇無法回想起源)
    • 如果以上不工作,那麼我們將不得不隱藏視圖(我知道幾乎沒有有效的,但我想不出別的..)
  • 縮小預覽的幀率,讓我們不會被緩衝區淹沒
  • 現在要顯示我們的緩衝區,我們可以使用默認的位圖繪製功能或使用opengl來顯示緩衝區。但是到目前爲止我還沒有使用過,所以根本不知道它是否可行,對此有何想法?

UPDATE
重溫SDK文檔,我發現這個API - setPreviewTexture這個API可以讓我們 - 「從圖像流作爲OpenGL ES的紋理捕捉幀」。一旦你的圖像具有應用的紋理,你可以使用OpenGL來顯示你的幀。 (請看@Stephan發佈的答案,如何執行此操作。)

注 - setPreviewTexture可從API級別11開始提供! SDK Link

+0

我想我可以看到你要去的地方。有沒有辦法使用'SurfaceHolder'而不使用'SurfaceView'?如果我們使用它來獲取預覽數據和用於繪製已處理幀的優化'GLSurfaceView',也許我們可以獲得合理的幀速率。 –

+2

我想我可能已經破解了這個 - 再次通過相機文檔,並發現這個'setPreviewTexture'這使我們能夠「從圖像流中捕獲幀作爲OpenGL ES紋理」,我認爲這個OpenGL ES紋理是方式去。我們再次可以使用opengl來顯示幀,一旦我們完成了它。 [SurfaceTexture](http://developer.android.com/reference/android/graphics/Sur​​faceTexture.html) – bluefalcon

+0

不錯!這些東西來自API級別11,所以我沒有在文檔中看到它。我正在尋找一些適用於API級別8的內容,但請將其納入您的答案中,因爲如果沒有替代方案,我會獎勵您的賞金。 –

2

請參閱this link,我認爲它與您想要實現的類似。

+0

我想這回答了我使用opengl顯示緩衝區的問題。謝謝! +1 – bluefalcon

+0

如果它不起作用,請注意以下代碼行:'this.setEGLConfigChooser(8,8,8,16,0);' – Stephan

4

另一種選擇是使用OpenCV的框架,它有一個Android端口:

http://opencv.willowgarage.com/wiki/Android2.3.0

它是開源的Open計算機視覺項目的NDK端口,它會採取原始的預覽框和允許用OpenCV處理它們,然後在SurfaceView上顯示它們。因爲它操縱幀,它不會以相同的幀速率運行,而只是直接掛在硬件優化的預覽中,但由於它本身就是原生的,所以它做得非常好。

該版本中有一個OpenCV_Sample應用程序鏈接在上面,編譯成一個演示應用程序,可以做你想要的東西。它具有菜單選項以啓用反轉,模糊圖像或在預覽區域進行邊緣檢測。即使它不是你想要的,源代碼中有一些很好的示例可供學習。

+0

鏈接已損壞! – acrespo