【问题标题】:How to convert YUV to RGB efficient如何高效地将 YUV 转换为 RGB
【发布时间】:2012-07-18 06:47:14
【问题描述】:

``我想在相机的预览中使用RGB。我使用JNI进行YUV到RGB的转换。我改变了RGB中的数据,然后我使用drawBitmap在预览中显示RGB。但是它显示得很慢,我该如何改进它

    public void onPreviewFrame(final byte[] data, Camera camera) {

    Thread showPic = new Thread(new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            Canvas c = mHolder.lockCanvas(null);
            try {

                synchronized (mHolder) {

                    // TODO Auto-generated method stub
                    int imageWidth = mCamera.getParameters()
                            .getPreviewSize().width;
                    int imageHeight = mCamera.getParameters()
                            .getPreviewSize().height;
                    int RGBData[] = new int[imageWidth * imageHeight];
                    int RGBDataa[] = new int[imageWidth * imageHeight];
                    int RGBDatab[] = new int[imageWidth * imageHeight];
                    int center = imageWidth * imageHeight / 2;

                    Jni.decodeYUV420SP(RGBData, data, imageWidth,
                            imageHeight); // decode
                    for (int i = 0; i < center; i++)
                        RGBDataa[i] = RGBData[i];
                    for (int i = center; i < imageWidth * imageHeight; i++)
                        RGBDatab[i - center] = RGBData[i];
                    for (int i = 0; i < center; i++)
                        RGBData[i] = RGBDatab[i];
                    for (int i = center; i < imageWidth * imageHeight; i++)
                        RGBData[i] = RGBDataa[i - center];

                    c.drawBitmap(RGBData, 0, imageWidth, 0, 0, imageWidth,
                            imageHeight, false, new Paint());

                    // Bitmap bm = Bitmap.createBitmap(RGBData, imageWidth,
                    // imageHeight, Config.ARGB_8888);

                }

            } finally {
                if (data != null)
                    mHolder.unlockCanvasAndPost(c);
            }
        }
    });
    showPic.run();

}

下面的代码是Jni

    public class Jni {
public native static void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width,
        int height);

} decodeYUV420SP方法由C语言完成。

【问题讨论】:

  • 嘿,我是堆栈 pn 同样的问题,但我把它放在拍摄的图片中我想问这个方法放在哪里以及如何调用
  • 如果最近有人在寻找答案,您最好的选择是 libyuv 及其手动优化的 NEON 组件。

标签: android camera java-native-interface rgb yuv


【解决方案1】:

我在搜索 YUV420sp 到 RGB565 转换时遇到了这个线程。按照上面的建议使用 decodeYUV420SP 可以正常工作,但我想添加一些运行时注意事项。

我在 Java 中使用 decodeYUV420SP 的第一次测试花了 74 秒解码和转换 10 秒的 .mp4 全高清视频(使用 Nexus 6 Android 设备)。分析器报告整个过程的 96% 都用于 decodeYUV420SP。

将 decodeYUV420SP 移动到 JNI/C 使得总体花费的时间减少到 32 秒。开启GCC代码优化,降到12秒。

虽然 OP 已经建议了这一点,但我想强调的是,将例程转移到 Java 不会是一种改进。虽然 Java 和 C 之间的上下文更改是有代价的,但这是一个很好的例子,在本机函数中执行的昂贵操作很容易补偿这种开销。间接费用声明对于非常简单的 JNI 函数有效,并且在需要来回查找方法和字段的情况下有效。此处不适用。

为了提高 OP 代码的性能:摆脱为每个帧完成的内存分配并将其存储在全局范围内,摆脱 RGBData* 上的算法并将这些东西也移动到 JNI。可以使用 Critical 函数在 JNI 级别上免费访问数组。

【讨论】:

  • 贴出的代码中还有更多需要清理的地方:去掉mCamera.getParameters(),使用预先计算好的宽度和高度;使用对位图数据的本机访问(AndroidBitmap_lockPixels() 等)来更新位图而不是复制像素;重用线程并摆脱同步锁……可以使用渲染脚本将转换卸载到 GPU,或者切换到 OpenGL 并让片段着色器完成艰苦的工作。可以肯定的一件事:在今天的 Android 上,用 C 和 Java 编写 YUV 到 RGB 的转换是合理的。
【解决方案2】:

不建议使用 jni,因为编译器将 java 代码转换为 C++ 的速度很慢。我认为你应该使用这样的直接方法

public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
    final int frameSize = width * height;

    for (int j = 0, yp = 0; j < height; j++) {
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (int i = 0; i < width; i++, yp++) {
            int y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0) y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0) r = 0; else if (r > 262143) r = 262143;
            if (g < 0) g = 0; else if (g > 262143) g = 262143;
            if (b < 0) b = 0; else if (b > 262143) b = 262143;

            rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
        }
    }
}

或者直接使用这个

Camera.Parameters.setPreviewFormat(ImageFormat.RGB_565);

直接将格式输出改为rgb

【讨论】:

  • 请注意,有些设备可能不支持 ImageFormat.RGB_565
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-27
  • 1970-01-01
  • 2022-07-31
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 2013-06-15
相关资源
最近更新 更多