android– 将YUV_420_888转换为JPEG并保存文件结果失真的图像

android– 将YUV_420_888转换为JPEG并保存文件结果失真的图像,第1张

概述我在我的gitrepo:https://github.com/ahasbini/cameraviewree/camera_preview_imp中使用了https://stackoverflow.com/a/40152147/2949966中提供的ImageUtil类(注意实现在camera_preview_imp分支中)来实现帧预览回调.ImageReader设置为以ImageFormat.YUV_420_888格式预览帧,使用

我在我的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并保存文件结果失真的图像所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1119988.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-29
下一篇 2022-05-29

发表评论

登录后才能评论

评论列表(0条)

保存