我在我的git repo:https://github.com/ahasbini/cameraview/tree/camera_preview_imp中使用了https://stackoverflow.com/a/40152147/2949966中提供的ImageUtil类(注意实现在camera_prevIEw_imp分支中)来实现帧预览回调. ImageReader设置为以ImageFormat.YUV_420_888格式预览帧,使用ImageUtil类将其转换为ImageFormat.JPEG并将其发送到帧回调.演示应用程序每50帧将回调帧保存到文件中.所有保存的帧图像都会失真,类似于以下内容:
如果我通过在Camera2中进行以下更改,将ImageReader更改为使用ImageFormat.JPEG:
mPrevIEwImageReader = ImageReader.newInstance(prevIEwSize.getWIDth(), prevIEwSize.getHeight(), ImageFormat.JPEG, /* maxImages */ 2);mCamera.createCaptureSession(Arrays.asList(surface, mPrevIEwImageReader.getSurface()), mSessionCallback, null);
图像正常运行而没有任何失真,但帧速率显着下降,视图开始滞后.因此我相信ImageUtil类没有正确转换.
解决方法:
@ volodymyr-kulyk提供的解决方案没有考虑图像中平面的行间距.下面的代码诀窍(图像是androID.media.Image类型):
data = NV21toJPEG(YUV420toNV21(image), image.getWIDth(), image.getHeight(), 100);
实施:
private static byte[] NV21toJPEG(byte[] nv21, int wIDth, int height, int quality) { ByteArrayOutputStream out = new ByteArrayOutputStream(); YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, wIDth, height, null); yuv.compresstoJpeg(new Rect(0, 0, wIDth, height), quality, out); return out.toByteArray();}private static byte[] YUV420toNV21(Image image) { Rect crop = image.getCropRect(); int format = image.getFormat(); int wIDth = crop.wIDth(); int height = crop.height(); Image.Plane[] planes = image.getPlanes(); byte[] data = new byte[wIDth * height * ImageFormat.getBitsPerPixel(format) / 8]; byte[] rowData = new byte[planes[0].getRowStrIDe()]; int channelOffset = 0; int outputStrIDe = 1; for (int i = 0; i < planes.length; i++) { switch (i) { case 0: channelOffset = 0; outputStrIDe = 1; break; case 1: channelOffset = wIDth * height + 1; outputStrIDe = 2; break; case 2: channelOffset = wIDth * height; outputStrIDe = 2; break; } ByteBuffer buffer = planes[i].getBuffer(); int rowStrIDe = planes[i].getRowStrIDe(); int pixelStrIDe = planes[i].getPixelStrIDe(); int shift = (i == 0) ? 0 : 1; int w = wIDth >> shift; int h = height >> shift; buffer.position(rowStrIDe * (crop.top >> shift) + pixelStrIDe * (crop.left >> shift)); for (int row = 0; row < h; row++) { int length; if (pixelStrIDe == 1 && outputStrIDe == 1) { length = w; buffer.get(data, channelOffset, length); channelOffset += length; } else { length = (w - 1) * pixelStrIDe + 1; buffer.get(rowData, 0, length); for (int col = 0; col < w; coL++) { data[channelOffset] = rowData[col * pixelStrIDe]; channelOffset += outputStrIDe; } } if (row < h - 1) { buffer.position(buffer.position() + rowStrIDe - length); } } } return data;}
方法来自以下link.
总结以上是内存溢出为你收集整理的android – 将YUV_420_888转换为JPEG并保存文件结果失真的图像全部内容,希望文章能够帮你解决android – 将YUV_420_888转换为JPEG并保存文件结果失真的图像所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)