Android:如何使用CameraX裁剪图像?

7

我想使用CameraX拍照并从中心剪裁出一个25x25dp的正方形。据我所知,可以使用ImageCapture进行裁剪,但很遗憾,目前几乎没有类似的示例。

val imageCaptureConfig = ImageCaptureConfig.Builder().apply {
    setTargetAspectRatio(Rational(1, 1))
    setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
}.build()

val imageCapture = ImageCapture(imageCaptureConfig)
btn_take_photo.setOnClickListener {
    imageCapture.takePicture(
        object : ImageCapture.OnImageCapturedListener() {
            override fun onCaptureSuccess(image: ImageProxy?, rotationDegrees: Int) {
                super.onCaptureSuccess(image, rotationDegrees)

                // image manipulation here?
            }
        }
    )
}

你是否特别想使用CameraX来完成这个任务?如果不是,你可以使用Glide,并使用它的Transformations来实现。 - Arthur Attout
我也可以使用Glide。我认为CameraX似乎非常强大,可能有一些功能。 - KunBa
CameraX主要是与设备相机进行交互的API。它更多地涉及硬件相关的内容。图像处理并不是这个API的设计目的。 - Arthur Attout
有没有解决方案?我遇到了一些问题。 - R Rifa Fauzi Komara
请在此处检查我的答案 答案链接 - Wojuola Ayotola
显示剩余2条评论
4个回答

6
您可以使用此功能,在拍摄图像后对其进行裁剪:
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 is the best quality possibe
        return stream.toByteArray()
    }

使用一个父视图作为框架和一个子视图作为最终参考,裁剪一张图片。

  • bitmap:要裁剪的图片
  • frame:图片所在的位置
  • reference:用于裁剪图片的参考框架
  • return:已经裁剪好的图片

1
那是如果你已经有了一个Bitmap;通常情况下你不会有一个,而是会有一个Image(就像问题中一样);如果你已经有了一个Bitmap,你可以直接使用Bitmap.createBitmap来裁剪它,而不需要进行字节级别的处理。 - Adam Burley
它裁剪的x和宽度不正确,y和高度似乎没问题。 - Vishnuvardhan

5

您可以将图像转换为位图,然后进行裁剪。

Bitmap cropImage(Image image, int rotationDegree, int xOffset, int yOffset, int cropWidth, int cropHeight) {
    // 1 - Convert image to Bitmap
    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
    byte[] bytes = new byte[buffer.remaining()];
    buffer.get(bytes);
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

    // 2 - Rotate the Bitmap
    if(rotationDegree != 0) {
        Matrix rotationMatrix = new Matrix();
        rotationMatrix.postRotate(rotationDegree);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), rotationMatrix, true);
    }

    // 3 - Crop the Bitmap
    bitmap = Bitmap.createBitmap(bitmap, xOffset, yOffset, cropWidth, cropHeight);

    return bitmap;
}

当我使用这个函数时,这一行 BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 返回了 null。 - Sebastianor
如果无法解码图像,则 decodeByteArray 会返回 null,如此处所述:https://developer.android.com/reference/android/graphics/BitmapFactory#public-methods_1。您能验证您拥有适当的图像并且字节数组已经正确填充吗? - Anthony Garant
X和Y偏移量是相对于图像中心还是其他位置? - rdxdkr
1
如果您的图像是YUV_420_888格式(CameraX的默认格式),那么您将有3个平面,而您的代码仅访问第一个平面->您裁剪后的图像最多只能是单色的,假设您正确解释了Y平面数据。 - Adam Burley
代码按预期工作。大多数转换缺少从图像到位图的旋转部分。此外,裁剪部分可以受益于越界检查。旋转完成后,宽度和高度会交换,您可以在边框外进行裁剪,这将返回异常。 - Cornescu Cătălin

1
你可以从图像中手动获取飞机并进行裁剪:
private fun cropByteArray(array : ByteArray, cropRect: Rect): ByteArray {
    val croppedArray = ByteArray(cropRect.width()*cropRect.height())
    val imageWidth = 640
    var i = 0
    array.forEachIndexed { index, byte ->
        val x = index % imageWidth
        val y = index / imageWidth

        if (cropRect.left <= x && x < cropRect.right && cropRect.top <= y && y < cropRect.bottom) {
            croppedArray[i] = byte
            i++
        }
    }
    return croppedArray
}

......

val buffer = image.planes[0].buffer
val imageByteArray = buffer.toByteArray()
val data = cropByteArray(imageByteArray, cropRect)

0

测试通过。简单的居中裁剪位图函数。

fun Bitmap.toSquare(): Bitmap {
    val srcBmp = this
    if (srcBmp.width >= srcBmp.height) {
        return Bitmap.createBitmap(
            srcBmp,
            srcBmp.width / 2 - srcBmp.height / 2,
            0,
            srcBmp.height,
            srcBmp.height
        );
    } else {
        return Bitmap.createBitmap(
            srcBmp,
            0,
            srcBmp.getHeight() / 2 - srcBmp.width / 2,
            srcBmp.width,
            srcBmp.width
        );
    }
}

使用方法:

val squareBitmap = orgBitmap.toSquare()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接