我试图将YUV_420_888图像转换为位图,来自camera2预览。但是输出图像的颜色不正确。
请让我知道如果有人能发现转换的问题:
@Override
public void onImageAvailable(ImageReader reader)
{
RenderScript rs = RenderScript.create(this.mContext);
final Image image = reader.acquireLatestImage();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer planeY = planes[0].getBuffer();
final ByteBuffer planeU = planes[1].getBuffer();
final ByteBuffer planeV = planes[2].getBuffer();
// Get the YUV planes data
final int Yb = planeY.rewind().remaining();
final int Ub = planeU.rewind().remaining();
final int Vb = planeV.rewind().remaining();
final ByteBuffer yuvData = ByteBuffer.allocateDirect(Yb + Ub + Vb);
planeY.get(yuvData.array(), 0, Yb);
planeU.get(yuvData.array(), Yb, Vb);
planeV.get(yuvData.array(), Yb + Vb, Ub);
// Initialize Renderscript
Type.Builder yuvType = new Type.Builder(rs, Element.YUV(rs))
.setX(image.getWidth())
.setY(image.getHeight())
.setYuvFormat(ImageFormat.YUV_420_888);
final Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs))
.setX(image.getWidth())
.setY(image.getHeight());
Allocation yuvAllocation = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
Allocation rgbAllocation = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
// Convert
yuvAllocation.copyFromUnchecked(yuvData.array());
ScriptIntrinsicYuvToRGB scriptYuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.YUV(rs));
scriptYuvToRgb.setInput(yuvAllocation);
scriptYuvToRgb.forEach(rgbAllocation);
// Get the bitmap
Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
rgbAllocation.copyTo(bitmap);
// Release
bitmap.recycle();
yuvAllocation.destroy();
rgbAllocation.destroy();
rs.destroy();
image.close();
}
在回答我自己的问题时,实际的问题正如我所怀疑的那样,是如何将图像平面转换为字节缓冲区的。接下来是解决方案,它应该适用于NV21和YV12。由于YUV数据已经在不同的平面上出现,所以只是一个根据行和像素步幅以正确的方式获得它的问题。还需要对如何将数据传递到RenderScript内部进行一些小的修改。
注意:对于经过生产优化的onImageAvailable()不间断流,在执行转换之前,应该将图像字节数据复制到单独的缓冲区中,并在单独的线程中执行转换(取决于您的需求)。但由于这不是问题的一部分,在下一段代码中,转换直接放在onImageAvailable()中,以简化答案。如果有人需要知道如何复制图像数据,请创建一个新的问题,让我知道,这样我将分享我的代码。
@Override
public void onImageAvailable(ImageReader reader)
{
// Get the YUV data
final Image image = reader.acquireLatestImage();
final ByteBuffer yuvBytes = this.imageToByteBuffer(image);
// Convert YUV to RGB
final RenderScript rs = RenderScript.create(this.mContext);
final Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
final Allocation allocationRgb = Allocation.createFromBitmap(rs, bitmap);
final Allocation allocationYuv = Allocation.createSized(rs, Element.U8(rs), yuvBytes.array().length);
allocationYuv.copyFrom(yuvBytes.array());
ScriptIntrinsicYuvToRGB scriptYuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
scriptYuvToRgb.setInput(allocationYuv);
scriptYuvToRgb.forEach(allocationRgb);
allocationRgb.copyTo(bitmap);
// Release
bitmap.recycle();
allocationYuv.destroy();
allocationRgb.destroy();
rs.destroy();
image.close();
}
private ByteBuffer imageToByteBuffer(final Image image)
{
final Rect crop = image.getCropRect();
final int width = crop.width();
final int height = crop.height();
final Image.Plane[] planes = image.getPlanes();
final byte[] rowData = new byte[planes[0].getRowStride()];
final int bufferSize = width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8;
final ByteBuffer output = ByteBuffer.allocateDirect(bufferSize);
int channelOffset = 0;
int outputStride = 0;
for (int planeIndex = 0; planeIndex < 3; planeIndex++)
{
if (planeIndex == 0)
{
channelOffset = 0;
outputStride = 1;
}
else if (planeIndex == 1)
{
channelOffset = width * height + 1;
outputStride = 2;
}
else if (planeIndex == 2)
{
channelOffset = width * height;
outputStride = 2;
}
final ByteBuffer buffer = planes[planeIndex].getBuffer();
final int rowStride = planes[planeIndex].getRowStride();
final int pixelStride = planes[planeIndex].getPixelStride();
final int shift = (planeIndex == 0) ? 0 : 1;
final int widthShifted = width >> shift;
final int heightShifted = height >> shift;
buffer.position(rowStride * (crop.top >> shift) + pixelStride * (crop.left >> shift));
for (int row = 0; row < heightShifted; row++)
{
final int length;
if (pixelStride == 1 && outputStride == 1)
{
length = widthShifted;
buffer.get(output.array(), channelOffset, length);
channelOffset += length;
}
else
{
length = (widthShifted - 1) * pixelStride + 1;
buffer.get(rowData, 0, length);
for (int col = 0; col < widthShifted; col++)
{
output.array()[channelOffset] = rowData[col * pixelStride];
channelOffset += outputStride;
}
}
if (row < heightShifted - 1)
{
buffer.position(buffer.position() + rowStride - length);
}
}
}
return output;
}
问题内容: 我正在尝试从相机预览中捕获图像并在其上进行一些绘制。问题是,我只有大约3-4 fps的绘图,并且一半的帧处理时间是从摄像机预览接收和解码NV21图像并将其转换为 位图 。我有一个执行此任务的代码,是在另一个堆栈问题上找到的。它似乎并不快,但我不知道如何优化它。在Samsung Note 3(图像尺寸1920x1080)上大约需要100-150毫秒。我怎样才能使其更快地工作? 代码: 图
问题内容: 我想将位图打印到移动蓝牙打印机(Bixolon SPP-R200)-SDK不提供直接方法来打印内存图像。所以我想到了这样转换一个位图: 到单色位图。我正在使用Canvas在给定的位图上方绘制黑色文本,效果很好。但是,当我将上述位图转换为ByteArray时,打印机似乎无法处理这些字节。我怀疑我需要一个每个像素一位的数组(一个像素将是白色= 1或黑色= 0)。 似乎没有方便的开箱即用的方
我想把openCV Mat文件转换成GDI+位图图像。我找不到任何关于如何做到这一点的信息?
问题内容: 用户选择后,我想在 base64中 获取图像(提交表单之前) 就像是 : 我了解了文件API和其他内容,我想要一个简单的跨浏览器解决方案(显然不包括IE6 / IE7) 任何帮助表示感谢。 问题答案: function readFile() { ( PS: 一个base64编码的图像(字符串)为原始图像数据大小的4/3)
问题内容: 如何将灰度OpenCV图像转换为黑白图像?我看到已经提出了类似的问题,但是我使用的是OpenCV 2.3,建议的解决方案似乎不再起作用。 我正在尝试将灰度图像转换为黑白图像,以便不是绝对黑色的任何东西都是白色,并将其用作surf.detect()的蒙版,以便忽略在黑色蒙版区域边缘上找到的关键点。 下面的Python几乎可以解决我的问题,但是发送到Threshold()的阈值似乎没有任何
问题内容: 有没有一种方法可以将JPanel(尚未显示)转换为BufferedImage? 谢谢, 杰夫 问题答案: 在BufferedImage中,您可以创建一个图形对象,可用于在JPanel上调用画图,如下所示: 您可能需要确保首先设置面板的尺寸。