C# 在Emgu wrapper中使用UMat

C# 在Emgu wrapper中使用UMat,c#,emgucv,hsv,C#,Emgucv,Hsv,我已经做了一个应用程序,我将HSV过滤器应用于图像,然后尝试跟踪特定的颜色。我想使用UMat,因为我需要在GPU中计算图像,而不是在CPU中 在下面的代码中,我首先拍摄一张图像,然后用HSV颜色格式转换成UMat格式。但是,当我分割通道时,每个通道有3个通道(例如,HSV通道[0]有三个通道;我不知道为什么会发生这种情况)。最后,我无法应用过滤器,因为当我使用inRangeImage方法时,我得到一个带有一个通道的图像,错误形式为CvInvoke.Copy“未知数组格式” 该应用程序不是最好的,

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

在下面的代码中,我首先拍摄一张
图像
,然后用HSV颜色格式转换成
UMat
格式。但是,当我分割通道时,每个通道有3个通道(例如,HSV通道[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;

    }
private UMat CvAndHsvImage(图像imgFrame,字节lowerHue,字节upperHue,字节lowerSat,字节upperSat,字节lowerBright,字节upperBright,
字节腐蚀=0,字节扩展=0,布尔色调=假,布尔饱和度=假,布尔亮度=假,布尔反转=假)
{
//首先将输入图像转换为hsv,以便我们可以更改频道
//Image hsvImage=imgFrame.Convert();
UMat hsvImage=新的UMat();
UMat bgrImage=新的UMat();
CvInvoke.CvtColor(imgFrame、bgrImage、ColorConversion.Bgra2Bgr);
CvInvoke.CvtColor(bgrImage、hsvImage、ColorConversion.Bgr2Hsv);
//将返回的最终图像。
UMat ResultImage=新的UMat();
UMat ResultImageH=新的UMat();
UMat ResultImageS=新的UMat();
UMat ResultImageV=新的UMat();
UMat[]hsvChannel=新UMat[3];
hsvChannel=hsvImage.Split();
UMat img1=范围图像(HSV通道[0],低色调,高色调);
UMat img2=范围图像(HSV通道[1],低卫星,高卫星);
UMat img3=范围图像(HSV通道[2],右下,上亮);
#区域复选框颜色模式
//评估每个筛选器的复选框。返回正确的图像
如果(色调)
{
CvInvoke.cvCopy(img1,ResultImageH,IntPtr.Zero);
}
国际单项体育联合会(星期六)
//结果年龄=img2;
CvInvoke.cvCopy(img2,ResultImageS,IntPtr.Zero);
如果(明亮)
//ResultImageV=img3;
CvInvoke.cvCopy(img3,ResultImageS,IntPtr.Zero);
if(色调和亮度)
结果年龄=结果年龄H;
如果(!色调和饱和度和亮度)
结果年龄=结果年龄;
如果(!色调&&!色差&&bright)
ResultImage=ResultImageV;
if(色调和饱和度和亮度)
{
CvInvoke.BitwiseAnd(ResultImageH,ResultImageS,ResultImageH);
结果年龄=结果年龄H;
}
if(色调和亮度)
{
CvInvoke.BitwiseAnd(ResultImageH,ResultImageV,ResultImageH);
结果年龄=结果年龄H;
}
如果(!色调和饱和度和亮度)
{
CvInvoke.BitwiseAnd(ResultImageS、resultimagesv、ResultImageS);
结果年龄=结果年龄;
}
if(色调和饱和度和亮度)
{
CvInvoke.BitwiseAnd(ResultImageH,ResultImageS,ResultImageH);
CvInvoke.BitwiseAnd(ResultImageH,ResultImageV,ResultImageH);
结果年龄=结果年龄H;
}
#端区
UMat grayImage=新的UMat();
CvInvoke.CvtColor(ResultImage、bgrImage、ColorConversion.Hsv2Bgr);
CvInvoke.CvtColor(bgrImage、grayImage、ColorConversion.Bgr2Gray);
hsvImage.Dispose();
bgrImage.Dispose();
返回灰度图像;
}
/// 
///定义HSV图像通道上下值的方法
/// 
///HSV和字节格式的图像
///要应用的较低值
///要应用的上限值
///具有应用范围的灰度图像
专用UMat inRangeImage(UMat hsvImage、整数下限、整数上限)
{
UMat resultImage=新的UMat();
UMat lowerBorder=新的UMat(hsvImage.Rows,hsvImage.Cols,DepthType.Cv8U,3);
UMat上边界=新的UMat(hsvImage.Rows,hsvImage.Cols,DepthType.Cv8U,3);
较低的顺序。设置为(新的灰色(较低的)。MCvScalar);
上边框。设置为(新灰色(上)。MCvScalar);
CvInvoke.InRange(hsvImage,小写,大写,resultImage);
//由于导致内存泄漏,请处理映像。
lowerBorder.Dispose();
upperBorder.Dispose();
返回结果年龄;
}

在Emgu.CV中,它看起来像一个bug,因为我看到了相同的行为

请尝试使用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>
}
private UMat CvAndHsvImage(图像imgFrame,字节lowerHue,字节upperHue,字节lowerSat,字节upperSat,字节lowerBright,字节upperBright,
字节腐蚀=0,字节扩展=0,布尔色调=假,布尔饱和度=假,布尔亮度=假,布尔反转=假)
{
// 
//将返回的最终图像。
UMat ResultImage=新的UMat();
UMat ResultImageH=新的UMat();
UMat ResultImageS=新的UMat();
UMat ResultImageV=新的UMat();
// >
//UMat[]hsvChannel=新UMat[3];
//hsvChannel=hsvImage.Split();
// >
VectorOfMat HSV通道=新VectorOfMat();
CvInvoke.Split(hsvImage、hsvChannels);
// 
}

此方法似乎可以提供预期的CV_8UC1 UMAT。

感谢您的回答。该方法有效,但是,当我尝试使用
.SetTo
方法“尝试读取或写入受保护内存”定义
UMat
的值时,出现了一个错误。然而,我设法找到了另一种方法。我创建了新的
图像
,并在将
图像
转换为
UMat
图像格式后设置了值。我不知道这是否是最好的方法,因为它需要大量的处理能力,但是,它起作用了。没问题。不过,我无法在SetTo中重现访问冲突。我想你不需要这个