我检查了将ImageProxy转换为位图中描述的所有硫化物,在许多设备中唯一起作用的是这个类的java版本,所以我使用下面的类将ImageProxy转换为位图:
public class YuvToRgbConverter {
private RenderScript rs;
private ScriptIntrinsicYuvToRGB scriptYuvToRgb;
private int pixelCount = -1;
private byte[] yuvBuffer = null;
private Allocation inputAllocation = null;
private Allocation outputAllocation = null;
public YuvToRgbConverter(Context context) {
rs = RenderScript.create(context);
scriptYuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
}
@Synchronized
public void yuvToRgb(Image image, Bitmap output) {
// Ensure that the intermediate output byte buffer is allocated
if (yuvBuffer == null) {
pixelCount = image.getCropRect().width() * image.getCropRect().height();
// Bits per pixel is an average for the whole image, so it's useful to compute the size
// of the full buffer but should not be used to determine pixel offsets
int pixelSizeBits = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888);
yuvBuffer = new byte[pixelCount * pixelSizeBits / 8];
}
// Get the YUV data in byte array form using NV21 format
imageToByteArray(image, yuvBuffer);
// Ensure that the RenderScript inputs and outputs are allocated
if (inputAllocation == null) {
// Explicitly create an element with type NV21, since that's the pixel format we use
Type elemType = new Type.Builder(rs, Element.YUV(rs)).setYuvFormat(ImageFormat.NV21).create();
inputAllocation = Allocation.createSized(rs, elemType.getElement(), yuvBuffer.length);
}
if (outputAllocation == null) {
outputAllocation = Allocation.createFromBitmap(rs, output);
}
// Convert NV21 format YUV to RGB
inputAllocation.copyFrom(yuvBuffer);
scriptYuvToRgb.setInput(inputAllocation);
scriptYuvToRgb.forEach(outputAllocation);
outputAllocation.copyTo(output);
}
private void imageToByteArray(Image image, byte[] outputBuffer) {
assert (image.getFormat() == ImageFormat.YUV_420_888);
Rect imageCrop = image.getCropRect();
Image.Plane[] imagePlanes = image.getPlanes();
for (int planeIndex = 0; planeIndex < imagePlanes.length; ++planeIndex) {
Image.Plane plane = imagePlanes[planeIndex];
int outputStride = 0;
int outputOffset = 0;
switch (planeIndex) {
case 0:
outputStride = 1;
outputOffset = 0;
break;
case 1:
outputStride = 2;
outputOffset = pixelCount + 1;
break;
case 2:
outputStride = 2;
outputOffset = pixelCount;
break;
default:
return;
}
ByteBuffer planeBuffer = plane.getBuffer();
int rowStride = plane.getRowStride();
int pixelStride = plane.getPixelStride();
Rect planeCrop = imageCrop;
if (planeIndex != 0) {
planeCrop = new Rect(imageCrop.left / 2, imageCrop.top / 2, imageCrop.right / 2, imageCrop.bottom / 2);
}
int planeWidth = planeCrop.width();
int planeHeight = planeCrop.height();
byte[] rowBuffer = new byte[plane.getRowStride()];
int rowLength = planeWidth;
if (pixelStride != 1 || outputStride != 1) {
rowLength = (planeWidth - 1) * pixelStride + 1;
}
for (int row = 0; row < planeHeight; row++) {
planeBuffer.position((row + planeCrop.top) * rowStride + planeCrop.left * pixelStride);
if (pixelStride == 1 && outputStride == 1) {
planeBuffer.get(outputBuffer, outputOffset, rowLength);
outputOffset += rowLength;
} else {
planeBuffer.get(rowBuffer, 0, rowLength);
for (int col = 0; col < planeWidth; col++) {
outputBuffer[outputOffset] = rowBuffer[col * pixelStride];
outputOffset += outputStride;
}
}
}
}
}
}这个类在许多设备中都能正常工作,但在某些设备中,我得到了一个绿色位图。
在许多设备中的正确转换()

某些设备中的绿色位图

所以我的问题是如何解决这个问题?还有更好的办法吗?谢谢
发布于 2022-02-25 07:25:40
这里,您可以轻松地将Imageproxy转换为位图。
private static ByteBuffer yuv420ThreePlanesToNV21(
Plane[] yuv420888planes, int width, int height) {
int imageSize = width * height;
byte[] out = new byte[imageSize + 2 * (imageSize / 4)];
if (areUVPlanesNV21(yuv420888planes, width, height)) {
// Copy the Y values.
yuv420888planes[0].getBuffer().get(out, 0, imageSize);
ByteBuffer uBuffer = yuv420888planes[1].getBuffer();
ByteBuffer vBuffer = yuv420888planes[2].getBuffer();
// Get the first V value from the V buffer, since the U buffer does not contain it.
vBuffer.get(out, imageSize, 1);
// Copy the first U value and the remaining VU values from the U buffer.
uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);
} else {
// Fallback to copying the UV values one by one, which is slower but also works.
// Unpack Y.
unpackPlane(yuv420888planes[0], width, height, out, 0, 1);
// Unpack U.
unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);
// Unpack V.
unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);
}
return ByteBuffer.wrap(out);
}
/** Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format. */
@RequiresApi(VERSION_CODES.KITKAT)
private static boolean areUVPlanesNV21(Plane[] planes, int width, int height) {
int imageSize = width * height;
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
// Backup buffer properties.
int vBufferPosition = vBuffer.position();
int uBufferLimit = uBuffer.limit();
// Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.
vBuffer.position(vBufferPosition + 1);
// Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.
uBuffer.limit(uBufferLimit - 1);
// Check that the buffers are equal and have the expected number of elements.
boolean areNV21 =
(vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);
// Restore buffers to their initial state.
vBuffer.position(vBufferPosition);
uBuffer.limit(uBufferLimit);
return areNV21;
}
/**
* Unpack an image plane into a byte array.
*
* <p>The input plane data will be copied in 'out', starting at 'offset' and every pixel will be
* spaced by 'pixelStride'. Note that there is no row padding on the output.
*/
@TargetApi(VERSION_CODES.KITKAT)
private static void unpackPlane(
Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {
ByteBuffer buffer = plane.getBuffer();
buffer.rewind();
// Compute the size of the current plane.
// We assume that it has the aspect ratio as the original image.
int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();
if (numRow == 0) {
return;
}
int scaleFactor = height / numRow;
int numCol = width / scaleFactor;
// Extract the data in the output buffer.
int outputPos = offset;
int rowStart = 0;
for (int row = 0; row < numRow; row++) {
int inputPos = rowStart;
for (int col = 0; col < numCol; col++) {
out[outputPos] = buffer.get(inputPos);
outputPos += pixelStride;
inputPos += plane.getPixelStride();
}
rowStart += plane.getRowStride();
}
}
public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
data.rewind();
byte[] imageInBuffer = new byte[data.limit()];
data.get(imageInBuffer, 0, imageInBuffer.length);
try {
YuvImage image =
new YuvImage(
imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 50, stream);
/*image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 100, stream);
byte[] jpegByteArray = stream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
Canvas c = new Canvas(bitmap.copy(bitmap.getConfig(),true));
Paint p = new Paint();
p.setARGB(255, 0, 0, 0); // ARGB for the color, in this case red
p.setAlpha(0);
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
c.drawPaint(p);*/
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
return bmp;
} catch (Exception e) {
Log.e("VisionProcessorBase", "Error: " + e.getMessage());
}
return null;
}如何使用
public void processImageProxy(ImageProxy image) {
FrameMetadata frameMetadata =
new FrameMetadata.Builder()
.setWidth(image.getWidth())
.setHeight(image.getHeight())
.setRotation(image.getImageInfo().getRotationDegrees())
.build();
ByteBuffer nv21Buffer =
yuv420ThreePlanesToNV21(Objects.requireNonNull(image.getImage()).getPlanes(), image.getWidth(), image.getHeight());
Bitmap yourBitmap = getBitmap(nv21Buffer, frameMetadata);
}https://stackoverflow.com/questions/71262274
复制相似问题