C#描述-计算机视觉OpenCV(4):图像分割

本文介绍了如何使用C#和OpenCV库中的GrabCut算法对图像进行分割,通过实例展示了如何创建模型、定义检测区域以及处理分割结果,最终实现了从原始图像中准确切割前景物体。
摘要由CSDN通过智能技术生成

C#描述-计算机视觉OpenCV(4):图像分割

前言

本文中如果有什么没说明的地方,大概率在前文中描述过了。
C#描述-计算机视觉OpenCV(1):基础操作
C#描述-计算机视觉OpenCV(2):图像处理
C#描述-计算机视觉OpenCV(3):重映射
上一章节我们通过波形来分析了图像,那么图像中的背景与主体在波形上会有怎样的呈现呢?

for (int k = 120; k < 400; k++)
            {
                int r = 390;
                XList4.Add(k);
                YList4.Add(img.At<Vec3b>(r, k)[1]);
                chart2.Series["Green"].Points.DataBindXY(XList4, YList4);
                XList5.Add(k);
                YList5.Add(img.At<Vec3b>(r, k)[2]);
                chart2.Series["Blue"].Points.DataBindXY(XList5, YList5);
                XList6.Add(k);
                YList6.Add(img.At<Vec3b>(r, k)[0]);
                chart2.Series["Red"].Points.DataBindXY(XList6, YList6);
                img.At<Vec3b>(r, k)[0] = 0;
                img.At<Vec3b>(r, k)[1] = 0;
                img.At<Vec3b>(r, k)[2] = 0;//检测线标记
            }

我们标记一条检测线并示波
在这里插入图片描述
色彩波形结果:
在这里插入图片描述

这种差别以为着我们可以通过数值的变化来捕捉图片中的物体,并且做出分割。

用 GrabCut 算法分割图像

物体通常有自己特有的颜色,通过识别颜色接近的区域,通常可以提取出这些颜色。OpenCV 提供了一种常用的图像分割算法,即 GrabCut 算法。GrabCut 算法比较复杂,计算量也很大,但结果通常很精确。如果要从静态图像中提取前景物体(例如从图像中剪切一个物体,并粘贴到另一幅图像),最好采用GrabCut 算法。
算法参数模型:
cv::Mat result; // 分割结果(四种可能的值)
cv::Mat bgModel,fgModel; // 模型(内部使用)
// GrabCut 分割算法
cv::grabCut(
image, // 输入图像
mask, // 分割结果
rectangle, // 包含前景的矩形
bgModel,fgModel, // 模型
X, // 迭代次数
cv::GC_INIT_WITH_RECT // 使用矩形
);
首先我们开出需要的模型:

Mat mask = new Mat();
Mat bgM = new Mat();
Mat fgM = new Mat();

然后我们定义一个检测矩形区域:

Rect rectangle;
rectangle = new Rect(int X,int Y,int Width,int Height);

然后我们可以代入一个图像,使用GrabCut()方法,

Cv2.GrabCut(image, mask, rectangle, bgM, fgM, 5, GrabCutModes.InitWithRect);

并获得一个结果Mat类 mask。需要注意:这个mask可不代表分割完成的结果。
我们在函数的中用 InitWithRect 标志作为最后一个参数,表示将使用
带边框的矩形模型。矩形中输入/输出的分割图像可以是以下四个值之一。
1.GC_BGD:这个值表示明确属于背景的像素(例如本例中矩形之外的像素)。
2.GC_FGD:这个值表示明确属于前景的像素(本例中没有这种像素)。
3.GC_PR_BGD:这个值表示可能属于背景的像素。
4.GC_PR_FGD:这个值表示可能属于前景的像素(即本例中矩形之内像素的初始值)
也就是说我们的mask是一个判断是否为主题的结果的矩阵,我们还需要来操作读取才能完成图像分割,那么具体该如何操作呢?

实例展示

原图如下:
在这里插入图片描述
我们选取区域(200, 45, 150, 400)来做切割,这里面主体与背景非常清晰。

public void ColorDetector(Mat image)
        {
            Mat mask = new Mat();
            Mat bgM = new Mat();
            Mat fgM = new Mat();
            Rect rectangle;
            
            rectangle = new Rect(200, 45, 150, 400);
            Cv2.GrabCut(image, mask, rectangle, bgM, fgM, 5, GrabCutModes.InitWithRect);

            Mat result = new Mat(mask.Rows, mask.Cols, MatType.CV_8UC1);
            for (int i = 0; i < mask.Rows; i++)
            {
                for (int j = 0; j < mask.Cols; j++)
                {
                    byte v = mask.Get<byte>(j, i);
                    switch (v)
                    {
                        case 0:
                            result.Set<byte>(j, i, 0);
                            break;
                        case 1:
                            result.Set<byte>(j, i, 255);
                            break;
                        case 2:
                            result.Set<byte>(j, i, 50);
                            break;
                        case 3:
                            result.Set<byte>(j, i, 200);
                            break;
                    }
                }
            }
            Cv2.ImShow("grab", result);
        }

我们划分出四个结果类型的区域,来看看分割的是否准确:
在这里插入图片描述
通过色块可以看到,我们还是切割出来了的,找到我们需要的色块类型,进行还原,并将其他色块统一:

for (int i = 0; i < mask.Rows; i++)
            {
                for (int j = 0; j < mask.Cols; j++)
                {
                    byte v = mask.Get<byte>(j, i);
                    switch (v)
                    {
                        case 0:
                            result.Set<byte>(j, i, 0);
                            
                            break;
                        case 1:
                            result.Set<byte>(j, i, 0);
                           
                            break;
                        case 2:
                          
                            result.Set<byte>(j, i, 0);
                            break;
                        case 3:
                            result.At<Vec3b>(j, i)[0] = image.At<Vec3b>(j, i)[0];
                            result.At<Vec3b>(j, i)[1] = image.At<Vec3b>(j, i)[1];
                            result.At<Vec3b>(j, i)[2] = image.At<Vec3b>(j, i)[2];
                            //result.Set<byte>(j, i, 200);
                            break;
                    }
                }
            }

在这里插入图片描述
分割成功!

  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
OpenCV(Open Source Computer Vision Library)是一个跨平台的计算机视觉和机器学习软件库,提供了丰富的图像处理和计算机视觉算法。C#语言可以通过OpenCVSharp等第三方库来使用OpenCVOpenCVSharp是一个非常流行的OpenCVC#封装库,它提供了一组C#封装的OpenCV库的API,可以在C#中方便地使用OpenCV的功能。使用OpenCVSharp,您可以访问OpenCV的所有主要模块,包括图像处理,计算机视觉,机器学习等。 下面是OpenCVSharp的一个例子,它演示了如何读取图像、转换图像并在图像上绘制矩形: ``` using OpenCvSharp; class Program { static void Main(string[] args) { Mat src = new Mat("image.jpg", ImreadModes.Color); Mat gray = new Mat(); Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); CascadeClassifier classifier = new CascadeClassifier("haarcascade_frontalface_default.xml"); Rect[] faces = classifier.DetectMultiScale(gray); foreach (Rect rect in faces) { Cv2.Rectangle(src, rect, new Scalar(0, 255, 0), 2); } Cv2.ImShow("result", src); Cv2.WaitKey(0); } } ``` 在这个例子中,我们首先读取一张彩色图像 `image.jpg`,然后将其转换为灰度图像。接着,我们使用 `CascadeClassifier` 类检测灰度图像中的人脸,并在图像上绘制矩形。最后,我们显示结果图像并等待用户按下任意键关闭窗口。 这只是OpenCVSharp的一个简单示例,OpenCVSharp还提供了很多其他功能,例如图像处理、图像分割、特征提取、目标跟踪、机器学习等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值