OpenCvSharp函数:ConnectedComponents、ConnectedComponentsWithStats、ConnectedComponentsEx

二值图像分析时黑色(0)为背景,白色(非0)为前景

邻域、邻接

对于任意像素(x,y),把像素的集合{(x+p,y+q)}(p、q是一对适当的整数)叫做像素(x,y)的邻域。即像素(x,y)附近的像素形成的区域。

邻域是指某像素p的周围像素,p与他们间的欧式距离不超过“根号2”即对角线的距离。如果q在p的某种邻域中,则p,q为某种邻接。

4-邻域:即对于像素(x,y),上下左右4个像素称为4-邻域,即以下元素:(x-1,y)(x,y-1)(x+1,y)(x,y+1)。

D-邻域:即对于像素(x,y),其中(max-1>x>1,max-1>y>1)。其D-邻域为以下元素:(x-1,y-1)(x+1,y-1)(x-1,y+1)(x+1,y+1)。

8-邻域:即对于像素(x,y),其中(max-1>x>1,max-1>y>1),上下左右4个元素以及4个对角线像素,称为8-邻域。为以下元素:(x-1,y-1)(x-1,y)(x-1,y+1)(x,y-1)(x,y+1)(x+1,y-1)(x+1,y)(x+1,y+1)

OpenCvSharp函数:ConnectedComponents、ConnectedComponentsWithStats、ConnectedComponentsEx_第1张图片

二值图像的邻接

4-邻接:如果q点在p点的4-邻域集合中,则p,q为4-邻接。即互为4-邻域的两个像素叫4-邻接。

8-邻接:如果q点在p点的8-邻域集合中,则p,q为8-邻接。即互为8-邻域的两个像素叫8-邻接。

D-邻接:如果q点在p点的D-邻域集合中,则p,q为D-邻接

m-邻接:如果q在p的4-邻域中,或者q在p的D-邻域中,且q的4-邻域与p的4-邻域交集为空,则p,q为m-邻接。

m-邻域的目的是消除8-邻域的二义性。

联通组件:像素值相同,通过4-领域或8-邻域相互连通的像素块。

联通组件分析过程:

OpenCvSharp函数:ConnectedComponents、ConnectedComponentsWithStats、ConnectedComponentsEx_第2张图片

(图片来源于https://edu.csdn.net/learn/38286/608274)

  1. (左图)第一行:从左到右,从上到下,扫描白色(前景),像素(0,0)、(0,1)标记为联通块1;(0,2)不联通;(0,3)、(0,4)、(0,5)为新的联通块标为2;(0,6)不通道;(0,7)为新的联通块标为3;

  1. (左图)第二行:(1,0)、(1,1)与上一行联通也标为1,依次类推。

  1. (右图)等价类合并:高标识符与低标识符相联时,将高标识符合为低标识符,2合并为1,6合并为4,7合并为3

ConnectedComponents函数

//函数原型1
int ConnectedComponents(InputArray image,
    OutputArray labels,
    PixelConnectivity connectivity = PixelConnectivity.Connectivity8)

//函数原型2
int ConnectedComponents(InputArray image, 
    out int[,] labels, 
    PixelConnectivity connectivity)

//函数原型3
int ConnectedComponents(InputArray image,
    OutputArray labels,
    PixelConnectivity connectivity,
    MatType ltype)

ConnectedComponents获取不带统计信息的联通组件

返回值(int):返回标签总数N,[0,N-1],0为背景

参数

说明

InputArray image

待标记图像:8位单通道,黑色背景

OutputArray labels

输出标记图像:与输入图像大小一样,对应的联通区域会标记上对应的数字

0为背景,其它数字为对应的联通区域

PixelConnectivity connectivity

通联域:默认是8联通

MatType ltype

输出标记图像的类型:默认是CV_32S,还支持CV_16U

OpenCvSharp函数:ConnectedComponents、ConnectedComponentsWithStats、ConnectedComponentsEx_第3张图片

ConnectedComponentsWithStats函数

//函数原型1
int ConnectedComponentsWithStats(InputArray image,
    OutputArray labels,
    OutputArray stats,
    OutputArray centroids,
    PixelConnectivity connectivity,
    MatType ltype)

//函数原型2(ltype=CV_32S)
int ConnectedComponentsWithStats(InputArray image,
    OutputArray labels,
    OutputArray stats,
    OutputArray centroids,
    PixelConnectivity connectivity = PixelConnectivity.Connectivity8)

ConnectedComponentsWithStats获取带统计信息的通道组件

返回值(int):返回标签总数N,[0,N-1],0为背景

参数

说明

InputArray image

待标记图像:8位单通道,黑色背景

OutputArray labels

输出标记图像:与输入图像大小一样,对应的联通区域会标记上对应的数字

0为背景,其它数字为对应的联通区域

OutputArray stats

各通道组件信息(含背景):N*5*ltype

对应各个通道组件的外接矩形的x,y,width,height和像素点个数

OutputArray centroids

通道组件中心点位置:N*2*CV_64F

PixelConnectivity connectivity

通联域:默认是8联通

MatType ltype

输出标记图像的类型:默认是CV_32S,还支持CV_16U

OpenCvSharp函数:ConnectedComponents、ConnectedComponentsWithStats、ConnectedComponentsEx_第4张图片

ConnectedComponentsWithAlgorithm可指定算法的不带统计通道组件获取

//函数原型,多了ccltype参数,可指定通道组件分析算法,其它与ConnectedComponents相同
int ConnectedComponentsWithAlgorithm(InputArray image,
    OutputArray labels,
    PixelConnectivity connectivity,
    MatType ltype,
    ConnectedComponentsAlgorithmsTypes ccltype)

ConnectedComponentsWithStatsWithAlgorithm可指定算法的带统计通道组件获取

//函数原型,多了ccltype参数,可指定通道组件分析算法,其它与ConnectedComponentsWithStats相同
int ConnectedComponentsWithStatsWithAlgorithm(InputArray image,
    OutputArray labels,
    OutputArray stats,
    OutputArray centroids,
    PixelConnectivity connectivity,
    MatType ltype,
    ConnectedComponentsAlgorithmsTypes ccltype)

ConnectedComponentsEx对ConnectedComponentsWithStatsWithAlgorithm封装

该函数是OpenCvSharp特有的?使用ConnectedComponents的Blob属性访问更便捷。

//函数源码
public static ConnectedComponents ConnectedComponentsEx(InputArray image,
    PixelConnectivity connectivity = PixelConnectivity.Connectivity8,
    ConnectedComponentsAlgorithmsTypes ccltype = ConnectedComponentsAlgorithmsTypes.Default)
{
    using Mat mat = new Mat();
    using Mat mat2 = new Mat();
    using Mat mat3 = new Mat();
    int num = ConnectedComponentsWithStatsWithAlgorithm(image, mat, mat2, mat3, connectivity, 4, ccltype);
    int[,] labels = mat.ToRectangularArray();
    int[,] array = mat2.ToRectangularArray();
    double[,] array2 = mat3.ToRectangularArray();
    ConnectedComponents.Blob[] array3 = new ConnectedComponents.Blob[num];
    for (int i = 0; i < num; i++)
    {
        array3[i] = new ConnectedComponents.Blob
        {
            Label = i,
            Left = array[i, 0],
            Top = array[i, 1],
            Width = array[i, 2],
            Height = array[i, 3],
            Area = array[i, 4],
            Centroid = new Point2d(array2[i, 0], array2[i, 1])
        };
    }

    return new ConnectedComponents(array3, labels, num);
}
OpenCvSharp函数:ConnectedComponents、ConnectedComponentsWithStats、ConnectedComponentsEx_第5张图片

源码示例

public void Run(ParamBase paramBase)
{
    using var srcGray = Cv2.ImRead(ImagePath.Shapes, ImreadModes.Grayscale);
    if (srcGray.Empty()) throw new Exception("图像读取有误");
    Cv2.ImShow("srcGray", srcGray);

    //需要去除噪声的话,可应用相关的模糊函数
    Cv2.GaussianBlur(srcGray, srcGray, new Size(3, 3), 0);
    //用大律法二值化
    Cv2.Threshold(srcGray, srcGray, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);

    #region ConnectedComponents相关
    //通道组件标记
    using var labels = new Mat();
    //componentsCount=实际联通区域个数+1(背景)
    //labels大小与srcGray,在相同的联通区域标记为对应的数字(1至N-1)
    var componentsCount = Cv2.ConnectedComponents(srcGray, labels, PixelConnectivity.Connectivity8, MatType.CV_32S);
    //Cv2.ConnectedComponentsWithAlgorithm

    //生成随机颜色填充颜色
    List colors = new List();
    for (int i = 0; i < componentsCount; i++)
    {
        colors.Add(Scalar.RandomColor().ToVec3b());
    }
    //用于绘制结果
    Mat colorResult = Mat.Zeros(labels.Size(), MatType.CV_8UC3);
    for (int row = 0; row < labels.Rows; row++)
    {
        for (int col = 0; col < labels.Cols; col++)
        {
            //注意类型必须与labels.MatType一致
            var color = labels.At(row, col);//CV_32S
            //var color = labels.At(row, col);//CV_16U

            if (color == 0) continue;//为0是背景
            colorResult.At(row, col) = colors[color];
        }
    }
    Cv2.ImShow("ColorResult:ConnectedComponents", colorResult);
    #endregion

    #region ConnectedComponentsWithStats相关
    //各通道组件外接矩形信息(含背景)
    using var stats = new Mat();
    //各通道组件中心点信息(含背景)
    using var centroids = new Mat();
    componentsCount = Cv2.ConnectedComponentsWithStats(srcGray, labels, stats, centroids, PixelConnectivity.Connectivity8, MatType.CV_32S);
    //Cv2.ConnectedComponentsWithStatsWithAlgorithm

    colorResult = srcGray.CvtColor(ColorConversionCodes.GRAY2BGR);
    for (int i = 1; i < componentsCount; i++)
    {
        //通道组件的中心点
        Cv2.Circle(colorResult, new Point(centroids.At(i, 0), centroids.At(i, 1)), 2, Scalar.Blue, -1);
        //通道组件的外接矩形
        Cv2.Rectangle(colorResult, new Rect(stats.At(i, 0), stats.At(i, 1), stats.At(i, 2), stats.At(i, 3)), Scalar.Red);
    }
    Cv2.ImShow("ColorResult:ConnectedComponentsWithStats", colorResult);
    #endregion

    #region ConnectedComponentsEx对ConnectedComponentsWithStatsWithAlgorithm封装
    var componentsEx = Cv2.ConnectedComponentsEx(srcGray, PixelConnectivity.Connectivity8, ConnectedComponentsAlgorithmsTypes.Default);
    colorResult = srcGray.CvtColor(ColorConversionCodes.GRAY2BGR);
    foreach (var blob in componentsEx.Blobs)
    {
        //背景跳过
        if (blob.Label == 0) continue;
        //通道组件的中心点
        Cv2.Circle(colorResult, blob.Centroid.ToPoint(), 2, Scalar.Blue, -1);
        //通道组件的外接矩形
        Cv2.Rectangle(colorResult, blob.Rect, Scalar.Red);
    }
    Cv2.ImShow("ColorResult:ConnectedComponentsEx", colorResult);
    #endregion

    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

OpenCvSharp函数示例(目录)

参考

https://edu.csdn.net/learn/38286/608274

https://docs.opencv.org/

你可能感兴趣的:(OpenCvSharp函数,opencv,c#,图像处理)