Android 在显示之前,在CameraX分析中操纵(裁剪和缩放)帧图像

Android 在显示之前,在CameraX分析中操纵(裁剪和缩放)帧图像,android,image,processing,crop,android-camerax,Android,Image,Processing,Crop,Android Camerax,我有一个CameraX的实现,希望在将每个帧交给textureview显示之前对其进行裁剪和缩放 <TextureView android:id="@+id/view_finder" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintTop_toTopOf=&qu

我有一个CameraX的实现,希望在将每个帧交给textureview显示之前对其进行裁剪和缩放

<TextureView
    android:id="@+id/view_finder"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" /> 

我想在analizer中为每一帧裁剪它的原因是裁剪窗口可以从外部更改-在开始(0,0100100)和几秒钟后(例如200140300240).

您能描述一下您的场景以帮助我理解为什么要裁剪矩形像这样移动吗?@Xi张熹 最后一位来自亚洲的开发者:)我知道你们在这方面很强。我想做的是:第1步:使用摄像头的livestream进行人脸检测=>获取嘴巴的位置和宽度(x、y、宽度、高度),并且只在“实时”中预览,感谢您的信任投票。:)然而,在这种情况下,转换输出并不是件小事。您需要Matrix#SetPolytopoloy之类的东西来从源匹配到目标。在本例中,源是嘴区域,目标是整个预览曲面。注意还有其他需要考虑的事情。请看一下PreviewView的源代码,特别是这一部分:我看到的是SetPolytoply做了一些倾斜?若你们去MLKit,在第节你们会看到MLKit也给了我一个边界框。因此,我不需要在第一步中进行反视图,只需要缩放/缩放+裁剪。但是我不知道从哪里开始。你不需要倾斜,但需要旋转,这就是为什么setpolytoply()很有用的原因。转换预览是一件复杂的事情。即使你熟悉这个主题,也需要做大量的工作。首先,我建议您看看我上面发布的源代码。CameraX将来可能会添加一些功能来帮助解决这个问题,但目前还没有ETA。
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textureView = findViewById(R.id.view_finder);
        startCamera(); //start camera if permission has been granted by user
}

 private void startCamera() {

    CameraX.unbindAll();

    Rational aspectRatio = new Rational (textureView.getWidth(), textureView.getHeight());
    Size screen = new Size(textureView.getWidth(), textureView.getHeight()); //size of the screen


    PreviewConfig pConfig = new PreviewConfig.Builder()
                                .setTargetAspectRatio(aspectRatio)
                                .setTargetResolution(screen)
                                .setLensFacing(CameraX.LensFacing.FRONT)
                                .build();
    Preview preview = new Preview(pConfig);

    preview.setOnPreviewOutputUpdateListener(
            new Preview.OnPreviewOutputUpdateListener() {
                @Override
                public void onUpdated(Preview.PreviewOutput output){
                    ViewGroup parent = (ViewGroup) textureView.getParent();
                    parent.removeView(textureView);
                    parent.addView(textureView, 0);

                    textureView.setSurfaceTexture(output.getSurfaceTexture());
                    updateTransform();
                }
            });

    ImageAnalysis imageAnalyzer = this.buildImageAnalysisUseCase(aspectRatio,screen);

    final Rect rect = new Rect();
    rect.top = 0;
    rect.bottom = 100;
    rect.right = 100;
    rect.left = 0;

    imageAnalyzer.setAnalyzer(new ImageAnalysis.Analyzer() {
        @Override
        public void analyze(ImageProxy image, int rotationDegrees) {
            Log.v("Analiiiize",rect.toString());
             image.setCropRect(rect); // here I hoped it will be cropped with a square of 100x100px in the top left corner and then displayed.. How could I achieve this here for each frame? 
            
            image.close();
        }
    });

    ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().setLensFacing(CameraX.LensFacing.FRONT).setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
            .setTargetRotation(getWindowManager().getDefaultDisplay().getRotation()).build();
    final ImageCapture imgCap = new ImageCapture(imageCaptureConfig);

    findViewById(R.id.imgCapture).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            File file = new File(Environment.getExternalStorageDirectory() + "/" + System.currentTimeMillis() + ".png");
            imgCap.takePicture(file, new ImageCapture.OnImageSavedListener() {
                @Override
                public void onImageSaved(@NonNull File file) {
                    String msg = "Pic captured at " + file.getAbsolutePath();
                    Toast.makeText(getBaseContext(), msg,Toast.LENGTH_LONG).show();
                }

                @Override
                public void onError(@NonNull ImageCapture.UseCaseError useCaseError, @NonNull String message, @Nullable Throwable cause) {
                    String msg = "Pic capture failed : " + message;
                    Toast.makeText(getBaseContext(), msg,Toast.LENGTH_LONG).show();
                    if(cause != null){
                        cause.printStackTrace();
                    }
                }
            });
        }
    });

    //bind to lifecycle:
    //CameraX.bindToLifecycle((LifecycleOwner)this, preview, imgCap);
    CameraX.bindToLifecycle(this, preview, imageAnalyzer);

}

private ImageAnalysis buildImageAnalysisUseCase(Rational aspectRatio,Size screen)

{
    ImageAnalysisConfig aConfig = new ImageAnalysisConfig.Builder()
                                .setTargetAspectRatio(aspectRatio)
                                .setTargetResolution(screen)
                                .setLensFacing(CameraX.LensFacing.FRONT)
                                .build();
    ImageAnalysis analysis = new ImageAnalysis(aConfig);
    return  analysis;
}

private void updateTransform(){
    Log.d("Was", "Uödate!");
    Matrix mx = new Matrix();
    float w = textureView.getMeasuredWidth();
    float h = textureView.getMeasuredHeight();

    float cX = w / 2f;
    float cY = h / 2f;

    int rotationDgr;
    int rotation = (int)textureView.getRotation();

    switch(rotation){
        case Surface.ROTATION_0:
            rotationDgr = 0;
            break;
        case Surface.ROTATION_90:
            rotationDgr = 90;
            break;
        case Surface.ROTATION_180:
            rotationDgr = 180;
            break;
        case Surface.ROTATION_270:
            rotationDgr = 270;
            break;
        default:
            return;
    }

    mx.postRotate((float)rotationDgr, cX, cY);
    textureView.setTransform(mx);
}