基于矩形裁剪YUV byte[]无转换:NV21格式混淆致图像异常求解决
Hey there, let's tackle your YUV cropping problem head-on—it sounds like the mix-up between different YUV sampling format diagrams threw you off, which is super easy to do given how many variants there are! Let's break down the core issues and fix this step by step.
核心问题根源
Your main pain point comes from mixing incompatible YUV sampling format logic:
- NV21 is a 4:2:0 format, not 4:2:2 or 4:1:1. The diagram labeled 4:2:2 is for formats like YUYV/YUY2, while 4:1:1 applies to YUV411—neither matches NV21's memory layout. Using the wrong diagram's logic will definitely mess up the UV component cropping, leading to that garbled output when converting to Bitmap/PNG.
关键修复建议
1. First: Lock in NV21's Exact Memory Layout
NV21's byte array is structured in two parts:
- Y Component: Takes up
width * heightbytes (1 byte per pixel, full resolution) - UV Component: Takes up
(width * height) / 2bytes, stored as interleaved V-U pairs (each pair corresponds to a 2x2 block of Y pixels)
2. Correct Cropping Logic for NV21 Byte[]
Cropping must respect 4:2:0's alignment rules—here's how to do it without conversion:
- Rule #1: Your crop width/height must be even numbers. 4:2:0 uses 2x2 Y blocks to share UV data, so odd dimensions will break the UV mapping.
- Rule #2: Crop Y and UV components separately, with aligned offsets:
- Crop the Y Component:
- Start index in original array:
cropY * srcWidth + cropX - For each of the
cropHeightrows, copycropWidthbytes from the original array to your new cropped array. Make sure to use the original image's width to calculate row offsets, not the cropped width!
- Start index in original array:
- Crop the UV Component:
- Start index in original array:
srcWidth * srcHeight + (cropY / 2) * srcWidth + (cropX / 2) * 2 - For each of the
cropHeight / 2UV rows, copycropWidthbytes (since each 2 Y columns map to 2 bytes of UV) to the end of your cropped array.
- Start index in original array:
- Crop the Y Component:
3. Fix Bitmap Conversion
Converting NV21 directly with BitmapFactory.decodeByteArray won't work—it assumes RGB data. Use Android's YuvImage class to properly convert to a usable bitmap:
// After cropping to get croppedNV21 byte[] YuvImage yuvImage = new YuvImage(croppedNV21, ImageFormat.NV21, cropWidth, cropHeight, null); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, cropWidth, cropHeight), 100, outputStream); byte[] jpegBytes = outputStream.toByteArray(); Bitmap croppedBitmap = BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.length);
Quick Troubleshooting Checks
- Double-check that
cropX,cropY,cropWidth, andcropHeightare all even numbers (or adjust them to be even—rounding down if needed) - Verify you're not using 4:2:2/4:1:1 row offset calculations for the UV component
- Make sure your byte array copy logic doesn't skip or duplicate bytes (off-by-one errors are common here!)
内容的提问来源于stack exchange,提问作者banerjk
相关产品推荐
相关产品推荐

