2013-06-10 4 views
19

고정 너비와 높이를 가진 TextureView가 있으며 그 안에 카메라 미리보기를 표시하고 싶습니다. 카메라 미리보기를 내 TextureView 내부로 뻗어 있지 않도록 잘라야합니다. 자르기를하는 방법? OpenGL을 사용해야하는 경우 Surface Texture를 OpenGL에 연결하는 방법과 OpenGL로 자르는 방법은 무엇입니까?TextureView 자르기 카메라 미리보기

public class MyActivity extends Activity implements TextureView.SurfaceTextureListener 
{ 

    private Camera mCamera; 
    private TextureView mTextureView; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_options); 

    mTextureView = (TextureView) findViewById(R.id.camera_preview); 
    mTextureView.setSurfaceTextureListener(this); 
} 

@Override 
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 
    mCamera = Camera.open(); 

    try 
    { 
     mCamera.setPreviewTexture(surface); 
     mCamera.startPreview(); 
    } catch (IOException ioe) { 
     // Something bad happened 
    } 
} 

@Override 
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 
    mCamera.stopPreview(); 
    mCamera.release(); 
    return true; 
} 

@Override 
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 
} 

@Override 
public void onSurfaceTextureUpdated(SurfaceTexture surface) 
{ 
    // Invoked every time there's a new Camera preview frame 
} 
} 

또한, 제대로 미리보기를 수행 한 후, 나는 실시간으로 자른 이미지의 중심에있는 픽셀을 읽을 수 있어야합니다.

+0

작은 미리보기로 시도해 볼 수 있을지 잘 모르겠다. 처음에는 기본 미리보기 크기가 큰 카메라를 제공합니다. – Amrendra

+1

미리보기 크기에 대해 알고 있습니다. 카메라 미리보기가 미리보기 크기와 다른 크기로 표시되므로보기에는 도움이되지 않습니다. –

+0

화면에서 조각을 시도 할 수 있습니다. – Amrendra

답변

2

byte[] dataonPreview()에서 조작 할 수 있습니다.

나는에 당신이 가지고있는 것 같아요 :

  • 크기를 조정/
    • Bitmap
    • 에서 자르기 스트레칭 조금을 할 비트 맵
    • 에 넣고에 Bitmap을 통과하여 SurfaceView

    이것은별로 좋은 방법은 아닙니다. 어쩌면 byte[]을 직접 조작 할 수도 있지만 NV21과 같은 그림 형식을 처리해야합니다.

  • 1

    @SatteliteSD의 응답이 가장 적합합니다. 모든 카메라는 HAL로 설정된 특정 미리보기 크기 만 지원합니다. 따라서 사용 가능한 미리보기 크기가 요구 사항을 만족하지 못하면 onPreview에서 데이터를 추출해야합니다.

    0

    카메라의 미리보기 이미지를 실시간으로 조작하기 위해 안드로이드 용 OpenCV가 완벽하게 적용됩니다. 여기에 필요한 모든 샘플을보실 수 있습니다 : http://opencv.org/platforms/android/opencv4android-samples.html, 그리고 알다시피, 실시간으로 잘 작동합니다.

    면책 조항 : C++/opencv/ndk로 실험 한 방법에 따라 android에서 opencv lib를 설정하는 것은 꽤 어려울 수 있습니다. 모든 경우 opencv 코드를 작성하는 것은 결코 쉬운 일이 아니지만 다른 한편으로는 매우 강력한 라이브러리입니다.

    +0

    나는 JavaCameraView를 직접보고 있었고 yuv를하고있는 것으로 보인다. -> rgb 네이티브 코드에서 하나의 GPU보다는 CPU로 변환 ... 나는 이것이 카메라 프레임 (지연과 가난한 fps)에 전달되는 카메라 프레임의 실제 감속으로 이어지고 있다고 생각합니다 – Sam

    11

    가로 세로 비율을 계산하고 크기 조정 행렬을 생성하여 TextureView에 적용하면됩니다. 표면의 종횡비와 미리보기 이미지의 종횡비에 따라 미리보기 이미지는 위쪽과 아래쪽 또는 왼쪽과 오른쪽에서 잘립니다. 내가 발견 한 또 다른 해결책은 전에 카메라를 열면 SurfaceTexture를 사용할 수 있다는 것입니다. 미리보기는 이미 자동으로 조정됩니다. 그냥 mCamera = Camera.open(); SurfaceTextureListener를 설정 한 후 onCreate 함수에 전달하십시오. 이것은 N4에서 나를 위해 일했습니다. 이 솔루션을 사용하면 세로에서 가로로 회전 할 때 문제가 발생할 수 있습니다. 세로 및 가로 지원이 필요한 경우, 척도 매트릭스로 솔루션을 가져옵니다!

    private void initPreview(SurfaceTexture surface, int width, int height) { 
        try { 
         camera.setPreviewTexture(surface); 
        } catch (Throwable t) { 
         Log.e("CameraManager", "Exception in setPreviewTexture()", t); 
        } 
    
        Camera.Parameters parameters = camera.getParameters(); 
        previewSize = parameters.getSupportedPreviewSizes().get(0); 
    
        float ratioSurface = width > height ? (float) width/height : (float) height/width; 
        float ratioPreview = (float) previewSize.width/previewSize.height; 
    
        int scaledHeight = 0; 
        int scaledWidth = 0; 
        float scaleX = 1f; 
        float scaleY = 1f; 
    
        boolean isPortrait = false; 
    
        if (previewSize != null) { 
         parameters.setPreviewSize(previewSize.width, previewSize.height); 
         if (display.getRotation() == Surface.ROTATION_0 || display.getRotation() == Surface.ROTATION_180) { 
          camera.setDisplayOrientation(display.getRotation() == Surface.ROTATION_0 ? 90 : 270); 
          isPortrait = true; 
         } else if (display.getRotation() == Surface.ROTATION_90 || display.getRotation() == Surface.ROTATION_270) { 
          camera.setDisplayOrientation(display.getRotation() == Surface.ROTATION_90 ? 0 : 180); 
          isPortrait = false; 
         } 
         if (isPortrait && ratioPreview > ratioSurface) { 
          scaledWidth = width; 
          scaledHeight = (int) (((float) previewSize.width/previewSize.height) * width); 
          scaleX = 1f; 
          scaleY = (float) scaledHeight/height; 
         } else if (isPortrait && ratioPreview < ratioSurface) { 
          scaledWidth = (int) (height/((float) previewSize.width/previewSize.height)); 
          scaledHeight = height; 
          scaleX = (float) scaledWidth/width; 
          scaleY = 1f; 
         } else if (!isPortrait && ratioPreview < ratioSurface) { 
          scaledWidth = width; 
          scaledHeight = (int) (width/((float) previewSize.width/previewSize.height)); 
          scaleX = 1f; 
          scaleY = (float) scaledHeight/height; 
         } else if (!isPortrait && ratioPreview > ratioSurface) { 
          scaledWidth = (int) (((float) previewSize.width/previewSize.height) * width); 
          scaledHeight = height; 
          scaleX = (float) scaledWidth/width; 
          scaleY = 1f; 
         }   
         camera.setParameters(parameters); 
        } 
    
        // calculate transformation matrix 
        Matrix matrix = new Matrix(); 
    
        matrix.setScale(scaleX, scaleY); 
        textureView.setTransform(matrix); 
    } 
    
    +0

    나는 그것을 얻을 수 없습니다 미리보기를 자르십시오. TextureView에서 미리보기를자를 수 있습니까? –

    +0

    그건 저를 위해 일하고 있습니다. 기본적으로 자르기가 아니라 크기 조정입니다. TextureView의 비율과 카메라 미리보기의 비율이 동일하지 않더라도 카메라 미리보기는 항상 TextureView 내부에 장착됩니다. 변형 행렬을 사용하면 왜곡을 보정하도록 스케일링을 설정할 수 있습니다. – Romanski

    29

    @Romanski의 초기 해결 방법은 잘 작동하지만 자르기와 함께 확장됩니다. 크기에 맞게 조정해야하는 경우 다음 솔루션을 사용하십시오. 표면 뷰가 변경 될 때마다 updateTextureMatrix를 호출하십시오. 즉, onSurfaceTextureAvailable 및 onSurfaceTextureSizeChanged 메소드에서 호출하십시오. 또한이 솔루션은 활동이 구성 변경 사항을 무시한다는 점에 유의하십시오 (예 :안드로이드 : configChanges = "오리엔테이션 | 화면 크기 | keyboardHidden"또는 그런 일) :

    또한
    private void updateTextureMatrix(int width, int height) 
    { 
        boolean isPortrait = false; 
    
        Display display = getWindowManager().getDefaultDisplay(); 
        if (display.getRotation() == Surface.ROTATION_0 || display.getRotation() == Surface.ROTATION_180) isPortrait = true; 
        else if (display.getRotation() == Surface.ROTATION_90 || display.getRotation() == Surface.ROTATION_270) isPortrait = false; 
    
        int previewWidth = orgPreviewWidth; 
        int previewHeight = orgPreviewHeight; 
    
        if (isPortrait) 
        { 
         previewWidth = orgPreviewHeight; 
         previewHeight = orgPreviewWidth; 
        } 
    
        float ratioSurface = (float) width/height; 
        float ratioPreview = (float) previewWidth/previewHeight; 
    
        float scaleX; 
        float scaleY; 
    
        if (ratioSurface > ratioPreview) 
        { 
         scaleX = (float) height/previewHeight; 
         scaleY = 1; 
        } 
        else 
        { 
         scaleX = 1; 
         scaleY = (float) width/previewWidth; 
        } 
    
        Matrix matrix = new Matrix(); 
    
        matrix.setScale(scaleX, scaleY); 
        textureView.setTransform(matrix); 
    
        float scaledWidth = width * scaleX; 
        float scaledHeight = height * scaleY; 
    
        float dx = (width - scaledWidth)/2; 
        float dy = (height - scaledHeight)/2; 
        textureView.setTranslationX(dx); 
        textureView.setTranslationY(dy); 
    } 
    

    당신이 필요로하는 다음과 같은 필드 :

    private int orgPreviewWidth; 
    private int orgPreviewHeight; 
    

    이 onSurfaceTextureAvailable mathod에 초기화 updateTextureMatrix를 호출하기 전에 :

    Camera.Parameters parameters = camera.getParameters(); 
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 
    
    Pair<Integer, Integer> size = getMaxSize(parameters.getSupportedPreviewSizes()); 
    parameters.setPreviewSize(size.first, size.second); 
    
    orgPreviewWidth = size.first; 
    orgPreviewHeight = size.second; 
    
    camera.setParameters(parameters); 
    

    getMaxSize 방법 :

    private static Pair<Integer, Integer> getMaxSize(List<Camera.Size> list) 
    { 
        int width = 0; 
        int height = 0; 
    
        for (Camera.Size size : list) { 
         if (size.width * size.height > width * height) 
         { 
          width = size.width; 
          height = size.height; 
         } 
        } 
    
        return new Pair<Integer, Integer>(width, height); 
    } 
    

    그리고 마지막으로 카메라 회전을 수정해야합니다. 그래서 활동의 onConfigurationChanged 방법 setCameraDisplayOrientation 메소드를 호출 (도 onSurfaceTextureAvailable 방법에서 초기 호출 할) : 난 그냥 픽셀 화를받지 않고 실제 입력의 2 배와 미리보기를 표시하는 데 필요한 작업 응용 프로그램을 만들었습니다

    public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) 
    { 
        Camera.CameraInfo info = new Camera.CameraInfo(); 
        Camera.getCameraInfo(cameraId, info); 
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); 
        int degrees = 0; 
        switch (rotation) 
        { 
         case Surface.ROTATION_0: 
          degrees = 0; 
          break; 
         case Surface.ROTATION_90: 
          degrees = 90; 
          break; 
         case Surface.ROTATION_180: 
          degrees = 180; 
          break; 
         case Surface.ROTATION_270: 
          degrees = 270; 
          break; 
        } 
    
        int result; 
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
        { 
         result = (info.orientation + degrees) % 360; 
         result = (360 - result) % 360; // compensate the mirror 
        } 
        else 
        { // back-facing 
         result = (info.orientation - degrees + 360) % 360; 
        } 
        camera.setDisplayOrientation(result); 
    
        Camera.Parameters params = camera.getParameters(); 
        params.setRotation(result); 
        camera.setParameters(params); 
    } 
    
    +0

    이 사람에게 최신 소식을 전하십시오! 이 루슬란에게 고마워. 필자는 약 1 주일 동안 표면보기, 서프 어테스트 텍스쳐 및 기타 백만 가지를 사용하여이를 공격하려고 시도했습니다. 스케일링 매트릭스를 설정할 수있는 뷰가 있어야한다는 것을 알았지 만 찾을 수 없었습니다. 이것은 완벽 해. 거기에있는 카메라 미리보기 자르기에 대한 다른 많은 질문에서이 대답에 대한 링크가 있어야한다고 생각합니다. – Sam

    +0

    편집 : Romanski가 해결 한 것 같은이 코드에 약간의 논리 문제가 있습니다. 문제가있는 곳에서 일하면이 대답을 업데이트하십시오. – Sam

    +0

    SurfaceTexture 및 GLES를 사용하여이 작업을 직접 수행하는 예는 " Grafika (https://github.com/google/grafika)의 "카메라에서 얻은 텍스쳐"활동. "확대/축소"액션은 텍스처 좌표를 조작하여 중앙 자르기 및 크기 조절을 수행합니다. TextureView는 비슷한 것을하고 있습니다. TextureView의 장점은 사용하기가 훨씬 쉽다는 것입니다. "원시 GLES"접근 방식은 훨씬 더 복잡하지만 훨씬 더 유연합니다. – fadden

    1

    을 보기. 예. 640x360 TextureView에서 1280x720 실시간 미리보기의 가운데 부분을 표시해야했습니다.

    내가 한 일은 다음과 같습니다.

    설정 내가 필요로 무엇의 2 배 해상도 카메라 미리보기 :

    params.setPreviewSize(1280, 720); 
    

    그리고 그에 따라 텍스처보기를 확장은 :

    this.captureView.setScaleX(2f); 
    this.captureView.setScaleY(2f); 
    

    이 소형 장치에 어떤 딸꾹질없이 실행됩니다.

    +0

    고맙습니다. 나를 구 해주십시오. – YeeKhin