Поворот байтового массива YUV на Android

Я хочу повернуть предварительный просмотр кадра YUV, полученного из предварительного просмотра Callblack, до сих пор я основал этот пост, который содержит алгоритм, чтобы вращать предварительный просмотр кадра, но испортил повернутые пиксели камеры изображения предварительного просмотра

Другим способом поворота изображения будет создание jpg из изображения YUV, создание растрового изображения, поворот растрового изображения и получение массива байтов растрового изображения, но мне действительно нужен формат в YUV (NV21).

FYI. причина, по которой я спрашиваю об этом, заключается в том, что у меня есть приложение камеры, которое поддерживает вращение, но предварительный просмотр кадров возвращается только в ландшафтном режиме.

3 ответа

Решение

Следующий метод может повернуть массив байтов YUV420 на 90 градусов.

private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) 
{
    byte [] yuv = new byte[imageWidth*imageHeight*3/2];
    // Rotate the Y luma
    int i = 0;
    for(int x = 0;x < imageWidth;x++)
    {
        for(int y = imageHeight-1;y >= 0;y--)                               
        {
            yuv[i] = data[y*imageWidth+x];
            i++;
        }
    }
    // Rotate the U and V color components 
    i = imageWidth*imageHeight*3/2-1;
    for(int x = imageWidth-1;x > 0;x=x-2)
    {
        for(int y = 0;y < imageHeight/2;y++)                                
        {
            yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x];
            i--;
            yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)];
            i--;
        }
    }
    return yuv;
}

(Обратите внимание, что это может работать, только если ширина и высота в 4 раза)

Вот варианты, чтобы повернуть другой угол (90, 180, 270):

public static byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) {
    byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
    // Rotate the Y luma
    int i = 0;
    for (int x = 0; x < imageWidth; x++) {
        for (int y = imageHeight - 1; y >= 0; y--) {
            yuv[i] = data[y * imageWidth + x];
            i++;
        }
    }
    // Rotate the U and V color components
    i = imageWidth * imageHeight * 3 / 2 - 1;
    for (int x = imageWidth - 1; x > 0; x = x - 2) {
        for (int y = 0; y < imageHeight / 2; y++) {
            yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
            i--;
            yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth)
                    + (x - 1)];
            i--;
        }
    }
    return yuv;
}

private static byte[] rotateYUV420Degree180(byte[] data, int imageWidth, int imageHeight) {
    byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
    int i = 0;
    int count = 0;
    for (i = imageWidth * imageHeight - 1; i >= 0; i--) {
        yuv[count] = data[i];
        count++;
    }
    i = imageWidth * imageHeight * 3 / 2 - 1;
    for (i = imageWidth * imageHeight * 3 / 2 - 1; i >= imageWidth
            * imageHeight; i -= 2) {
        yuv[count++] = data[i - 1];
        yuv[count++] = data[i];
    }
    return yuv;
}

public static byte[] rotateYUV420Degree270(byte[] data, int imageWidth,
                                     int imageHeight) {
    byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
    int nWidth = 0, nHeight = 0;
    int wh = 0;
    int uvHeight = 0;
    if (imageWidth != nWidth || imageHeight != nHeight) {
        nWidth = imageWidth;
        nHeight = imageHeight;
        wh = imageWidth * imageHeight;
        uvHeight = imageHeight >> 1;// uvHeight = height / 2
    }
    // ??Y
    int k = 0;
    for (int i = 0; i < imageWidth; i++) {
        int nPos = 0;
        for (int j = 0; j < imageHeight; j++) {
            yuv[k] = data[nPos + i];
            k++;
            nPos += imageWidth;
        }
    }
    for (int i = 0; i < imageWidth; i += 2) {
        int nPos = wh;
        for (int j = 0; j < uvHeight; j++) {
            yuv[k] = data[nPos + i];
            yuv[k + 1] = data[nPos + i + 1];
            k += 2;
            nPos += imageWidth;
        }
    }
    return rotateYUV420Degree180(yuv, imageWidth, imageHeight);
}

Вот как я это сделал

Этот блок кода установлен в другом месте

    Camera.Size size
    Rect rectangle = new Rect();
    rectangle.bottom = size.height;
    rectangle.top = 0;
    rectangle.left = 0;
    rectangle.right = size.width;

Это метод, который делает работу

    private Bitmap rotateBitmap(YuvImage yuvImage, int orientation, Rect rectangle)
    {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    yuvImage.compressToJpeg(rectangle, 100, os);

    Matrix matrix = new Matrix();
    matrix.postRotate(orientation);
    byte[] bytes = os.toByteArray();
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    return Bitmap.createBitmap(bitmap, 0 , 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

сжать YUVImage в JPEG, чтобы растровое изображение могло справиться с этим. Поверните растровое изображение, а затем экспортируйте его. Чтобы вернуть его в JPEG, как я и хотел, я использовал эту строку

image.compress(Bitmap.CompressFormat.JPEG, 50, outputStream);
Другие вопросы по тегам