首页 > 其他分享 >37.图像分割

37.图像分割

时间:2023-04-11 17:34:40浏览次数:41  
标签:分割 函数 int 37 算法 参数 图像

1、Grabcut图像分割

代码清单8-21 grabCut()函数原型
void cv::grabCut(InputArray  img,
                 InputOutputArray  mask,
                 Rect  rect,
                 InputOutputArray  bgdModel,
                 InputOutputArray  fgdModel,
                 int  iterCount,
                 int  mode = GC_EVAL 
                 )
  • img:输入的待分割图像,数据类型为CV_8U的三通道图像。
  • mask:用于输入、输出的CV_8U单通道掩码图像,图像中像素值的取值范围以及含义在表8-4给出。
  • rect:包含对象的ROI区域,该参数仅在mode == GC_INIT_WITH_RECT时使用。
  • bgdModel:背景模型的临时数组。
  • fgdModel:前景模型的临时数组。
  • iterCount:算法需要进行的迭代次数。
  • mode:分割模式标志,该参数值可选择范围以及含义在表8-5给出。

  该函数实现了GrabCut图像分割算法,函数的第一个参数是待分割的输入图像,要求是CV_8U的三通道彩色图像。第二个参数是掩码矩阵,该参数既用于输入又用于输出,当最后一个参数设置为GC_INIT_WITH_RECT时,该矩阵会被设置为初始掩码,掩码矩阵中具有4个可选择的参数,分别是0(GC_BGD)表示明显为背景的像素、1(GC_FGD)表示明显为前景或者对象的像素、2(GC_PR_BGD)表示疑似背景的像素、3(GC_PR_FGD)表示疑似前景或者对象的像素。最后图像的分割结果也是通过分析掩码矩阵中每个像素的数值进行提取。函数第三个参数是需要进行分割去ROI区域,在ROI区域的外部会被标记为“明显的背景”区域,该参数尽在mode == GC_INIT_WITH_RECT时使用。函数第四个和第五个参数分别是背景模型、前景模型的临时数组,需要注意的是在处理同一图像时,请勿对它进行修改。函数第六个参数是算法进行迭代的次数。函数最后一个参数是分割模式标志,可以选择的参数及其含义在表8-5给出。

  为了了解该函数的使用方法以及对图像的分割效果,在代码清单8-22中给出了通过grabCut()函数对图像进行分割的示例程序。程序中首先在原图像中选择ROI矩形区域,之后利用grabCut()函数对该区域分割,计算前景和背景,最后将掩码矩阵中明显是前景和疑似前景的像素点全部输出,程序运行结果如图8-14所示。需要说明的是程序中为了保证绘制矩形框不对图像分割产生影响,在绘制矩形框时对原图像进行了深拷贝。

代码清单8-22 myGrabCut.cpp利用grabCuts方法图像分割
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    Mat img = imread("lena.png");
    if (!img.data)  //防止错误读取图像
    {
        cout<<"读取图像错误,请确认图像文件是否正确" << endl; 
        return 0;
    }

    //绘制矩形
    Mat imgRect;
    img.copyTo(imgRect);  //备份图像,方式绘制矩形框对结果产生影响
    Rect rect(80, 30, 340, 390);
    rectangle(imgRect, rect, Scalar(255, 255, 255),2);
    imshow("选择的矩形区域", imgRect);

    //进行分割
    Mat bgdmod = Mat::zeros(1, 65, CV_64FC1);
    Mat fgdmod = Mat::zeros(1, 65, CV_64FC1);
    Mat mask = Mat::zeros(img.size(), CV_8UC1);
    grabCut(img, mask, rect, bgdmod, fgdmod, 5, GC_INIT_WITH_RECT);
    
    //将分割出的前景绘制回来
    Mat result;
    for (int row = 0; row < mask.rows; row++) 
    {
        for (int col = 0; col < mask.cols; col++) 
        {
            int n = mask.at<uchar>(row, col);
            //将明显是前景和可能是前景的区域都保留
            if (n == 1 || n == 3) 
            {
                mask.at<uchar>(row, col) = 255;
            }
            //将明显是背景和可能是背景的区域都删除
            else 
            {
                mask.at<uchar>(row, col) = 0;
            }
        }
    }
    bitwise_and(img, img, result, mask);
    imshow("分割结果", result);
    waitKey(0);
    return 0;
}

2、Mean-Shift分割算法

  Mean-Shift算法又被称为均值漂移法,是一种基于颜色空间分布的图像分割算法。该算法的输出是一个经过滤色的“分色”图像,其颜色会变得渐变,并且细纹纹理会变得平缓。在Mean-Shift算法中每个像素点用一个五维的向量表示,前两个量是像素点在图像中的坐标,后三个量是每个像素点的颜色分量(蓝、绿、红)。在颜色分布的峰值处开始,通过滑动窗口不断寻找属于同一类的像素点并统一像素点的像素值。滑动窗口由半径和颜色幅度构成,半径决定了滑动窗口的范围,即坐标的范围,颜色幅度决定了半径内像素点分类的标准。这样通过不断地移动滑动窗口,实现基于像素点颜色的图像分割。由于分割后同一类像素点具有相同像素值,因此Mean-Shift算法的输出结果是一个颜色渐变、纹理平缓的图像。

OpenCV 4中提供了实现Mean-Shift算法分割图像的pyrMeanShiftFiltering()函数,该函数的函数原型在代码清单8-23中给出。

代码清单8-23 pyrMeanShiftFiltering()函数原型
void cv::pyrMeanShiftFiltering(InputArray  src,
                               OutputArray  dst,
                               double  sp,
                               double  sr,
                               int  maxLevel = 1,
                               TermCriteria  termcrit = 
                               TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 5, 1)  
8.                              )
  • src:待分割的输入图像,必须是三通道CU_8U的彩色图像
  • dst:分割后的输出图像,与输入图像具有相同的尺寸和数据类型
  • sp:滑动窗口的半径
  • sr:滑动窗口颜色幅度
  • maxLevel:分割金字塔缩放层数
  • termcrit:迭代算法终止条件。

  该函数基于彩色图像的像素值实现对图像的分割,函数的输出结果是经过颜色分布平滑的图像。经过该函数分割后的图像具有较少的纹理信息,可以利用边缘检测函数Canny()以及连通域查找函数findContours()进行进一步细化分类和处理。函数前两个参数是待分割的输入图像和分割后的输出图像,两个图像具有相同的尺寸并且必须是CV_8U的三通道彩色图像。第三个参数为滑动窗口的半径,第四个参数为滑动窗口的颜色幅度。第五个参数为分割金字塔缩放层数,当参数大于1时构建maxLevel + 1层高斯金字塔。该算法首先在尺寸最小的图像层中进行分类,之后将结果传播到尺寸较大的图像层,并且仅在颜色与上一层颜色差异大于滑动窗口颜色幅度的像素上再次进行分类,从而使得颜色区域的边界更清晰。当分割金字塔缩放层数为0时表示直接在整个原始图像时进行均值平移分割。函数最后一个参数表示算法迭代停止的条件,该参数的数据类型是TermCriteria,该数据类型是OpenCV 4中用于表示迭代算法终止条件的数据类型,在所有涉及到迭代条件的函数中都有该参数,用于表示在满足某些条件时函数将停止迭代并输出结果。TermCriteria变量可以通过TermCriteria()函数进行赋值,该函数的函数原型在代码清单8-24中给出。

代码清单8-24 TermCriteria()函数原型
cv::TermCriteria::TermCriteria(int  type,
                               int  maxCount,
                               double  epsilon 
                               )
  • type:终止条件的类型标志,可以选择的参数及含义在表8-6中给出。
  • maxCount:最大迭代次数或者元素数。
  • epsilon:迭代算法停止时需要满足的精度或者参数变化。

  该函数可以表示迭代算法的终止条件,主要分为满足迭代次数和满足计算精度两种。函数第一个参数是终止条件的类型标志,其可选参数在表8-6中给出,这几个标志可以互相结合使用,需要注意的是,由于该参数在TermCriteria类中,因此在使用时需要在变量前面添类名前缀。函数第二个参数表示最大迭代次数,在epsilon== TermCriteria::COUNT时发挥作用。函数第三个参数表示停止迭代时需要满足的计算精度,在epsilon== TermCriteria::EPS时发挥作用。

码清单8-25 myPyrMeanShiftFiltering.cpp利用均值漂移法分割图像
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
  Mat img = imread("coins.png");
  if (!img.data)
  {
    cout << "读取图像错误,请确认图像文件是否正确" << endl;
    return -1;
  }

  //分割处理
  Mat result1, result2;
  TermCriteria T10 = TermCriteria(TermCriteria::COUNT | TermCriteria::EPS, 10, 0.1);
  pyrMeanShiftFiltering(img, result1, 20, 40, 2, T10);  //第一次分割
  pyrMeanShiftFiltering(result1, result2, 20, 40, 2, T10);  //第一次分割的结果再次分割

                                //显示分割结果
  imshow("img", img);
  imshow("result1", result1);
  imshow("result2", result2);

  //对图像提取Canny边缘
  Mat imgCanny, result1Canny, result2Canny;
  Canny(img, imgCanny, 150, 300);
  Canny(result1, result1Canny, 150, 300);
  Canny(result2, result2Canny, 150, 300);

  //显示边缘检测结果
  imshow("imgCanny", imgCanny);
  imshow("result1Canny", result1Canny);
  imshow("result2Canny", result2Canny);
  waitKey(0);
  return 0;
}

3、分水岭算法

void watershed( InputArray image, InputOutputArray markers );

总的概括一下watershed图像自动分割的实现步骤:

1. 图像灰度化、滤波、Canny边缘检测

2. 查找轮廓,并且把轮廓信息按照不同的编号绘制到watershed的第二个入参merkers上,相当于标记注水点。

3. watershed分水岭运算

4. 绘制分割出来的区域,视觉控还可以使用随机颜色填充,或者跟原始图像融合以下,以得到更好的显示效果。

以下是Opencv分水岭算法watershed实现的完整过程:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>

using namespace cv;
using namespace std;

Vec3b RandomColor(int value);  //生成随机颜色函数

int main( int argc, char* argv[] )
{
    Mat image=imread(argv[1]);    //载入RGB彩色图像
    imshow("Source Image",image);

    //灰度化,滤波,Canny边缘检测
    Mat imageGray;
    cvtColor(image,imageGray,CV_RGB2GRAY);//灰度转换
    GaussianBlur(imageGray,imageGray,Size(5,5),2);   //高斯滤波
    imshow("Gray Image",imageGray); 
    Canny(imageGray,imageGray,80,150);  
    imshow("Canny Image",imageGray);

    //查找轮廓
    vector<vector<Point>> contours;  
    vector<Vec4i> hierarchy;  
    findContours(imageGray,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());  
    Mat imageContours=Mat::zeros(image.size(),CV_8UC1);  //轮廓    
    Mat marks(image.size(),CV_32S);   //Opencv分水岭第二个矩阵参数
    marks=Scalar::all(0);
    int index = 0;
    int compCount = 0;
    for( ; index >= 0; index = hierarchy[index][0], compCount++ ) 
    {
        //对marks进行标记,对不同区域的轮廓进行编号,相当于设置注水点,有多少轮廓,就有多少注水点
        drawContours(marks, contours, index, Scalar::all(compCount+1), 1, 8, hierarchy);
        drawContours(imageContours,contours,index,Scalar(255),1,8,hierarchy);  
    }

    //我们来看一下传入的矩阵marks里是什么东西
    Mat marksShows;
    convertScaleAbs(marks,marksShows);
    imshow("marksShow",marksShows);
    imshow("轮廓",imageContours);
    watershed(image,marks);

    //我们再来看一下分水岭算法之后的矩阵marks里是什么东西
    Mat afterWatershed;
    convertScaleAbs(marks,afterWatershed);
    imshow("After Watershed",afterWatershed);

    //对每一个区域进行颜色填充
    Mat PerspectiveImage=Mat::zeros(image.size(),CV_8UC3);
    for(int i=0;i<marks.rows;i++)
    {
        for(int j=0;j<marks.cols;j++)
        {
            int index=marks.at<int>(i,j);
            if(marks.at<int>(i,j)==-1)
            {
                PerspectiveImage.at<Vec3b>(i,j)=Vec3b(255,255,255);
            }             
            else
            {
                PerspectiveImage.at<Vec3b>(i,j) =RandomColor(index);
            }
        }
    }
    imshow("After ColorFill",PerspectiveImage);

    //分割并填充颜色的结果跟原始图像融合
    Mat wshed;
    addWeighted(image,0.4,PerspectiveImage,0.6,0,wshed);
    imshow("AddWeighted Image",wshed);

    waitKey();
}

Vec3b RandomColor(int value)    <span style="line-height: 20.8px; font-family: sans-serif;">//生成随机颜色函数</span>
{
    value=value%255;  //生成0~255的随机数
    RNG rng;
    int aa=rng.uniform(0,value);
    int bb=rng.uniform(0,value);
    int cc=rng.uniform(0,value);
    return Vec3b(aa,bb,cc);
}

 

 

标签:分割,函数,int,37,算法,参数,图像
From: https://www.cnblogs.com/okmai77xue/p/17306935.html

相关文章

  • 提升工作效率的顶级AI工具:写作、图像、音视频、编程与效率
    ChatGPT风靡全球,人人可用!小红书上有关ChatGPT的笔记已有10w+篇,相关话题浏览量也达到了1.12亿次。其中讨论最为热烈的,要数“ChatGPT使用教程”。(当然,类似的话题还包括,教你如何使用Midjourney等等)甚至还有人通过ChatGPT教学,月入十万。在如今处处都追求降......
  • 35.图像矩的计算与应用
    矩是描述图像特征的算子,被广泛用于图像检索和识别、图像匹配、图像重建、图像压缩以及运动图像序列分析等领域。本节中将介绍几何矩与Hu矩的计算方法以及应用Hu矩实现图像轮廓的匹配。1、几何矩与中心矩 OpenCV4提供了计算图像矩的moments()函数,该函数的函数原型在代码清单7-......
  • 31、图像连通域分析
    图像的连通域是指图像中具有相同像素值并且位置相邻的像素组成的区域,连通域分析是指在图像中寻找出彼此互相独立的连通域并将其标记出来。提取图像中不同的连通域是图像处理中较为常用的方法,例如在车牌识别、文字识别、目标检测等领域对感兴趣区域分割与识别。一般情况下,一个......
  • 30.图像距离变换
    图像中两个像素之间的距离有多种定义方式,图像处理中常用的距离有欧式距离、街区距离和棋盘距离,本节中将重点介绍这三种距离的定义方式,以及如何利用两个像素间的距离来描述一幅图像。1、欧式距离,两个像素点之间的直线距离。与直角坐标系中两点之间的直线距离求取方式相同,分别......
  • Meta AI 开源万物可分割 AI 模型(SAM)
    开始4月6日,根据MetaAI官方博客,MetaAI宣布推出了一个AI模型SegmentAnythingModel(SAM,分割一切模型)。据介绍,该模型能够根据文本指令等方式实现图像分割,而且万物皆可识别和一键抠图。github源码地址:facebookresearch/segment-anything官方网站体验地址:segment-anythin......
  • 28.图像滤波
    1、均值滤波代码清单5-8blur()函数原型voidcv::blur(InputArraysrc,OutputArraydst,Sizeksize,Pointanchor=Point(-1,-1),intborderType=BORDER_DEFAULT)待......
  • A537CL1化学成分、A537CL1执行标准、A537CL1力学性能
    一、A537CL1钢板简介:A537CL1钢板归属于钢板中的一大类,锅炉容器钢板之一。A537CL1钢板执行的是美国标准,所以也是美标的压力容器锅炉钢板。A537CL1钢板执行标准:执行ASTM标准(美标)。二、A537CL1钢板化学成分:CSiMnPSNiCrMoCuNbVTiAltB≤0.240.15~0.51~1.6≤0.025≤0.025≤0.25≤0.25≤0......
  • 27、图像中加入噪声
    1、图像中加入椒盐噪声椒盐噪声又被称作脉冲噪声,它会随机改变图像中的像素值,是由相机成像、图像传输、解码处理等过程产生的黑白相间的亮暗点噪声,其样子就像在图像上随机的撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。考虑到椒盐噪声会随机产生在图像中的任何一个位置,因此对于......
  • 25.图像直方图
    1、图像直方图绘制图像直方图是图像处理中非常重要的像素统计结果,图像直方图不再表征任何的图像纹理信息,而是对图像像素的统计。由于同一物体无论是旋转还是平移在图像中都具有相同的灰度值,因此直方图具有平移不变性、放缩不变性等优点,因此可以用来查看图像整体的变化形式,例......
  • m基于shepp-Logan模型和滤波反投影的医学图像多尺度全局重建和局部重建matlab仿真
    1.算法描述        从投影重建物体的截面图像是图像处理中非常重要的技术此技术在物体的无损伤性检测其内部缺陷的应用中能起很大作用从投影重建图像的技术早在20世纪中期就已经制成常规医疗诊断设备的商品1917年奥地利数学家J.Radon发表的论文证明了二维物体或三维物体......