Обрезать байтовый массив YUV420/NV21 прямо в Android
Мне нужно обрезать каждый кадр из onPreviewFrame камеры. Я хочу обрезать его непосредственно, выполняя операции с байтовым массивом без преобразования его в растровое изображение. Причина, по которой я хочу сделать это непосредственно в массиве, заключается в том, что он не может быть слишком медленным или слишком дорогим. После операции обрезки я буду использовать выходной байтовый массив напрямую, поэтому мне не нужно преобразовывать растровые изображения.
int frameWidth;
int frameHeight;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// Crop the data array directly.
cropData(data, frameWidth, frameHeight, startCropX, startCropY, outputWidth, outputHeight);
}
1 ответ
private static byte[] cropNV21(byte[] img, int imgWidth, @NonNull Rect cropRect) {
// 1.5 mean 1.0 for Y and 0.25 each for U and V
int croppedImgSize = (int)Math.floor(cropRect.width() * cropRect.height() * 1.5);
byte[] croppedImg = new byte[croppedImgSize];
// Start points of UV plane
int imgYPlaneSize = (int)Math.ceil(img.length / 1.5);
int croppedImgYPlaneSize = cropRect.width() * cropRect.height();
// Y plane copy
for (int w = 0; w < cropRect.height(); w++) {
int imgPos = (cropRect.top + w) * imgWidth + cropRect.left;
int croppedImgPos = w * cropRect.width();
System.arraycopy(img, imgPos, croppedImg, croppedImgPos, cropRect.width());
}
// UV plane copy
// U and V are reduced by 2 * 2, so each row is the same size as Y
// and is half U and half V data, and there are Y_rows/2 of UV_rows
for (int w = 0; w < (int)Math.floor(cropRect.height() / 2.0); w++) {
int imgPos = imgYPlaneSize + (cropRect.top / 2 + w) * imgWidth + cropRect.left;
int croppedImgPos = croppedImgYPlaneSize + (w * cropRect.width());
System.arraycopy(img, imgPos, croppedImg, croppedImgPos, cropRect.width());
}
return croppedImg;
}
Структура NV21:
PS: Кроме того, если начальная позиция вашего прямоугольника нечетная, U и V будут заменены местами. Чтобы справиться с этим случаем, я использую:
if (cropRect.left % 2 == 1) {
cropRect.left -= 1;
}
if (cropRect.top % 2 == 1) {
cropRect.top -= 1;
}