2011-12-03 5 views
15

카메라 출력의 단일 프레임에 사용자 정의 필터를 적용하고 표시하려면 어떻게합니까? 내가 지금까지 시도했습니다 무엇카메라 출력에 사용자 정의 필터 적용

:

  • 그 이름이 "녹색"나는 실제로 단지 어떻게 든 값을 수정할 포함되어 있지만

    mCamera.setPreviewCallback(new CameraGreenFilter()); 
    
    public class CameraGreenFilter implements PreviewCallback { 
    
        @Override 
        public void onPreviewFrame(byte[] data, Camera camera) { 
         final int len = data.length; 
         for(int i=0; i<len; ++i){ 
          data[i] *= 2; 
         } 
        } 
    } 
    
    (이 경우, 색상이 조금 강화 될 것이다) . 긴 이야기 짧게, 그것은 작동하지 않습니다.

  • 바이트 배열 'data'는 카메라 출력의 복사본임을 알았습니다. 그러나 이것은 '실제'버퍼가 필요하기 때문에 실제로 도움이되지 않습니다.

  • OpenGL을 사용하여 구현할 수 있다고 들었습니다. 그것은 매우 복잡한 것처럼 들립니다.

더 쉬운 방법이 있습니까? 그렇지 않으면이 openGL-surfaceView 매핑은 어떻게 작동합니까?

답변

36

좋습니다. 몇 가지 방법이 있습니다. 그러나 성능에 심각한 문제가 있습니다. 카메라의 바이트 []는 YUV format이며, 표시하려면 일종의 RGB 형식으로 변환해야합니다. 이 변환은 상당히 비싼 작동이며 출력 fps를 크게 낮 춥니 다.

실제로 카메라 미리보기로 무엇을 할 것인가에 달려 있습니다. 가장 좋은 해결책은 콜백없이 카메라 미리보기를 그리고 카메라 미리보기에 영향을주기 때문입니다. 그것이 논쟁의 여지가있는 재능을 만드는 일반적인 방법입니다.

하지만 실제로 출력을 수동으로 표시해야하는 경우 몇 가지 방법이 있습니다. 당신의 예제는 여러 가지 이유로 작동하지 않습니다. 먼저 이미지를 전혀 표시하지 않습니다. 당신이 호출하는 경우 : 카메라가 모든 미리보기를 표시하지 않습니다

mCamera.setPreviewCallback(new CameraGreenFilter()); 
mCamera.setPreviewDisplay(null); 

보다, 당신은 수동으로 표시해야합니다. 그리고 onPreviewFrame 메서드에서 값 비싼 연산을 수행 할 수 없습니다. 데이터의 수명이 제한되어 있으므로 다음 프레임에서 덮어 쓰게됩니다. 한 가지 힌트는 setPreviewCallbackWithBuffer을 사용하십시오. 하나의 버퍼를 다시 사용하고 각 프레임에 새 메모리를 할당 할 필요가 없으므로 더 빠릅니다.

그래서 당신이 뭔가를 할 필요가 :

private byte[] cameraFrame; 
private byte[] buffer; 
@Override 
public void onPreviewFrame(byte[] data, Camera camera) { 
    cameraFrame = data; 
    addCallbackBuffer(data); //actually, addCallbackBuffer(buffer) has to be called once sowhere before you call mCamera.startPreview(); 
} 


private ByteOutputStream baos; 
private YuvImage yuvimage; 
private byte[] jdata; 
private Bitmap bmp; 
private Paint paint; 

@Override //from SurfaceView 
public void onDraw(Canvas canvas) { 
    baos = new ByteOutputStream(); 
    yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null); 

    yuvimage.compressToJpeg(new Rect(0, 0, width, height), 80, baos); //width and height of the screen 
    jdata = baos.toByteArray(); 

    bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length); 

    canvas.drawBitmap(bmp , 0, 0, paint); 
    invalidate(); //to call ondraw again 
} 

이 일을하려면, 당신은 클래스 생성자 또는 어딘가에 setWillNotDraw(false)를 호출해야합니다.

색상을 수정하려면 예를 들어 paint.setColorFilter(filter)을 적용 할 수 있습니다. 당신이 원한다면 나는 그 몇 가지 예를 게시 할 수 있습니다.

이렇게하면 작동하지만 성능은 낮아집니다 (8fps 미만). BitmapFactory.decodeByteArray가 느려집니다. 네이티브 코드와 android NDK를 사용하여 YUV에서 RGB로 데이터를 변환 할 수는 있지만 상당히 복잡합니다.

다른 옵션은 OpenGL ES를 사용하는 것입니다. 카메라 프레임을 텍스처로 바인딩하는 GLSurfaceView가 필요합니다 (GLSurfaceView에서는 Camera.previewCallback을 구현하므로 일반 표면과 같은 방식으로 onPreviewFrame을 사용합니다). 하지만 같은 문제가 있습니다. YUV 데이터를 변환해야합니다.YUV의 바이트 배열의 첫 번째 절반은 색상이없는 휘도 데이터이므로 미리보기 (회색 음영 이미지)의 휘도 데이터 만 빠르게 표시 할 수 있습니다. 그래서 당신은 배열의 첫 번째 절반을 복사 arraycopy를 사용하고,이 같은 질감을 결합보다 onPreviewFrame에 :

gl.glGenTextures(1, cameraTexture, 0); 
int tex = cameraTexture[0]; 
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex); 
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE, 
    this.prevX, this.prevY, 0, GL10.GL_LUMINANCE, 
    GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(this.cameraFrame)); //cameraFrame is the first half od byte[] from onPreviewFrame 

gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 

당신은 캔트 약 16 ~ 18 이런 식으로 FPS 당신은 몇 가지 필터를 만들기 위해 OpenGL을 사용 할 수 있습니다 . 원하는 경우 여기에 코드를 더 보낼 수 있지만 여기에 입력하는 데 너무 길어 ...

자세한 내용은 내 simillar question을 참조하십시오.하지만 좋은 해결책이 아닙니다.

+0

YUV 데이터를 표시 할 수 있도록 RGB 데이터로 변환해야하며 이는 약 8fps 정도입니다. 이렇게 높은 디스플레이 속도를 얻기 위해 안드로이드 프레임 워크는 무엇입니까 (필터 적용 안함)? 거의 20 fps를 얻기 위해 모든 것을 OpenGL ES에 배치하고 있다고 생각하십니까? :) – poitroae

+0

아마 그들은 안드로이드 API를 사용하지 않고있을 것입니다 :) 네이티브 코드 또는 그와 비슷한 것으로 작성되었을 것입니다 (단지 추측입니다 ...) 그러나 안드로이드는 오픈 소스이기 때문에 실제로 코드를 찾는 방법을 찾을 수 있습니다 작품 : –

+0

Jaa-c, 당신이 위의 코드를 사용하여 예제를 게시하는 것이 가능한지 궁금합니다 (OpenGL이 아님). 제대로 작동하려면 모두 함께 추가하는 방법을 알아낼 수 없으며 이전 질문 이었지만 Google에서이 사실을 알 수있는 정보는 많지 않습니다. 또는 이것을 구현하기 위해 어떤 수업을 할 지에 대한 간단한 자습서를 만들 수 있습니까? –

관련 문제