在 Emgu 包装器中使用 UMat
Working with UMat in Emgu wrapper
我制作了一个应用程序,我将 HSV 滤镜应用于图像,然后尝试跟踪特定颜色。我想使用 UMat,因为我需要在 GPU 中而不是在 CPU 中计算图像。
在下面的代码中,我首先采用 Image<Bgra, Byte>
,然后将其转换为具有 HSV 颜色格式的 UMat
格式。但是,当我拆分频道时,每个频道有 3 个频道(例如 hsvChannels[0] 有三个频道;我不知道为什么会这样)。最后,我无法应用过滤器,因为当我使用 inRangeImage
方法时,我得到了一个具有一个通道和错误形式的图像 CvInvoke.Copy
"Unknown array format".
该应用程序不是最好的,但我想先了解 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;
}
我认为 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。
我制作了一个应用程序,我将 HSV 滤镜应用于图像,然后尝试跟踪特定颜色。我想使用 UMat,因为我需要在 GPU 中而不是在 CPU 中计算图像。
在下面的代码中,我首先采用 Image<Bgra, Byte>
,然后将其转换为具有 HSV 颜色格式的 UMat
格式。但是,当我拆分频道时,每个频道有 3 个频道(例如 hsvChannels[0] 有三个频道;我不知道为什么会这样)。最后,我无法应用过滤器,因为当我使用 inRangeImage
方法时,我得到了一个具有一个通道和错误形式的图像 CvInvoke.Copy
"Unknown array format".
该应用程序不是最好的,但我想先了解 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;
}
我认为 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。