当前位置:   article > 正文

OpenCV - C++实战(06) — Grabcut图像分割_opencv c++ grabcut对图片进行处理

opencv c++ grabcut对图片进行处理

目录

第6章  图像分割

6.1 Grabcut实现

6.1.1 定义前景和背景

6.1.2   cv::grabCut()

6.1.3 cv::compare()

6.1.4 算法实现
​​​​​​​


Github代码地址:GitHub - Qinong/OpenCV

第6章  图像分割

        Opencv提供了一种常用的图像分割算法Grabcut。Grabcut算法比较复杂,计算量也很大,但有很高的精确度。

6.1 Grabcut实现

6.1.1 定义前景和背景

        cv::grabCut函数的用法非常简单,只需要在输入图像做上 “属于背景”或“属于前最” 的标记即可。根据这个局部标记,算法将计算出整幅图像的前景/背景分割线。

        可以通过定义矩形指定输人图像局部前景/背景标签的。

  1. // 定义一个带边框的矩形
  2. // 矩形外部的像素会被标记为背景
  3. cv::Rect rectangle(100,120,650,350);

 

6.1.2   cv::grabCut()

        GrabCut算法的工作原理是:参考文章

接受输入图像与任一(1)的边界框,我们想段或(2)所涉及的图像中指定的对象的位置掩模即近似分割

        反复执行以下步骤:

        步骤1:通过高斯混合模型(GMM)估算前景和背景的颜色分布

        步骤2:在像素标签上构造一个马尔可夫随机场(即,前景与背景)

        步骤3:应用图割优化以进行最终细分

         GrabCut是Graph Cut的改进版,是迭代的Graph Cut。OpenCV中的GrabCut算法是依据《"GrabCut" - Interactive Foreground Extraction using Iterated Graph Cuts》这篇文章来实现的。该算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只要少量的用户交互操作即可得到比较好的分割结果。与Graph cut指定两个顶点不同,grabcut只需指定一个粗略的能将目标框住的边框就可以完成良好的分割。

        虽然神经网络的分割已经占据了主流,但是再很多情况下并不需要如此大力气的训练,所以GrabCut也是可选项之一。

  1. void grabCut( InputArray img,
  2. InputOutputArray mask,
  3. Rect rect,                        
  4. InputOutputArray bgdModel,
  5. InputOutputArray fgdModel,
  6. int iterCount,
  7. int mode = GC_EVAL );
  • img:输入图像
  • mask:得到掩码矩阵,其值为以下四种

             cv::GC_BGD  == 0//表示是背景

             cv::GC_FGD  == 1//表示是前景

              cv::GC_PR_BGD  == 2//表示可能是背景

              cv::GC_PR_FGD  == 3//表示可能是前景

  • rect:指定的包含目标对象的矩阵
  • bdgModel:背景模型,如果为null,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13*5
  • fgdModel:前景模型,如果为null,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;(bgdModel , fgdModel可以在 cv::GC_INIT_WITH_MASK下使用,可以在以往迭代的基础上用它们保存的信息继续迭代)
  • iterCount:指定迭代次数
  • mode:有三个值可用

          cv::GC_INIT_WITH_RECT//用矩阵初始化grabCut

          cv::GC_INIT_WITH_MASK//用掩码初始化grabCut

          cv::GC_EVAL//执行分割

6.1.3 cv::compare()

        cv::compare()主要用于两个图像之间进行逐像素的比较,并输出比较的结果。具体用法如下:

  1. bool cv::compare(cv::InputArray src1, // 输入数组1
  2.      cv::InputArray src2, // 输入数组2
  3.      cv::OutputArray dst, // 输出数组
  4.     int cmpop // 比较操作子,见注释 
  •     cmpop:比较操作子

        cv::CMP_EQ    src==src1
        cv::CMP_GT    src>src1
        cv::CMP_GE    src>=src1
        cv::CMP_LT    src<src1
        cv::CMP_LE    src<=src1
        cv::CMP_NE    src!=src1

6.1.4 算法实现

  1. int main()
  2. {
  3. cv::Mat image= cv::imread("Ferrar_F8.png");
  4. if (!image.data)
  5. return 0;
  6. cv::namedWindow("Image");
  7. cv::imshow("Image",image);
  8. // 定义边框矩形
  9. cv::Rect rectangle(100,120,650,350);
  10. // 定义前景、背景和分割结果
  11. cv::Mat bgModel,fgModel,result;
  12. // GrabCut分割
  13. cv::grabCut(image,
  14. result,
  15. rectangle,
  16. bgModel,
  17. fgModel,
  18. 5,
  19. cv::GC_INIT_WITH_RECT); // use rectangle
  20. // 标记可能属于前景的区域
  21. cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
  22. // or:
  23. // result= result&1;
  24. // 创建前景图像
  25. cv::Mat foreground(image.size(), CV_8UC3, cv::Scalar(255, 255, 255));
  26. image.copyTo(foreground,result); // 复制前景图像
  27. // 在原图像绘制矩形区域
  28. cv::rectangle(image, rectangle, cv::Scalar(200,0,200),4);
  29. cv::namedWindow("Rectangle");
  30. cv::imshow("Rectangle",image);
  31. cv::namedWindow("Foreground");
  32. cv::imshow("Foreground",foreground);
  33. cv::waitKey();
  34. return 0;
  35. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/285089
推荐阅读
相关标签
  

闽ICP备14008679号