【问题标题】:Working with UMat in Emgu wrapper在 Emgu 包装器中使用 UMat
【发布时间】:2015-07-02 07:35:35
【问题描述】:

我创建了一个应用程序,将 HSV 过滤器应用于图像,然后尝试跟踪特定颜色。我想使用 UMat,因为我需要在 GPU 中而不是在 CPU 中计算图像。

在下面的代码中,我首先采用Image<Bgra, Byte>,然后使用HSV 颜色格式转换为UMat 格式。但是,当我拆分频道时,每个频道都有 3 个频道(例如 hsvChannels[0] 有三个频道;我不知道为什么会这样)。最后我无法应用过滤器,因为当我使用inRangeImage 方法时,我得到一个带有一个通道和错误形式CvInvoke.Copy“未知数组格式”的图像。

该应用程序不是最好的,但我想先了解 UMat 图像格式的工作原理,然后尝试改进它。

        private UMat CvAndHsvImage(Image<Bgra, Byte> imgFrame, byte lowerHue, byte upperHue, byte lowerSat, byte upperSat, byte lowerBright, byte upperBright,
        byte erosion = 0, byte dilate = 0, bool hue = false, bool sat = false, bool bright = false, bool invert = false)
    {
        // First convert the input image to hsv so we can change the channels
        //Image<Hsv, Byte> hsvImage = imgFrame.Convert<Hsv, Byte>();
        UMat hsvImage = new UMat();
        UMat bgrImage = new UMat();
        CvInvoke.CvtColor(imgFrame, bgrImage, ColorConversion.Bgra2Bgr);
        CvInvoke.CvtColor(bgrImage, hsvImage, ColorConversion.Bgr2Hsv);

        // Final image that will be returned.
        UMat ResultImage = new UMat();
        UMat ResultImageH = new UMat();
        UMat ResultImageS = new UMat();
        UMat ResultImageV = new UMat();

        UMat[] hsvChannels = new UMat[3];
        hsvChannels = hsvImage.Split();

        UMat img1 = inRangeImage(hsvChannels[0], lowerHue, upperHue);
        UMat img2 = inRangeImage(hsvChannels[1], lowerSat, upperSat);
        UMat img3 = inRangeImage(hsvChannels[2], lowerBright, upperBright);


        #region checkBox Color Mode
        // Evaluation of the check box for each filter. Return the right image
        if (hue)
        {
            CvInvoke.cvCopy(img1, ResultImageH, IntPtr.Zero);
        }
        if (sat)
            //ResultImageS = img2;
            CvInvoke.cvCopy(img2, ResultImageS, IntPtr.Zero);
        if (bright)
            //ResultImageV = img3;
            CvInvoke.cvCopy(img3, ResultImageS, IntPtr.Zero);

        if (hue && !sat && !bright)
            ResultImage = ResultImageH;
        if (!hue && sat && !bright)
            ResultImage = ResultImageS;
        if (!hue && !sat && bright)
            ResultImage = ResultImageV;

        if (hue && sat && !bright)
        {
            CvInvoke.BitwiseAnd(ResultImageH, ResultImageS, ResultImageH);
            ResultImage = ResultImageH;
        }

        if (hue && !sat && bright)
        {
            CvInvoke.BitwiseAnd(ResultImageH, ResultImageV, ResultImageH);
            ResultImage = ResultImageH;
        }

        if (!hue && sat && bright)
        {
            CvInvoke.BitwiseAnd(ResultImageS, ResultImageV, ResultImageS);
            ResultImage = ResultImageS;
        }

        if (hue && sat && bright)
        {
            CvInvoke.BitwiseAnd(ResultImageH, ResultImageS, ResultImageH);
            CvInvoke.BitwiseAnd(ResultImageH, ResultImageV, ResultImageH);
            ResultImage = ResultImageH;
        }
        #endregion

        UMat grayImage = new UMat();

        CvInvoke.CvtColor(ResultImage, bgrImage, ColorConversion.Hsv2Bgr);
        CvInvoke.CvtColor(bgrImage, grayImage, ColorConversion.Bgr2Gray);

        hsvImage.Dispose();
        bgrImage.Dispose();

        return grayImage;

    }

    /// <summary>
    /// Method to define the upper and lower values of the channels of HSV image
    /// </summary>
    /// <param name="hsvImage">Image in HSV and Byte format</param>
    /// <param name="lower">Lower value to be applied</param>
    /// <param name="upper">Upper value to be applied</param>
    /// <returns>Grayscale image with the applied range</returns>
    private UMat inRangeImage(UMat hsvImage, int lower, int upper)
    {
        UMat resultImage = new UMat();
        UMat lowerBorder = new UMat(hsvImage.Rows, hsvImage.Cols, DepthType.Cv8U, 3);
        UMat upperBorder = new UMat(hsvImage.Rows, hsvImage.Cols, DepthType.Cv8U, 3);

        lowerBorder.SetTo(new Gray(lower).MCvScalar);
        upperBorder.SetTo(new Gray(upper).MCvScalar);

        CvInvoke.InRange(hsvImage, lowerBorder, upperBorder, resultImage);

        // Dispose the image due to causing memory leaking.
        lowerBorder.Dispose();
        upperBorder.Dispose();

        return resultImage;

    }

【问题讨论】:

    标签: c# emgucv hsv


    【解决方案1】:

    在 Emgu.CV 中对我来说似乎是一个错误,因为我看到了相同的行为。

    尝试像这样使用 CvInvoke.Split():

    private UMat CvAndHsvImage(Image<Bgra, Byte> imgFrame, byte lowerHue, byte upperHue, byte lowerSat, byte upperSat, byte lowerBright, byte upperBright,
        byte erosion = 0, byte dilate = 0, bool hue = false, bool sat = false, bool bright = false, bool invert = false)
    {
        // <snip>
    
        // Final image that will be returned.
        UMat ResultImage = new UMat();
        UMat ResultImageH = new UMat();
        UMat ResultImageS = new UMat();
        UMat ResultImageV = new UMat();
    
        // << Replaced this >>
        // UMat[] hsvChannels = new UMat[3];
        // hsvChannels = hsvImage.Split();
        // << with this >>
        VectorOfUMat hsvChannels = new VectorOfUMat();
        CvInvoke.Split(hsvImage, hsvChannels);
    
        // </snip>
    }
    

    此方法似乎按预期提供了 CV_8UC1 UMats。

    【讨论】:

    • 感谢您的回答。该方法有效,但是当我尝试使用.SetTo 方法定义UMat 的值时出现错误:“尝试读取或写入受保护的内存”。但是,我设法找到了另一种方法来做到这一点。在将Image&lt;&gt; 转换为UMat 图像格式后,我创建了新的Image&lt;Hsv, Byte&gt; 并设置了值。我不知道这是否是最好的方法,因为它需要大量的处理能力,但它确实有效。
    • 没问题。不过,我无法在 SetTo 中重现访问冲突。如果它们是恒定的,我认为你不需要 UMats 的下限和上限。试试 CvInvoke.InRange(hsvImage, new ScalarArray(lower), new ScalarArray(upper), resultImage);
    • 感谢您的宝贵时间。我再次遇到同样的错误。目前,我正在使用 Image&lt;Hsv, Byte&gt; 进行此操作,并且它正在工作(您可以使用 UI 中的滑块更改值)但是,我想使用 UMat 尝试它,因为我读到它可以提高图像处理的性能。 link(看最后)
    猜你喜欢
    • 2015-08-11
    • 2013-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 2019-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多