CameraXのカメラプレビューで画像の長方形をトリミングする方法



How Crop Image Rectangle Camera Preview Camerax



解決:

おっしゃるように、cameraXで撮影した画像を切り抜く方法の例を次に示します。それが最善の方法かどうかはわかりません。他の解決策を知りたいと思っています。

camerax_version = '1.0.0-alpha07'



CameraFragment.java

cameraXを初期化します:



//プライベートPreviewViewpreviewViewを表示します; // CameraX private ProcessCameraProvider cameraProvider;プライベートListenableFuturecameraProviderFuture;プライベートCameraSelectorcameraSelector;プライベートエグゼキュータエグゼキュータ;プライベートImageCaptureimageCapture; @Override public void onCreate(@Nullable Bundle savedInstanceState){super.onCreate(savedInstanceState); cameraProviderFuture = ProcessCameraProvider.getInstance(getContext()); executor = ContextCompat.getMainExecutor(getContext()); cameraSelector = new CameraSelector.Builder()。requireLensFacing(LensFacing.BACK).build(); } @Override public void onViewCreated(@NonNull View view、@ Nullable Bundle savedInstanceState){super.onViewCreated(view、savedInstanceState); PreviewView = view.findViewById(R.id.preview); ImageButton btnCapture = view.findViewById(R.id.btn_capture); //ビューが適切にレイアウトされるのを待ちますpreviewView.post(()-> {// CameraXを初期化しますcameraProviderFuture.addListener(()-> {if(cameraProvider!= null)cameraProvider.unbindAll(); try {cameraProvider = cameraProviderFuture.get(); //カメラプレビューを表示するためのプレビューユースケースを設定しますプレビュープレビュー= new Preview.Builder()。setTargetAspectRatio(AspectRatio.RATIO_4_3).setTargetRotation(previewView.getDisplay()。getRotation())。build( ); Preview.setPreviewSurfaceProvider(previewView.getPreviewSurfaceProvider()); //ユーザーが写真を撮ることができるようにキャプチャのユースケースを設定しますimageCapture = new ImageCapture.Builder()。setCaptureMode(ImageCapture.CaptureMode.MINIMIZE_LATENCY).setTargetRotation(previewView.getDisplay ().getRotation())。setTargetAspectRatio(AspectRatio.RATIO_4_3).build(); //同じライフサイクル所有者を使用して宣言された構成をCameraXに適用しますcameraProvider.bindToLifecycle(this、cameraSelector、preview、imageCapture);} catch(ExecutionException | InterruptedException e){ e.printStackTrace(); }}、ContextCompat.getMainExecutor(getContext())); }); btnCapture.setOnClickListener(v-> {String format = 'yyyy-MM-dd-HH-mm-ss-SSS'; SimpleDateFormat fmt = new SimpleDateFormat(format、Locale.US); String date = fmt.format(System.currentTimeMillis ());ファイルfile = new File(getContext()。getCacheDir()、date + '。jpg'); imageCapture.takePicture(file、executor、imageSavedListener);}); }

写真が撮影されたら、写真のパスを通過するギャラリーフラグメントを開きます。

private ImageCapture.OnImageSavedCallback imageSavedListener = new ImageCapture.OnImageSavedCallback(){@ Override public void onImageSaved(@NonNull File photoFile){//新しいフラグメントとトランザクションを作成するFragment newFragment = new GalleryFragment(); FragmentTransactionトランザクション= getActivity()。getSupportFragmentManager()。beginTransaction(); //引数を設定しますBundleargs = new Bundle(); args.putString( 'KEY_PATH'、Uri.fromFile(photoFile).toString()); newFragment.setArguments(args); // fragment_containerビューにあるものをこのフラグメントに置き換えますtransaction.replace(R.id.fragment_container、newFragment、null); transaction.addToBackStack(null); //トランザクションをコミットしますtransaction.commit(); } @Override public void onError(int imageCaptureError、@ NonNull String message、@ Nullable Throwable cause){if(cause!= null){cause.printStackTrace(); }}};

現時点では、写真はトリミングされていません。cameraXで直接トリミングできるかどうかはわかりません。

GalleryFragment.java



フラグメントに渡された引数をロードします。

@Override public void onCreate(@Nullable Bundle savedInstanceState){super.onCreate(savedInstanceState);文字列パス= getArguments()。getString( 'KEY_PATH'); sourceUri = Uri.parse(path); }

ImageViewにグライドを使用してURIをロードし、トリミングします。

@Override public void onViewCreated(@NonNull View view、@ Nullable Bundle savedInstanceState){super.onViewCreated(view、savedInstanceState); //ビューを初期化しますImageViewimageView = view.findViewById(R.id.image_view);表示cropArea = view.findViewById(R.id.crop_area); //画像を表示しますGlide.with(this).load(sourceUri).listener(new RequestListener(){@ Override public boolean onLoadFailed(@Nullable GlideException e、Object model、Target target、boolean isFirstResource){return false;} @ public boolean onResourceReady(Drawable resource、Object model、Target target、DataSource dataSource、boolean isFirstResource){//元のビットマップを取得sourceBitmap =((BitmapDrawable)resource).getBitmap(); //トリミング領域に対応する新しいビットマップを作成しますint [] CropAreaXY = new int [2]; int [] placeHolderXY = new int [2]; Rect rect = new Rect(); imageView.getViewTreeObserver()。addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){@ Override public boolean onPreDraw (){try {imageView.getLocationOnScreen(placeHolderXY); CropArea.getLocationOnScreen(cropAreaXY); CropArea.getGlobalVisibleRect(rect); CroppedBitmap = Bitmap.createBitmap(sourceBitmap、cropAreaXY [0]、cropAreaXY [1] --placeHolderXY [1]、rect .width()、rect.height()); // croppedBiを保存しますgetActivity()。runOnUiThread(()-> imageView.setImageBitmap(croppedBitmap));が必要な場合はtmap trueを返します。 }最後に{imageView.getViewTreeObserver()。removeOnPreDrawListener(this); }}}); falseを返します。 }})。into(imageView); }

Fragment_camera.xml

  

Fragment_gallery.xml

   

私には解決策があります。この関数を使用して、画像をキャプチャした後に画像をトリミングします。

private fun CropImage(bitmap:Bitmap、frame:View、reference:View):ByteArray {val heightOriginal = frame.height val widthOriginal = frame.width val heightFrame = reference.height val widthFrame = reference.width val leftFrame = reference.left val topFrame = reference.top val heightReal = bitmap.height val widthReal = bitmap.width val widthFinal = widthFrame * widthReal / widthOriginal val heightFinal = heightFrame * heightReal / heightOriginal val leftFinal = leftFrame * widthReal / widthOriginal val topFinal = topFrame * heightReal / heightOriginal val bitmapFinal = Bitmap.createBitmap(bitmap、leftFinal、topFinal、widthFinal、heightFinal)val stream = ByteArrayOutputStream()bitmapFinal.compress(Bitmap.CompressFormat.JPEG、100、stream)// 100は最高品質の可能性のあるreturnstream.toByteArray() }

フレームのようなビューの親と最終参照のようなビューの子を参照して画像をトリミングします

  • ストップトリミングするビットマップ画像
  • ストップ画像が設定されているフレーム
  • ストップ画像をトリミングするための参照を取得するための参照フレーム
  • すでにトリミングされた画像を返す

この例を見ることができます:https://github.com/rrifafauzikomara/CustomCamera/tree/custom_camerax


camerax構成を使用してこれを行う簡単で簡単な方法を見つけました。

カメラのプレビューから、必要なプレビュー領域の長方形の高さと幅を取得します。

例えば

  

私の幅は350dp、高さは100dpです。

次に、ViewPortを使用して必要な領域を取得します

val viewPort = ViewPort.Builder(Rational(width、height)、rotation).build()//幅= 350、高さ= 100、回転= Surface.ROTATION_0 val useCaseGroup = UseCaseGroup.Builder()。addUseCase(preview)//プレビュー.addUseCase(imageAnalysis)// imageAnalysisを使用している場合.addUseCase(imageCapture).setViewPort(viewPort).build()

次に、CameraProviderのライフサイクルにバインドします

cameraProvider.bindToLifecycle(this、cameraSelector、useCaseGroup)

詳細については、このリンクCropRectを使用してください

以下のヘルプコメントが必要な場合は、実用的なソースコードを提供できます。

編集

ソースコードサンプルへのリンク