首页 > 编程问答 >Android ImageProxy 到 byteArray 并通过套接字发送

Android ImageProxy 到 byteArray 并通过套接字发送

时间:2024-08-04 15:19:36浏览次数:12  
标签:python java android image-processing android-camerax

我正在尝试将 ImageProxy 转换为 byteArray,以通过套接字将其发送到 python 服务器。 我正在使用 Camerax,这是我的图像分析:

mageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                        .setTargetResolution(new Size(720, 640))
                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
//                        .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) // uncomment if it solves the problem easier
                        .build();
 
                 imageAnalysis.setAnalyzer(executor, image -> {

                    byte[] imageBytes = imageProxyToByteArray(image);
                    if (imageBytes != null && imageBytes.length > 0) {
                        try (Socket socket = new Socket("192.168.143.234", 65432)) {
                            OutputStream outputStream = socket.getOutputStream();
                            outputStream.write("<start>".getBytes());
                            outputStream.write(imageBytes);
                            outputStream.write("<end>".getBytes());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    image.close();
                });

private byte[] imageProxyToByteArray(ImageProxy image) {
        ImageProxy.PlaneProxy[] planes = image.getPlanes();
        ByteBuffer yBuffer = planes[0].getBuffer();
        ByteBuffer uBuffer = planes[1].getBuffer();
        ByteBuffer vBuffer = planes[2].getBuffer();

        int ySize = yBuffer.remaining();
        int uSize = uBuffer.remaining();
        int vSize = vBuffer.remaining();

        byte[] nv21 = new byte[ySize + uSize + vSize];

        yBuffer.get(nv21, 0, ySize);
        vBuffer.get(nv21, ySize, vSize);
        uBuffer.get(nv21, ySize + vSize, uSize);

        YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 100, out);
        return out.toByteArray();
    }

我在 Android 设备的 java 中使用了上述代码,这是 python 代码:

img_array = ... #comes from socket and im sure it is started with <start> and end with <end> 
img_array = np.frombuffer(img_array, dtype=np.uint8)
image = cv2.imdecode(img_array, cv2.IMREAD_UNCHANGED)
cv2.imwrite('received_image.jpg', image)

但结果不是有效的图像: not a valid image

请帮我解决这个问题:(


你的代码看起来很接近正确了,但是有一些小问题会导致图像损坏。让我们看看如何改进它:

问题

  1. NV21 格式假设 : 你的代码假设 ImageProxy 始终提供 NV21 格式的数据。虽然这是最常见的格式,但 Camerax 也可以提供其他格式,例如 YUV_420_888。
  2. 平面顺序 : NV21 格式的平面顺序是 Y、V、U,而不是 Y、U、V。你在填充 nv21 数组时颠倒了 V 和 U 平面。

解决方案

  1. 处理不同的图像格式 : 使用 image.getFormat() 检查图像格式,并根据格式调整你的代码。

  2. 修正平面顺序 : 确保按照 Y、V、U 的顺序填充 nv21 数组。

改进后的代码

private byte[] imageProxyToByteArray(ImageProxy image) {
    ImageProxy.PlaneProxy[] planes = image.getPlanes();
    int format = image.getFormat();

    ByteBuffer yBuffer = planes[0].getBuffer();
    int ySize = yBuffer.remaining();

    byte[] nv21;

    if (format == ImageFormat.YUV_420_888) { 
        // 处理 YUV_420_888 格式
        ByteBuffer uBuffer = planes[1].getBuffer();
        ByteBuffer vBuffer = planes[2].getBuffer();
        int uSize = uBuffer.remaining();
        int vSize = vBuffer.remaining();

        nv21 = new byte[ySize + uSize + vSize];

        yBuffer.get(nv21, 0, ySize);
        // 注意 V, U 顺序
        vBuffer.get(nv21, ySize, vSize);
        uBuffer.get(nv21, ySize + vSize, uSize); 
    } else if (format == ImageFormat.NV21) {
        // 处理 NV21 格式
        ByteBuffer vuBuffer = planes[1].getBuffer();
        int vuSize = vuBuffer.remaining();

        nv21 = new byte[ySize + vuSize];

        yBuffer.get(nv21, 0, ySize);
        vuBuffer.get(nv21, ySize, vuSize);
    } else {
        // 处理其他格式,或者抛出异常
        throw new IllegalArgumentException("Unsupported image format: " + format);
    }

    YuvImage yuvImage = new YuvImage(nv21, format, image.getWidth(), image.getHeight(), null);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    yuvImage.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 100, out);
    return out.toByteArray();
}

其他建议

  • 错误处理 : 在你的 Python 代码中添加错误处理,以捕获解码错误。这有助于识别图像是否在传输过程中损坏。
  • 压缩 : 考虑使用更有效的压缩方法,例如 WebP 或 H.264,以减少图像大小和传输时间。

通过这些更改,你应该能够成功地将图像从你的 Android 设备传输到 Python 服务器并正确解码。

标签:python,java,android,image-processing,android-camerax
From: 78829954

相关文章

  • 如何在python中使用xarray打开grib2文件?
    将xarray导入为xr导入cfgrib导入生态码将pandas导入为pddata=xr.open_dataset(r"C:\Users\new\forecast_data.grib2",engine="cfgrib")这是我的代码。我只想使用xarray读取这个文件。错误是:无法识别的引擎cfgrib必须是以下之一:['netcdf4'、'scipy'、'......
  • 如何在 java 或 python 中使用 HTTP(S) 解决无法解析的主机名或无法识别的名称错误?
    我尝试以编程方式访问网站的信息,但在Java和Python上都无法解析主机名。如果我指定IP地址,则会将错误更改为TLSV1_UNRECOGNIZED_NAME。不过,这个网站无需任何额外的工作就可以通过任何浏览器解决。我在这里浏览了很多潜在的解决方案,但对于Python,它说这个问题应该在2.7......
  • Java对象流
    对象流对象输入流java.io.ObjectInputStream使用对象流可以进行对象反序列化构造器ObjectInputStream(InputStreamin)将当前创建的对象输入流链接在指定的输入流上方法ObjectreadObject()进行对象反序列化并返回。该方法会从当前对象输入流链接的流中读取若干......
  • Python 请求 POST 请求与 websockets 库一起使用时挂起
    我使用Python中的requests库发送POST请求,同时维护与websockets库的WebSocket连接:importasyncioimportrequestsimportwebsocketsasyncdefwebsocket_handler(uri):asyncwithwebsockets.connect(uri)aswebsocket:whileTrue:me......
  • 在Python中,list1[::] = list2的空间复杂度是多少?
    此代码首先迭代列表nums,更新整数0、1、2(也分别称为红色、白色和蓝色)的计数。nums保证只有整数0、1和/或2。找到计数后,代码使用[::],这是一种就地修改列表的技巧,以排序numsdefsortColors(self,nums:List[int])->None:re......
  • JavaScript Proxy() 构造函数、Proxy对象
    Proxy()构造函数Proxy()构造函数用于创建Proxy对象。语法newProxy(target,handler)可以使用Proxy()构造函数来创建一个新的Proxy对象。构造函数接收两个必须的参数:target是要创建的对象,即要使用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数......
  • Java - 异常与File
    异常灵魂四问:如果try中没有遇到问题,怎么执行?try全部执行,catch不执行如果try中可能会遇到多个问题,怎么执行?写多个catch与之对应,父类异常需要写在下面如果try中遇到的问题没有被捕获,怎么执行?异常会默认交给虚拟机处理,try...catch白写如果try中遇到了问题,那......
  • [附开题]flask框架高校资产管理系统d8y3s(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育事业的快速发展,高校资产规模日益庞大,种类繁多,管理难度显著增加。传统的资产管理方式往往依赖于手工记录和纸质档案,不仅效率低......
  • [附开题]flask框架贺州图特产管理系统uuy79(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景贺州,这座历史悠久、文化底蕴深厚的城市,以其丰富的自然资源和独特的地理位置孕育了众多令人瞩目的特产。然而,在信息化快速发展的今天,贺州特......
  • [附开题]flask框架红枫超市会员管理系统ew5iq(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着零售行业的快速发展与消费者需求的日益多样化,超市作为人们日常生活中不可或缺的一部分,其管理效率和服务质量直接影响着顾客的购物体验......