版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
本文的VB版本请访问:图像分割-Grabcut法-CSDN博客
GrabCut是一种基于图像分割的技术,它可以用于将图像中的前景和背景分离。在实现中,GrabCut算法通常需要使用高斯混合模型(GMM)来建立前景和背景的概率分布,以便更好的估计像素的标签。同时,还需要考虑如何处理边界处的像素,以避免边界处的像素被错误地分类。GrabCut算法在图像分割中有着广泛的应用,例如人像分割、物体抠图等。
EmguCV使用CvInvoke.GrabCut方法来执行GrabCut算法,该方法声明如下:
public static void GrabCut(
IInputArray img,
IInputOutputArray mask,
Rectangle rect,
IInputOutputArray bgdModel,
IInputOutputArray fgdModel,
int iterCount,
GrabcutInitType type
)
参数说明:
- img:输入输出的图像,必须是三通道彩色图像。
- mask:指定的掩码图像,必须是单通道灰度图像,并且与输入图像具有相同的尺寸。可以传入0-3的值,分别为:0表示明显为背景的像素、1表示冥相位前景的像素、2表示可能为背景的像素、3表示可能为前景的像素。
- rect:指定的矩形框,用于定位大概率可能为前景目标的位置。
- bgdModel:背景模型,必须是单通道浮点型Mat。
- fgdModel:前景模型,必须是单通道浮点型Mat。
- iterCount:迭代次数,用于控制算法的收敛性。
- type:GrabCut算法初始化类型,可以选择GrabCutInitType.WithRect或GrabCutInitType.WithMask,分别表示根据提供的矩形初始化或根据掩码初始化。
该方法没有返回值,而是直接在mask图像上进行前景分割操作,最终获得的mask包含0-3的值,含义如参数中说明。
//Grabcut法
private void Button5_Click(object sender, EventArgs e)
{
Mat m = new Mat("C:\\learnEmgucv\\tower.jpg", ImreadModes.AnyColor);
Mat result = new Mat();
Mat bg = new Mat();
Mat fg = new Mat();
Rectangle rect = new Rectangle(80, 30, 680, 450);
CvInvoke.GrabCut(m, result, rect, bg, fg, 1, GrabcutInitType.InitWithRect);
//输出的result只有4个值:
//0:确定背景
//1:确定前景
//2:可能背景
//3:可能前景
//演示框选范围
CvInvoke.Rectangle(m, rect, new MCvScalar(255, 255, 255), 1);
ImageBox1.Image = m;
//标记区域
Matrix<byte> matr = new Matrix<byte>(result.Rows, result.Cols);
result.CopyTo(matr);
for (int i = 0; i < matr.Cols; i++)
{
for (int j = 0; j < matr.Rows; j++)
{
//将确定背景和可能背景标记为0,否则为255
if (matr[j, i] == 0 || matr[j, i] == 2)
matr[j, i] = 0;
else
matr[j, i] = 255;
}
}
Mat midm = new Mat();
midm = matr.Mat;
//显示标记的图像
CvInvoke.Imshow("midm", midm);
//灰度转为彩色
Mat midm1 = new Mat();
CvInvoke.CvtColor(midm, midm1, ColorConversion.Gray2Bgr);
Mat mout = new Mat();
//And运算
CvInvoke.BitwiseAnd(m, midm1, mout);
CvInvoke.Imshow("mout", mout);
}
输出结果如下图所示:
图8-5 Grabcut法分离前景
//Grabcut法
private void Button6_Click(object sender, EventArgs e)
{
Mat m = CvInvoke.Imread("C:\\learnEmgucv\\tower.jpg", ImreadModes.Color);
Mat result = new Mat();
Mat bg = new Mat();
Mat fg = new Mat();
Rectangle rect = new Rectangle(80, 30, 680, 450);
CvInvoke.GrabCut(m, result, rect, bg, fg, 5, GrabcutInitType.InitWithRect);
Image<Bgr, byte> src = m.ToImage<Bgr, byte>();
Image<Bgr, byte> dst = new Image<Bgr, byte>(new Size(src.Width, src.Height));
Image<Gray, byte> mask = result.ToImage<Gray, byte>();
//直接操作Image像素点
for (int i = 0; i < src.Rows; i++)
{
for (int j = 0; j < src.Cols; j++)
{
//如果是确定前景和可能前景,直接保留原像素点颜色,否则为黑色
if (mask.Data[i, j, 0] == 1 || mask.Data[i, j, 0] == 3)
{
dst.Data[i, j, 0] = src.Data[i, j, 0];
dst.Data[i, j, 1] = src.Data[i, j, 1];
dst.Data[i, j, 2] = src.Data[i, j, 2];
}
else
{
dst.Data[i, j, 0] = 0;
dst.Data[i, j, 1] = 0;
dst.Data[i, j, 2] = 0;
}
}
}
ImageBox1.Image = dst;
}
输出结果如下图所示:
图8-6 Grabcut法分离前景
//标记为确定前景,这里使用InitWithMask 参数
private void Button7_Click(object sender, EventArgs e)
{
Mat m = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);
Mat mask = new Mat();
Mat bg = new Mat();
Mat fg = new Mat();
Rectangle rect = new Rectangle(80, 30, 340, 480);
//使用前景为全白色
Mat m1 = new Mat("c:\\learnEmgucv\\lena_fillwhite.jpg", ImreadModes.Grayscale);
Mat mask1 = new Mat();
//二值化
CvInvoke.Threshold(m1, mask1, 250, 1, ThresholdType.Binary);
CvInvoke.Rectangle(m, rect, new MCvScalar(255, 255, 255), 1);
//标记之后再调用GrabCut,使用InitWithMask参数
CvInvoke.GrabCut(m, mask1, rect, bg, fg, 2, GrabcutInitType.InitWithMask);
Matrix<byte> matrx = new Matrix<byte>(mask1.Rows, mask1.Cols);
mask1.CopyTo(matrx);
for (int i = 0; i < matrx.Cols; i++)
for (int j = 0; j < matrx.Rows; j++)
if (matrx[i, j] == 0 || matrx[i, j] == 2)
matrx[i, j] = 0;
else
matrx[i, j] = 255;
Mat midm2 = new Mat();
midm2 = matrx.Mat;
Mat midm1 = new Mat();
CvInvoke.CvtColor(midm2, midm1, ColorConversion.Gray2Bgr);
Mat mout = new Mat();
CvInvoke.BitwiseAnd(m, midm1, mout);
CvInvoke.Imshow("mout", mout);
}
输出结果如下图所示:
图8-7 Grabcut法分离前景
由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。
学习更多vb.net知识,请参看vb.net 教程 目录