你好,我是android开发的新手,谁能帮我根据PreviewView上的矩形裁剪CameraX捕获的图像?
这是activity_main.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/frameRoot"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="@+id/viewOverlay_center"
android:background="@drawable/card_rectangle"
android:layout_width="270dp"
android:layout_height="400dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/ll_bottom"/>
<LinearLayout
android:id="@+id/ll_bottom"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/black"
android:gravity="center"
android:orientation="horizontal"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<ImageView
android:id="@+id/image_capture_button"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="?android:selectableItemBackground"
android:src="@drawable/shutter_camera" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
这是我的MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
viewBinding.imageCaptureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
capturePhoto();
}
});
}
private void capturePhoto(){
if (imageCapture == null) {
return;
}
String filename = "Card-" + mDateFormat.format(System.currentTimeMillis());
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "Card-" + mDateFormat.format(System.currentTimeMillis()));
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
imageCapture.takePicture(ContextCompat.getMainExecutor(this), new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(@NonNull ImageProxy imageProxy) {
super.onCaptureSuccess(imageProxy);
ImageInfo imageInfo = imageProxy.getImageInfo();
Bitmap image = rotateBitmapIfNeeded(imageProxyToBitmap(imageProxy),imageInfo);
saveBitmap(cropBitmapToCard(image,viewBinding.frameRoot,viewBinding.viewOverlayCenter),uri);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(MainActivity.this, DecoderActivity.class);
intent.putExtra("KEY", uri.toString());
startActivity(intent);
imageProxy.close();
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
super.onError(exception);
Log.e("MainActivity","Error on takePicture",exception);
}
});
}
private void startCamera() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
startCameraX(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
}, ContextCompat.getMainExecutor(this));
}
void startCameraX(@NonNull ProcessCameraProvider cameraProvider) {
cameraProvider.unbindAll();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
// preview use case
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(viewBinding.viewFinder.getSurfaceProvider());
// image capture use case
imageCapture = new ImageCapture.Builder()
.setTargetRotation(this.getWindowManager().getDefaultDisplay().getRotation())
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build();
// bind to lifecycle
cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview, imageCapture);
}
void saveBitmap(Bitmap target, Uri uri){
try {
OutputStream output = getContentResolver().openOutputStream(uri);
target.compress(Bitmap.CompressFormat.JPEG, 100, output);
}
catch (Exception e) {
Log.d("onBtnSavePng", e.toString()); // java.io.IOException: Operation not permitted
}
}
Bitmap cropBitmapToCard(Bitmap source,View frame, View cardPlaceHolder){
float scaleX = source.getWidth() / (float)frame.getWidth();
float scaleY = source.getHeight() / (float) frame.getHeight();
int x =(int)((cardPlaceHolder.getLeft()) * scaleX);
int y = (int)((cardPlaceHolder.getTop()) * scaleY);
Log.v("MainActivity-Crop","leftPos: " + cardPlaceHolder.getLeft() + " width: " + cardPlaceHolder.getWidth());
int width = (int)(cardPlaceHolder.getWidth() * scaleX);
int height = (int)(cardPlaceHolder.getHeight() * scaleY);
return Bitmap.createBitmap(source,x,y,width,height);
}
private Bitmap imageProxyToBitmap(ImageProxy image)
{
ImageProxy.PlaneProxy planeProxy = image.getPlanes()[0];
ByteBuffer buffer = planeProxy.getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
private Bitmap rotateBitmapIfNeeded(Bitmap source, ImageInfo info){
int angle = info.getRotationDegrees();
Matrix mat = new Matrix();
mat.postRotate(angle);
return Bitmap.createBitmap(source,0,0,source.getWidth(),source.getHeight(),mat,true);
}
}
这就是我的应用程序的样子(预览模式),我想提取矩形内位图的 ROI
我得到了这个,你可以看到我的裁剪仍然不正确。
y 轴似乎存在映射错误。
有人可以帮助我如何正确裁剪图像吗?因为我已经搜索和研究如何做到这一点,但仍然感到困惑并且不适合我