如何在不转换为位图的情况下裁剪包含Y'(亮度)的byte []数组

VisionApp的Matt

编辑:解决了!见下文。我需要裁剪从Camera2的onImageAvailable侦听器获取的图像(YUV422888颜色空间)。我不希望或不需要将其转换为位图,因为它会极大地影响性能,而且我实际上对亮度而不是RGB信息(包含在图像的平面0中)感兴趣。我想出了以下解决方案:

  1. 获取包含在侦听器中的Camera2可用的Image对象的Plane 0中的Y'信息。
  2. 转换Y”平面成字节[]数组
  3. 将byte []数组转换为2d byte [] []数组以进行裁剪。
  4. 使用一些for循环在所需的左,右,上和下坐标处裁剪。
  5. 折叠2D字节[] []数组回1D byte []数组出来,含有裁剪亮度Y”的信息。

不幸的是,第4点产生了损坏的图像。我究竟做错了什么?

Camera2onImageAvailableListener中(请注意,尽管我正在计算位图,但是只能看到正在发生的事情,因为我对Bitmap / RGB数据不感兴趣):

               Image.Plane[] planes = image.getPlanes();
               ByteBuffer buffer = planes[0].getBuffer(); // Grab just the Y' Plane.
               buffer.rewind();
               byte[] data = new byte[buffer.capacity()];
               buffer.get(data);

               Bitmap bitmap = cropByteArray(data, image.getWidth(), image.getHeight()); // Just for preview/sanity check purposes. The bitmap is **corrupt**.

               runOnUiThread(new bitmapRunnable(bitmap) {
                   @Override
                   public void run() {
                       image_view_preview.setImageBitmap(this.bitmap);
                   }
               });

cropByteArray功能需要修复。它输出损坏的位图,并应输出类似于inout byte []数组,但仅包含裁剪区域:

    public Bitmap cropByteArray(byte[] in, int inw, int inh) {

    int l = 100; // left crop start
    int r = 400; // right crop end
    int t = 400; // top crop start
    int b = 700; // top crop end
    int outw = r-l;
    int outh = b-t;


    byte[][] in2d = new byte[inw][inh]; // input width and height are 1080 x 1920.
    byte[] out = new byte[outw*outh];
    int[] pixels = new int[outw*outh];

    i = 0;
    for(int col = 0; col < inw; col++) {
        for(int row = 0; row < inh; row++) {
            in2d[col][row] = in[i++];
        }
    }

    i = 0;
    for(int col = l; col < r; col++) {
        for(int row = t; row < b; row++) {
            //out[i++] = in2d[col][row]; // out is the desired output of the function, but for now we output a bitmap instead

            int grey = in2d[col][row] & 0xff;
            pixels[i++] = 0xFF000000 | (grey * 0x00010101);

        }
    }

    return Bitmap.createBitmap(pixels, inw, inh, Bitmap.Config.ARGB_8888);
}

编辑由于Eddy Talvala的建议而解决。以下代码将产生裁剪为所需坐标的Y'(ImageReader的亮度平面0)。裁剪的数据在输出字节数组中。生成位图只是为了确认。我还在下面附加了方便的YUVtoGrayscale()函数。

        Image.Plane[] planes    = image.getPlanes();
        ByteBuffer buffer       = planes[0].getBuffer();
        int stride              = planes[0].getRowStride();
        buffer.rewind();
        byte[] Y = new byte[buffer.capacity()];
        buffer.get(Y);

        int t=200; int l=600;
        int out_h = 600; int out_w = 600;
        byte[] out = new byte[out_w*out_h];

        int firstRowOffset = stride * t + l;
        for (int row = 0; row < out_h; row++) {
            buffer.position(firstRowOffset + row * stride);
            buffer.get(out, row * out_w, out_w);
        }
        Bitmap bitmap = YUVtoGrayscale(out, out_w, out_h);

这里是YUVtoGrayscale()

    public Bitmap YUVtoGrayscale(byte[] yuv, int width, int height) {

    int[] pixels = new int[yuv.length];

    for (int i = 0; i < yuv.length; i++) {
        int grey = yuv[i] & 0xff;
        pixels[i] = 0xFF000000 | (grey * 0x00010101);
    }

    return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
}

还有一些剩余的问题。我正在使用前置摄像头,尽管TextureView内部的预览方向是正确的,但ImageViewer返回的图像是顺时针旋转并垂直翻转的(预览时一个人躺在他们的右脸颊上,只有右脸颊是左脸颊,因为我的设备上的垂直翻转角度为270度。是否存在接受的解决方案,使使用Camera2的预览和保存的照片具有相同的正确方向?

干杯。

埃迪·塔瓦拉(Eddy Talvala)

如果您描述了图像是如何损坏的,这将很有帮助-您看到有效的图像,但图像失真了,还是只是完全的垃圾,还是完全的黑色?

但我想您没有注意Y平面的行距(https://developer.android.com/reference/android/media/Image.Plane.html#getRowStride())导致图像歪斜(垂直线变为斜线)。

当访问Y平面时,像素(x,y)的字节索引为:

y * rowStride + x

y * width + x

因为行跨度可能大于宽度。

我还要避免大量复制;您确实不需要2D数组,并且图像的大byte []也浪费了内存。

您可以改为seek()到每个输出行的开头,然后仅使用ByteBuffer.get(byte [],offset,length)读取需要直接复制到目标byte []中的字节。

看起来像

int stride = planes[0].getRowStride();
ByteBuffer img = planes[0].getBuffer();
int firstRowOffset = stride * t + l;
for (int row = 0; row < outh; row++) {
    img.position(firstRowOffset + row * stride);
    img.get(out, row * outw, outw);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Perl:如何在不创建副本的情况下将数组引用转换为数组

如何在不转换为Numpy数组的情况下将TensorFlow张量转换为PyTorch张量?

如何在不循环元素的情况下将int数组转换为可为null的int数组?

如何在不更改数组顺序的情况下将数组转换为Rails ActiveRecord :: Relation?

如何在不了解输入和输出数组的情况下将冻结图中的对象检测模型转换为 .tflite

如何在不转换为数组的情况下将数字添加为 firebase 实时数据库子项?

如何在不更改图像的情况下将 3d RGB NumPy 数组转换为浮动?

在 Google 表格中,如何在不破坏文本的情况下将数字转换为数组中的值?

从BitSet转换为Byte数组

如何在不循环每个像素的情况下,以窗口大小同时裁剪numpy数组的每个元素?

如何在React Native中将String转换为Byte数组?

如何在Delphi中将Byte数组转换为PByte?

如何在不使用键的情况下将json转换为数组

如何在不保存图像的情况下将Numpy数组图像转换为JPEG?

如何在不使用循环的情况下将数组转换为Javascript中的对象?

如何在保持相同顺序的情况下将数组转换为字典

如何在没有警告/错误的情况下将数组转换为ArrayList?

如何在不使用Gson的情况下将JSON转换为数组

如何在不使用jQuery的情况下将对象转换为对象数组?

如何在不复制元素的情况下将Vec转换为数组?

如何在不将其转换为数组的情况下返回多个值?

如何在不排序的情况下从对象输出数组

如何在不爆炸的情况下映射 Spark 数组?

swift:如何在不创建包含上述对象数组的结构的情况下解码json对象数组?

如何在不包含O(n)^ 3的情况下遍历包含2D数组的对象?

如何在不增加OverflowError:Python int太大而无法转换为C long的情况下,将数组中的每个元素与大量相乘?

如何在元素中考虑NaN的情况下将1-d数组转换为nd数组?

如何在不复制的情况下将字节数组转换为整数数组

如何在不更改屏幕像素RGB值的情况下极大地降低亮度?