如何获取Drawable文件夹中图片的Image.getPlanes()信息
读取Drawable中的JPG并获取Image.getPlanes()信息
嘿,我来帮你搞定这个问题!首先得明确:Android的Image类大多是针对相机预览、媒体解码这类YUV格式的场景设计的,而Drawable里的JPG是RGB格式,所以我们得先把图片转换成YUV_420_888格式的Image对象,才能调用getPlanes()方法。下面是完整的实现步骤和代码:
核心思路
- 从Drawable加载图片为
Bitmap - 通过
ImageReader创建一个对应尺寸、YUV格式的Image实例 - 将Bitmap的RGB数据转换成YUV_420_888格式,写入到
Image的Planes中 - 最后用你现有的
fillBytes方法提取Planes数据
完整代码实现
private byte[][] yuvBytes; public void processDrawableImage() { // 1. 加载Drawable中的图片为Bitmap(替换成你的图片资源ID) Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.your_image); if (bitmap == null) { Log.e("ImageProcess", "Failed to load bitmap from drawable"); return; } // 2. 创建ImageReader并获取Image对象,格式指定为YUV_420_888 ImageReader imageReader = ImageReader.newInstance( bitmap.getWidth(), bitmap.getHeight(), ImageFormat.YUV_420_888, 1 // 只需要一个Image实例 ); Image image = imageReader.acquireNextImage(); if (image == null) { Log.e("ImageProcess", "Failed to acquire image from ImageReader"); bitmap.recycle(); return; } try { // 3. 将Bitmap转换为YUV420格式并写入Image convertBitmapToYUV420(bitmap, image); // 4. 现在可以用你原有的代码获取Planes并填充yuvBytes final Plane[] planes = image.getPlanes(); yuvBytes = new byte[planes.length][]; // 初始化yuvBytes数组 fillBytes(planes, yuvBytes); // 这里可以添加你的后续处理逻辑,比如用yuvBytes做图像分类 Log.d("ImageProcess", "Successfully filled yuvBytes, plane count: " + planes.length); } finally { // 务必回收资源,避免内存泄漏 image.close(); imageReader.close(); bitmap.recycle(); } } /** * 将Bitmap的RGB数据转换为YUV_420_888格式,写入到Image对象中 */ private void convertBitmapToYUV420(Bitmap bitmap, Image image) { Rect rect = image.getCropRect(); int width = rect.width(); int height = rect.height(); Plane[] planes = image.getPlanes(); byte[] yBuffer = new byte[width * height]; // Y通道数据 byte[] uBuffer = new byte[(width / 2) * (height / 2)]; // U通道数据(420格式下是1/4分辨率) byte[] vBuffer = new byte[(width / 2) * (height / 2)]; // V通道数据 // 提取Bitmap的所有像素 int[] pixels = new int[width * height]; bitmap.getPixels(pixels, 0, width, 0, 0, width, height); int yIndex = 0; int uIndex = 0; int vIndex = 0; // 遍历每个像素,将RGB转换为YUV for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixel = pixels[y * width + x]; int r = (pixel >> 16) & 0xff; int g = (pixel >> 8) & 0xff; int b = pixel & 0xff; // 使用标准RGB转YUV公式计算 int yVal = (int) (0.299 * r + 0.587 * g + 0.114 * b); int uVal = (int) ((b - yVal) * 0.564 + 128); // U通道偏移128,保证在0-255范围内 int vVal = (int) ((r - yVal) * 0.713 + 128); // V通道同理 yBuffer[yIndex++] = (byte) Math.max(0, Math.min(255, yVal)); // YUV420格式:每2x2像素采样一次UV通道 if (y % 2 == 0 && x % 2 == 0) { uBuffer[uIndex++] = (byte) Math.max(0, Math.min(255, uVal)); vBuffer[vIndex++] = (byte) Math.max(0, Math.min(255, vVal)); } } } // 将转换后的YUV数据写入Image的各个Plane缓冲区 planes[0].getBuffer().put(yBuffer); planes[1].getBuffer().put(uBuffer); planes[2].getBuffer().put(vBuffer); } // 你原有的fillBytes方法可以直接复用 protected void fillBytes(final Plane[] planes, final byte[][] yuvBytes) { for (int i = 0; i < planes.length; ++i) { final ByteBuffer buffer = planes[i].getBuffer(); if (yuvBytes[i] == null) { yuvBytes[i] = new byte[buffer.capacity()]; } buffer.get(yuvBytes[i]); } }
关键注意事项
- 格式匹配:必须使用
ImageFormat.YUV_420_888格式创建ImageReader,这是getPlanes()最常用的格式,对应3个Plane(Y、U、V)。 - 资源回收:
Image和ImageReader使用后必须调用close(),Bitmap要调用recycle(),否则会造成内存泄漏。 - 转换公式:代码里用的是标准的RGB转YUV公式,保证转换后的数据符合图像分类模型的输入要求。
内容的提问来源于stack exchange,提问作者Surya Tej
相关产品推荐
相关产品推荐

