版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
本文的VB版本请访问:图像分割 分水岭法 watershed-CSDN博客
Watershed算法是一种图像处理算法,它是基于形态学的图像分割方法。在实现中,Watershed算法通常需要先对图像进行预处理,例如去除噪声、边缘检测等操作,以便更好的构建隔板。在填充山谷时,可以使用队列或其他数据结构来实现,以便管理待处理的像素。对于连通的区域,可以使用标记或者颜色来区分。最终得到的分割结果可以用于物体识别、形状分析等应用场景。
CvInvoke.Watershed方法用于执行图像的分水岭分割操作。该方法声明如下:
public static void Watershed(
?????????? IInputArray image,
?????????? IInputOutputArray markers
)
参数说明:
该方法没有返回值,而是直接在markers图像上进行分割操作。最终输出的图像,两个区域间使用-1作为分割线。
//分水岭法 watershed
private void Button4_Click(object sender, EventArgs e)
{
Mat m = new Mat("c:\\learnEmgucv\\tower.jpg", ImreadModes.Color);
//灰度
Mat mgray = new Mat();
CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray);
//滤波
Mat mgaussian = new Mat();
CvInvoke.GaussianBlur(mgray, mgaussian, new Size(5, 5), 2);
ImageBox1.Image = mgaussian;
//边缘检测
Mat mcanny = new Mat();
CvInvoke.Canny(mgaussian, mcanny, 60, 120);
//ImageBox2.Image = mcanny;
//获取轮廓
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
VectorOfRect hierarchy = new VectorOfRect();
CvInvoke.FindContours(mcanny, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
Mat mmark = new Mat();
mmark = Mat.Zeros(mcanny.Rows, mcanny.Cols, DepthType.Cv32S, 1);
//仅为查看轮廓使用
Mat mcontours = new Mat(mcanny.Rows, mcanny.Cols, DepthType.Cv8U, 1);
for (int i = 0; i < contours.Size; i++)
{
//标记连通分量索引
CvInvoke.DrawContours(mmark, contours, i, new MCvScalar(i), 1, LineType.EightConnected, hierarchy);
//仅为查看轮廓使用
CvInvoke.DrawContours(mcontours, contours, i, new MCvScalar(255), 1, LineType.EightConnected, hierarchy);
}
//仅为查看轮廓使用
CvInvoke.Imshow("mcontours", mcontours);
//mmark是32S,显示不了的
//CvInvoke.Imshow("mmark", mmark);
//分水岭法
CvInvoke.Watershed(m, mmark);
//仅演示,watershed后的数据
Mat mc = new Mat();
mc = mmark.Clone();
//转为可以显示的CV8U
mc.ConvertTo(mc, DepthType.Cv8U);
CvInvoke.Imshow("mc", mc);
//使用Matrix和Image便于生成图像(Mat操作像素点比较麻烦)
Matrix<Int32> matrwater = new Matrix<Int32>(mmark.Rows, mmark.Cols);
mmark.CopyTo(matrwater);
Image<Bgr, byte> imgwater = new Image<Bgr, byte>(mmark.Cols, mmark.Rows);
//为每个区域填充不同的颜色
Hashtable HSpointcolor = new Hashtable(); //index,bgr
int count = 0;
//对每个像素点操作
for (int i = 0; i < matrwater.Rows; i++)
{
for (int j = 0; j < matrwater.Cols; j++)
{
//获得连通分量(像素点值)
Int32 index = matrwater[i, j];
//如果是区域的分割线
if (index == -1)
{
imgwater.Data[i, j, 0] = 255;
imgwater.Data[i, j, 1] = 255;
imgwater.Data[i, j, 2] = 255;
}
else
{
Bgr pointcolor;
//检查是否已经存在索引对应的颜色
if (HSpointcolor.ContainsKey(index))
{
pointcolor = (Bgr)HSpointcolor[index];
}
else
{
//获得随机颜色
pointcolor = getRadomBgr();
//将已经使用的随机颜色加入List
HSpointcolor.Add(index, pointcolor);
count += 1;
}
//像素点填充颜色
imgwater.Data[i, j, 0] = (byte)pointcolor.Blue;
imgwater.Data[i, j, 1] = (byte)pointcolor.Green;
imgwater.Data[i, j, 2] = (byte)pointcolor.Red;
}
}
}
//输出使用分水岭法后的结果
CvInvoke.Imshow("imgwater", imgwater);
}
//获得随机颜色
private Bgr getRadomBgr()
{
Random rand = new Random(DateTime.Now.Millisecond);
byte b = (byte)rand.Next(0, 256);
byte g = (byte)rand.Next(0, 256);
byte r = (byte)rand.Next(0, 256);
return new Bgr(b, r, g);
}
输出结果如下图所示:
图8-4 分水岭法使用随机颜色填充
由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。
学习更多vb.net知识,请参看vb.net 教程 目录