图像分割——单阈值大津法

一.图像分割

1.什么是图像分割

图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。
也就是说图像分割将图像细分为一个个子区域或物体,细分的程度取决于要解决的的问题,当我们得到感兴趣区域时,分割就停止。
PS 打个岔:图像分类是什么
计算机看图像是一堆数字矩阵,不像我们人眼这么高级 能分辨出里面比如有小狗 兔子这些东西。所以为了让计算机理解图像的内容,我们需要应用图像分类,使用计算机视觉和机器学习算法处理图像,这个操作可以简单的为一张图像分配一个标签,如猫还是狗,或者也可以高级到解释图像的 内容并且返回一个可读的句子。
总的来说图像分类一般是涉及计算机视觉机器学习,相对来说更高级 比图像分割涉及范围更广
小结:图像分割是获得想要的区域或者物体 图像分类是对图像中的内容进行理解和解释

2.现有图像分割方法的分类

图像分割——单阈值大津法_第1张图片
多数分割方法是基于灰度值的两个基本性质 不连续性和相似性
(1)基于阈值的方法
图像分割——单阈值大津法_第2张图片
包括全局阈值、自适应阈值等等
①全局阈值是指整幅图像使用同一个阈值做分割处理,适用于背景和前景有明显对比的图像。根据整幅图像确定,但是这种方法只考虑像素本身的灰度值,一般不考虑空间特征,因而对噪声很敏感。常用的全局阈值选取方法有利用图像灰度直方图的峰谷法、最小误差法、最大类间方差法、最大熵自动阈值法以及其它一些方法。
②自适应阈值
在图像中比较复杂的情况下,全局阈值很难准确地将物体与背景分开。这时可以根据需要实际按照将图像分成若干子区域分别计算阈值,进行图像分割,这时的阈值为自适应阈值。

举例子:
cv2.threshold(src,thresh,maxval,type)
cv2.adaptiveThreshold()

(2)基于区域
基于区域的方法是以直接寻找区域为基础的分割技术
①区域生长
②区域分裂与聚合
明天单独写一篇

(3)基于边缘
基于边缘的分割方法 是以灰度局部剧烈变化检测为基础 其中 线和边缘 是主要研究对象
边缘或者说边缘线段是连接边缘像素的集合 线两侧的灰度一侧远亮于该线上的灰度 另一侧是远暗于该线上的灰度
边缘检测 (很多算子)
后天单独写一篇

(4)基于特定理论
特定理论大概有:聚类分析、模糊集理论、基因编码、小波变换等。
小波变换用的也挺多的 这篇排到大后天了

二.单阈值大津法

大津法属于全局阈值方法中的一种,即是最大类间方差法
大津法作为图像分割中阈值选取的常用算法,计算简单,不受图像亮度和对比度的影响,主要原理如下:
影像的大小为M×N,将前景区域和背景区域的分割阈值记作T,影像中像素值小于阈值T的像素个数记为N0,像素值大于阈值T的像素个数记为N1,则有:

w0=N0/(M×N)    
w1=N1/(M×N)    
μ=w0×μ0+w1×μ1    
g=w0×(μ0-μ)^2+w1×(μ1-μ)^2    

其中w0为前景区域像素个数占整幅影像的比例,其像素均值为μ0;w1是背景区域像素个数占整幅影像的比例,其像素均值为μ1;μ为影像的总像素均值,g为类间方差,当计算出的类间方差g最大时,对应的阈值T即为最佳分割效果的阈值。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

double Otsu(Mat& image)
{
    int threshold = 0;
    double maxVariance = 0;
    double w0 = 0, w1 = 0;//前景与背景像素点所占比例
    double u0 = 0, u1 = 0;//前景与背景像素值平均灰度
    int histogram[256] = { 0 }; //定义一个数组 长度为256  0-255
    int Num = image.cols * image.rows;  //总像素个数
    //统计256个bin,每个bin像素的个数
    for (int i = 0; i < image.rows; i++)
    {
        const uchar* p = image.ptr(i);
        for (int j = 0; j < image.cols; j++)
        {
            histogram[int(*p++)]++; //cout<<"Histogram[data[i*image.step+j]]++:;"< maxVariance)
        {
            maxVariance = variance;
            threshold = i;
        }
    }
    cout << "threshold:" << threshold << endl;
    return threshold;
}

int main()
{
    Mat img = imread("C://Users//马亚飞//Pictures//Saved Pictures//湖人.jpg");
    imshow("原图", img);

    Mat img1;
    img.copyTo(img1);
    cvtColor(img, img, CV_BGR2GRAY);   // 把img转为灰度图
    cvtColor(img1, img1, CV_BGR2GRAY); //把img1转为灰度图
    double th = Otsu(img);   //调用Otsu函数 得到阈值th
    cout << "The return value of getOstu is: " << th << endl;   //输出阈值th
    cout << "The return value of opencv threshold is: " << threshold(img1, img1, th, 255, CV_THRESH_OTSU);//opencv已实现的大津法  

    for (int i = 0; i < img.rows; i++)  //行循环
    {
        uchar* data = img.ptr(i);  //获取第i行的首地址
        for (int j = 0; j < img.cols; j++)   //列循环
        {
            if (data[j] <= th)
                data[j] = 0;
            else
                data[j] = 255;
        }  //行处理结束
    }

    imshow("Ostu_img", img);
    //cv::namedWindow("Opencv_img", CV_WINDOW_NORMAL);
    cv::imshow("Opencv_img", img1);
    //对一次大津法 的黑色或者白色部分进行掩膜
    //bitwise_not(img1, img1); //这里先变反转颜色
    /*Mat src = imread("D://opencvdata//0//0.png");
    src.setTo(0,img1);
    imshow("掩膜", src);*/
    waitKey(0);
    return 0;
}

图像分割——单阈值大津法_第3张图片
(威少的黑白图还有点像利拉德)
都差不多

学习自:https://blog.csdn.net/Java_co...

你可能感兴趣的:(图像分割——单阈值大津法)