C#+OpenCV基础(十五)_图像的基础分割方法

1、GrabCut人为干预分割前景

/// <summary>
/// 检测边缘并标注(GrabCut人为干预分割前景;速度比分水岭算法慢,结果准确性高)
/// </summary>
/// <param name="img">图片</param>
/// <param name="rect">前景物体矩形区域;new Rect(100, 100, 200, 200)</param>
/// <param name="dstMat">结果图片</param>
/// <param name="bgdModel">背景图</param>
/// <param name="fgdModel">前景图</param>
/// <param name="iterCount">迭代次数</param>
/// <param name="mode">初始化的模式;默认为矩形初始化</param>
public static Mat GrabCut(Mat img, Rect rect, out Mat dstMat,
    out Mat bgdModel, out Mat fgdModel, int iterCount = 1, GrabCutModes mode = GrabCutModes.InitWithRect)
{
    Mat dstMat1 = new Mat();

    dstMat = new Mat();
    bgdModel = new Mat();
    fgdModel = new Mat();

    Cv2.GrabCut(img, dstMat, rect, bgdModel, fgdModel, iterCount, mode);
    Cv2.Compare(img, dstMat, dstMat1, CmpType.EQ);

    return dstMat1;
}

2、漫水填充分割

/// <summary>
/// 检测边缘并标注(漫水填充;类似于PS的魔术棒,适合于对二值图处理)
/// </summary>
/// <param name="image">图片/结果图片</param>
///// <param name="mask">操作掩码;但是不会填充非零像素</param>
/// <param name="seedPoint">起始点</param>
/// <param name="newVal">被染色的值</param>
/// <param name="rect">设置重绘区域的最小边界矩形区域</param>
/// <param name="loDiff">最小色差值</param>
/// <param name="upDiff">最大色差值</param>
/// <param name="flags">操作标志位</param>
/// <returns></returns>
public static int FloodFill(InputOutputArray image, Point seedPoint, Scalar newVal, out Rect rect,
    Scalar? loDiff = null, Scalar? upDiff = null, FloodFillFlags flags = FloodFillFlags.Link4)
    => Cv2.FloodFill(image, seedPoint, newVal, out rect, loDiff, upDiff, flags);

3、分水岭分割

/// <summary>
/// 分水岭分割
/// </summary>
/// <param name="image">图片</param>
/// <param name="markers">掩码</param>
/// <returns></returns>
public static void Watershed(InputArray image, InputOutputArray markers) => Cv2.Watershed(image, markers);
/// <summary>
/// 检测边缘并标注(分水岭分割)
/// 先在外面找边缘-比如:先图像灰度化、再滤波、再Canny边缘检测;如使用MarginDetector_Sobel或者MarginDetector_Canny
/// 再传入原始图像和边缘信息
/// </summary>
/// <param name="image">图片</param>
/// <param name="points">轮廓集合</param>
/// <param name="hierarchy">历史轮廓</param>
/// <returns></returns>
public static Mat Watershed_Draw(Mat image, Point[][] points, HierarchyIndex[] hierarchy)
{
    Mat imageContours = Mat.Zeros(image.Size(), MatType.CV_8UC1);  // 轮廓
    Mat markers = new Mat(image.Size(), MatType.CV_32S);  // 第二个参数

    for (int index = 0; index < hierarchy.Length; index++)
    {
        Cv2.DrawContours(markers, points, index, Scalar.All(index + 1), 1, LineTypes.Link8, hierarchy);
        Cv2.DrawContours(imageContours, points, index, new Scalar(255), 1, LineTypes.Link8, hierarchy);
    }

    // 分水岭分割
    Cv2.Watershed(image, markers);

    // 填充颜色
    Mat perspectiveImage = new Mat(image.Size(), MatType.CV_8UC3);
    for (int i = 0; i < markers.Size().Height; i++)
    {
        for (int j = 0; j < markers.Size().Width; j++)
        {
            int index = markers.At<int>(i, j);
            if (index == -1)
            {
                perspectiveImage.At<Vec3b>(i, j) = new Vec3b(255, 255, 255);
            }
            else
            {
                perspectiveImage.At<Vec3b>(i, j) = RandomColor(index);
            }
        }
    }
    Mat wshed = new Mat();
    Cv2.AddWeighted(image, 0.4, perspectiveImage, 0.6, 0, wshed);
    return wshed;
}

/// <summary>
/// 随机颜色
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private static Vec3b RandomColor(int index)
{
    int value = index % 255;  // 0~255随机数

    Random random = new Random();
    byte aa = Convert.ToByte(random.Next(0, value));
    byte bb = Convert.ToByte(random.Next(0, value));
    byte cc = Convert.ToByte(random.Next(0, value));

    return new Vec3b(aa, bb, cc);
}
posted @ 2024-07-11 10:36  ꧁执笔小白꧂  阅读(73)  评论(0编辑  收藏  举报