我正在尝试将 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)
请帮我解决这个问题:(
你的代码看起来很接近正确了,但是有一些小问题会导致图像损坏。让我们看看如何改进它:
问题
-
NV21 格式假设
: 你的代码假设
ImageProxy
始终提供 NV21 格式的数据。虽然这是最常见的格式,但 Camerax 也可以提供其他格式,例如 YUV_420_888。 -
平面顺序
: NV21 格式的平面顺序是 Y、V、U,而不是 Y、U、V。你在填充
nv21
数组时颠倒了 V 和 U 平面。
解决方案
-
处理不同的图像格式 : 使用
image.getFormat()
检查图像格式,并根据格式调整你的代码。 -
修正平面顺序 : 确保按照 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