【问题标题】:Convert YUV420 to RGB using OpenCVSharp使用 OpenCVSharp 将 YUV420 转换为 RGB
【发布时间】:2019-11-12 22:46:15
【问题描述】:

我想将 YUV 流转换为 RGB 字节,以便它们可以通过 WPF 图像显示。

所有 YUV 值都放置在每帧的各自数组中 yuv。色度宽度和高度是各自亮度尺寸的一半。

byte[] y = (byte[])yData;
byte[] u = (byte[])uData;
byte[] v = (byte[])vData;

var ym = new Mat(new[] { lumaHeight, lumaWidth }, MatType.CV_8UC1, y, new long[] { lumaStride });
var um = new Mat(new[] { chromaWidth, chromaHeight }, MatType.CV_8UC1, u, new long[] { chromaStride});
var vm = new Mat(new[] { chromaWidth, chromaHeight }, MatType.CV_8UC1, v, new long[] { chromaStride});

我使用以下代码将数据传递给openCV:

var combinedSource = new[] { ym, um, vm };

var m = new Mat();
var src = InputArray.Create(combinedSource);
var @out = OutputArray.Create(m);
Cv2.CvtColor(src, @out, ColorConversionCodes.YUV2BGR);
ImageData = @out.GetMat().ToBytes();

但我收到 错误{"!_src.empty()"} yuv 数组肯定不是空的。

我尝试使用另一种方法:

var combinedOut = new Mat(new[] { lumaHeight, lumaWidth }, MatType.CV_8UC3);
Cv2.Merge(combinedSource, combinedOut);
var bgra = combinedOut.CvtColor(ColorConversionCodes.YUV2BGR);
ImageData = bgra.ToBytes();

但收到错误 {"mv[i].size == mv[0].size && mv[i].depth() == depth"}

为什么我会收到这些错误,正确的转换方法是什么?

【问题讨论】:

    标签: c# wpf opencv


    【解决方案1】:

    您为什么不尝试通过循环遍历所有源数组和输出数组来进行转换。要使此方法起作用,您必须将所有数组合并为一个,然后将该数组传递给以下函数

    private static unsafe void YUV2RGBManaged(byte[] YUVData, byte[] RGBData, int width, int height)
        {
            fixed(byte* pRGBs = RGBData, pYUVs = YUVData)
            {
                for (int r = 0; r < height; r++)
                {
                    byte* pRGB = pRGBs + r * width * 3;
                    byte* pYUV = pYUVs + r * width * 2;
    
                    //process two pixels at a time
                    for (int c = 0; c < width; c += 2)
                    {
                        int C1 = pYUV[1] - 16;
                        int C2 = pYUV[3] - 16;
                        int D = pYUV[2] - 128;
                        int E = pYUV[0] - 128;
    
                        int R1 = (298 * C1 + 409 * E + 128) >> 8;
                        int G1 = (298 * C1 - 100 * D - 208 * E + 128) >> 8;
                        int B1 = (298 * C1 + 516 * D + 128) >> 8;
    
                        int R2 = (298 * C2 + 409 * E + 128) >> 8;
                        int G2 = (298 * C2 - 100 * D - 208 * E + 128) >> 8;
                        int B2 = (298 * C2 + 516 * D + 128) >> 8;
    #if true
                        //check for overflow
                        //unsurprisingly this takes the bulk of the time.
                        pRGB[0] = (byte)(R1 < 0 ? 0 : R1 > 255 ? 255 : R1);
                        pRGB[1] = (byte)(G1 < 0 ? 0 : G1 > 255 ? 255 : G1);
                        pRGB[2] = (byte)(B1 < 0 ? 0 : B1 > 255 ? 255 : B1);
    
                        pRGB[3] = (byte)(R2 < 0 ? 0 : R2 > 255 ? 255 : R2);
                        pRGB[4] = (byte)(G2 < 0 ? 0 : G2 > 255 ? 255 : G2);
                        pRGB[5] = (byte)(B2 < 0 ? 0 : B2 > 255 ? 255 : B2);
    #else
                        pRGB[0] = (byte)(R1);
                        pRGB[1] = (byte)(G1);
                        pRGB[2] = (byte)(B1);
    
                        pRGB[3] = (byte)(R2);
                        pRGB[4] = (byte)(G2);
                        pRGB[5] = (byte)(B2);
    #endif
    
                        pRGB += 6;
                        pYUV += 4;
                    }
                }
            }
        }
    

    【讨论】:

    • 我看到这段代码是another answer 的副本。虽然将我的 YUV420 输入转换为我相信此代码使用的 YUYV 格式是一种可能的途径,但我更愿意相信 OpenCV,它很可能比这种方法更可靠和更快。在旁注中,这最好放在评论中而不是作为答案。
    【解决方案2】:

    按照post,我能够得出以下解决方案:

        private byte[] YuvToRgbOpenCv(object luma, object chroma, object yData, object uData, object vData)
        {
            int[] lumaArray = (int[])luma;
            int[] chromaArray = (int[])chroma;
    
            int lumaWidth = lumaArray[0];
            int lumaHeight = lumaArray[1];
    
            int chromaWidth = chromaArray[0];
            int chromaHeight = chromaArray[1];
    
            byte[] y = (byte[])yData;
            byte[] u = (byte[])uData;
            byte[] v = (byte[])vData;
    
            var ym = new Mat(new[] { lumaHeight, lumaWidth }, MatType.CV_8UC1, y);
            var um = new Mat(new[] { chromaHeight, chromaWidth }, MatType.CV_8UC1, u);
            var vm = new Mat(new[] { chromaHeight, chromaWidth }, MatType.CV_8UC1, v);
    
            var umResized = um.Resize(new OpenCvSharp.Size(lumaWidth, lumaHeight), 0, 0, InterpolationFlags.Nearest);
            var vmResized = vm.Resize(new OpenCvSharp.Size(lumaWidth, lumaHeight), 0, 0, InterpolationFlags.Nearest);
    
            var yuvMat = new Mat();
            var resizedChannels = new[] { ym, umResized, vmResized };
    
            Cv2.Merge(resizedChannels, yuvMat);
    
            var bgr = yuvMat.CvtColor(ColorConversionCodes.YUV2BGR);
    
            var result = bgr.ToBytes();
    
            return result;
        }
    

    我不得不调整 U、V 数据长度以匹配 Y 的长度。

    【讨论】:

      猜你喜欢
      • 2022-12-22
      • 2021-04-13
      • 2016-02-06
      • 2020-12-18
      • 2011-09-27
      • 2020-01-03
      • 1970-01-01
      • 2012-11-28
      • 2014-05-16
      相关资源
      最近更新 更多