使用 OpenCV 从 android Camera2 将 YUV 转换为 RGB ImageReader 时出现问题,输出图像为灰度

Posted

技术标签:

【中文标题】使用 OpenCV 从 android Camera2 将 YUV 转换为 RGB ImageReader 时出现问题,输出图像为灰度【英文标题】:Problem converting YUV to RGB ImageReader from android Camera2 using OpenCV, output image is in grayscale 【发布时间】:2019-08-28 05:27:25 【问题描述】:

我正在尝试在 java 中的 onImageAvailable 方法中将图像从 YUV 转换为 RGB。

我正在使用 openCV 进行转换。 我不能使用 android Camera2 的 RGB 格式来避免丢帧。

我无法选择最佳的转换格式。

Image.Plane Y = image.getPlanes()[0];
Image.Plane U = image.getPlanes()[1];
Image.Plane V = image.getPlanes()[2];

Y.getBuffer().position(0);
U.getBuffer().position(0);
V.getBuffer().position(0);

int Yb = Y.getBuffer().remaining();
int Ub = U.getBuffer().remaining();
int Vb = V.getBuffer().remaining();

ByteBuffer buffer = ByteBuffer.allocateDirect( Yb + Ub + Vb);

buffer.put(Y.getBuffer());
buffer.put(U.getBuffer());
buffer.put(V.getBuffer());

// Image is 640 x 480
Mat yuvMat = new Mat(960, 640, CvType.CV_8UC1);
yuvMat.put(0, 0, buffer.array());

// I don't know what is the correct format 
Mat rgbMat = new Mat(yuvMat.rows, yuvMat.cols, CvType.CV_8UC4);
Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV420sp2RGBA);

final Bitmap bit = Bitmap.createBitmap(rgbMat.cols(), rgbMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rgbMat, bit);

其实我得到的只是裁剪后的灰度图

【问题讨论】:

解决坦克到answers.opencv.org/question/61628/… 【参考方案1】:

试试这个功能:

    void decodeYUV420SP( byte[] rgb, byte[] yuv420sp, int width, int height )

    final int frameSize = width * height;

    for (int j = 0, yp = 0; j < height; j++) 
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (int i = 0; i < width; i++, yp++) 
            int y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0)
                y = 0;
            if ((i & 1) == 0) 
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0)                  r = 0;               else if (r > 262143)
                r = 262143;
            if (g < 0)                  g = 0;               else if (g > 262143)
                g = 262143;
            if (b < 0)                  b = 0;               else if (b > 262143)
                b = 262143;

            //rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
            int nIdx = ((width - i - 1) * height + height - j - 1) * 3;//device
            //int nIdx = (i * height + j) * 3;//nox
            rgb[nIdx] = (byte) (((r << 6) & 0xff0000)>>16);
            rgb[nIdx+1] = (byte) (((g >> 2) & 0xff00)>>8);
            rgb[nIdx+2] = (byte) ((b >> 10) & 0xff);
        
    

使用:decodeYUV420SP(rgb, camData, nWidth234, nHeight234);

可以得到RGB字节数组;

如果你需要从字节数组中获取图片,试试这个。

    public boolean convertYunToJpeg(byte[] data, int width, int height)
    YuvImage image = new YuvImage(data, ImageFormat.NV21, width, height, null);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int quailty = 20;
    image.compressToJpeg(new Rect(0,0, width, height), quailty, baos);
    byte[] jpegByteArray = baos.toByteArray();
    Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length);
    Matrix matrix = new Matrix();
    matrix.postRotate(-90);
    Bitmap lastbitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    try 

        File file = new File(BaseApplication.DIRECTORY + mCode + ".png");
        if(!file.exists())
            RandomAccessFile me = new RandomAccessFile(BaseApplication.DIRECTORY + mCode + ".png", "rw");
            me.writeInt(5);
            me.close();
            file = new File(BaseApplication.DIRECTORY + mCode + ".png");
        
        FileOutputStream fos = new FileOutputStream(file);
        lastbitmap.compress(Bitmap.CompressFormat.PNG, quailty, fos);
     catch (IOException e) 
        e.printStackTrace();
        return  false;
    
    return true;

【讨论】:

这是旧版相机引擎,而不是 camera2

以上是关于使用 OpenCV 从 android Camera2 将 YUV 转换为 RGB ImageReader 时出现问题,输出图像为灰度的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 OpenCV 从 C++ 程序制作 Android 应用程序

使用 OpenCV Python 从 Android 智能手机捕获视频

Android - 从图像中裁剪文本(使用 openCV 或其他任何东西)

OpenCV,Android:从图像中检测对象而不是实时检测

使用OpenCV Android SDK从摄像头帧实时检测人脸

在android中单击相机后,无需按确定按钮即可从相机获取图像