2012-03-02 79 views
1

我正在Android上爲我的機器人制作線路跟隨者(學習Java/Android編程),目前我正面臨圖像處理問題:攝像頭預覽返回一個名爲YUV的圖像格式,I想要將其轉換爲閾值以便知道線路的位置,那麼該怎麼做?Android上的攝像頭預覽處理

截至目前我已經成功獲得東西,這是我絕對可以從相機的預覽中讀取數據,並通過某種奇蹟,即使知道,如果光強度超過或低於一定值時在一定的區域屏幕。我的目標是將機器人的路徑繪製在相機預覽的疊加層上,這在某種程度上也起作用,但問題在於YUV管理。

Galaxy Nexus Screenshot

正如你不僅可以看到暗區側身拉,但它也重演4倍和預覽圖像被拉伸,我無法弄清楚如何解決這些問題。

這裏的代碼的相關部分:

public void surfaceCreated(SurfaceHolder arg0) { 
    // TODO Auto-generated method stub 

    // camera setup 
    mCamera = Camera.open(); 

    Camera.Parameters parameters = mCamera.getParameters(); 
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes(); 
    for(int i=0; i<sizes.size(); i++) 
    { 
     Log.i("CS", i+" - width: "+sizes.get(i).width+" height: "+sizes.get(i).height+" size: "+(sizes.get(i).width*sizes.get(i).height)); 
    } 

    // change preview size 
    final Camera.Size cs = sizes.get(8); 
    parameters.setPreviewSize(cs.width, cs.height); 

    // initialize image data array 
    imgData = new int[cs.width*cs.height]; 

    // make picture gray scale 
    parameters.setColorEffect(Camera.Parameters.EFFECT_MONO); 
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 
    mCamera.setParameters(parameters); 

    // change display size 
    LayoutParams params = (LayoutParams) mSurfaceView.getLayoutParams(); 
    params.height = (int) (mSurfaceView.getWidth()*cs.height/cs.width); 
    mSurfaceView.setLayoutParams(params); 

    LayoutParams overlayParams = (LayoutParams) swOverlay.getLayoutParams(); 
    overlayParams.width = mSurfaceView.getWidth(); 
    overlayParams.height = mSurfaceView.getHeight(); 
    swOverlay.setLayoutParams(overlayParams); 

    try 
    { 
     mCamera.setPreviewDisplay(mSurfaceHolder); 
     mCamera.setDisplayOrientation(90); 
     mCamera.startPreview(); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
     mCamera.stopPreview(); 
     mCamera.release(); 
    } 

    // callback every time a new frame is available 
    mCamera.setPreviewCallback(new PreviewCallback() { 
     public void onPreviewFrame(byte[] data, Camera camera) 
     { 
      // create bitmap from camera preview 
      int pixel, pixVal, frameSize = cs.width*cs.height; 
      for(int i=0; i<frameSize; i++) 
      { 
       pixel = (0xff & ((int) data[i])) - 16; 
       if(pixel < threshold) 
       { 
        pixVal = 0; 
       } 
       else 
       { 
        pixVal = 1; 
       } 
       imgData[i] = pixVal; 
      } 

      int cp = imgData[(int) (cs.width*(0.5+(cs.height/2)))]; 

      //Log.i("CAMERA", "Center pixel RGB: "+cp); 
      debug.setText("Center pixel: "+cp); 

      // process preview image data 
      Paint paint = new Paint(); 
      paint.setColor(Color.YELLOW); 


      int start, finish, last; 
      start = finish = last = -1; 
      float x_ratio = mSurfaceView.getWidth()/cs.width; 
      float y_ratio = mSurfaceView.getHeight()/cs.height; 

      // display calculated path on overlay using canvas 
      Canvas overlayCanvas = overlayHolder.lockCanvas(); 
      overlayCanvas.drawColor(0, Mode.CLEAR); 

      // start by finding the tape from bottom of the screen  
      for(int y=cs.height; y>0; y--) 
      { 
       for(int x=0; x<cs.width; x++) 
       { 
        pixel = imgData[y*cs.height+x]; 

        if(pixel == 1 && last == 0 && start == -1) 
        { 
         start = x; 
        } 
        else if(pixel == 0 && last == 1 && finish == -1) 
        { 
         finish = x; 
         break; 
        } 
        last = pixel; 
       } 
       //overlayCanvas.drawLine(start*x_ratio, y*y_ratio, finish*x_ratio, y*y_ratio, paint); 
       //start = finish = last = -1; 
      } 
      overlayHolder.unlockCanvasAndPost(overlayCanvas); 
     } 
    }); 
} 

此代碼退出應用程序時,有時會產生一個錯誤,由於一些方法release之後被調用,這是至少我的問題。


UPDATE:

現在的定位問題是固定的(CCD傳感器方向),我仍然面臨重複的問題,這可能與我的YUV數據管理......

enter image description here

回答

2

你的面和攝像頭的管理看起來是正確的,但我會雙檢該相機實際接受預覽大小設置(有些相機實現拒絕一些設置默默地)

當你正在使用肖像模式,你必須記住,相機不會放棄有關prhone方向的放屁 - 它的座標原點是由CCD芯片決定的,並且總是在右上角並且掃描方向是從上到下,從右到左 - 與疊加畫布完全不同。 (但是如果你處於橫向模式,一切都是正確的;)) - 這是奇怪繪圖結果的來源

你的閾值處理有點幼稚,在現實生活中不是非常有用 - 我會建議自適應閾值處理。在我們javaocr項目(純java的,也有機器人演示)我們實現的高效sauvola二值化(見演示):

http://sourceforge.net/projects/javaocr/

性能二值化可以改進爲僅在單個圖像行(補丁歡迎)

工作

問題與圖像的紫外線部分很簡單 - 默認福曼是NV21,亮度至上 這只是字節流,而你並不需要在所有圖像的紫外線部分(看看演示以上)

+0

謝謝你CCD尖端,這確實是問題,現在重複這個怎麼樣肯定與我的YUV管理有關。一旦我得到它的工作,我會用動態閾值進行優化。 – Solenoid 2012-03-02 11:04:16

+0

...關於liminance問題的介紹 – 2012-03-02 12:40:46