乐趣区

关于图像处理:图像分割单阈值大津法

一. 图像宰割

1. 什么是图像宰割

图像宰割就是把图像分成若干个特定的、具备独特性质的区域并提出感兴趣指标的技术和过程。
也就是说图像宰割将图像细分为一个个子区域或物体,细分的水平取决于要解决的的问题,当咱们失去感兴趣区域时,宰割就进行。
PS 打个岔:图像分类是什么
计算机看图像是一堆数字矩阵,不像咱们人眼这么高级 能分辨出外面比方有小狗 兔子这些货色。所以为了让计算机了解图像的内容,咱们须要利用图像分类,应用计算机视觉和机器学习算法解决图像,这个操作能够简略的为一张图像调配一个标签,如猫还是狗,或者也能够高级到解释图像的 内容并且返回一个可读的句子。
总的来说图像分类个别是波及 计算机视觉 机器学习 ,相对来说更高级 比图像宰割波及范畴更广
小结:图像宰割是取得想要的区域或者物体 图像分类是对图像中的内容进行了解和解释

2. 现有图像宰割办法的分类

少数宰割办法是基于灰度值的两个根本性质 不连续性和相似性
(1)基于阈值的办法

包含全局阈值、自适应阈值等等
①全局阈值是指整幅图像应用同一个阈值做宰割解决,实用于背景和前景有显著比照的图像。依据整幅图像确定,然而这种办法只思考像素自身的灰度值,个别不思考空间特色,因此对噪声很敏感。罕用的全局阈值选取办法有利用图像灰度直方图的峰谷法、最小误差法、最大类间方差法、最大熵主动阈值法以及其它一些办法。
②自适应阈值
在图像中比较复杂的状况下,全局阈值很难精确地将物体与背景离开。这时能够依据须要理论依照将图像分成若干子区域别离计算阈值,进行图像宰割,这时的阈值为自适应阈值。

举例子:
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 <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2\imgproc\types_c.h>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/opencv.hpp>
#include <iostream>

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<uchar>(i);
        for (int j = 0; j < image.cols; j++)
        {histogram[int(*p++)]++; //cout<<"Histogram[data[i*image.step+j]]++:;"<<histogram[int(*p++)]++<<endl; 
        }
        //*p++,  * 和 ++ 优先级是雷同的 先解援用取出指针指向的值,// 而后再将指针地址加 1,指向下一个地位。也就是取值为 *p   然而这时候指针曾经指向下一个地位
    }
    // 前景像素统计
    for (int i = 1; i < 256; i++)
    {
        w0 = 0;    // 前景像素所占比例
        w1 = 0;    // 背景像素所占比例
        u0 = 0;    // 前景像素灰度均值
        u1 = 0;    // 背景像素灰度均值   
        for (int j = 1; j <= i; j++)
        {w0 = w0 + histogram[j];// 以 i 为阈值,统计前景像素比例
            u0 = u0 + j * histogram[j];// 以 i 为阈值,统计前景像素灰度总和
        }
        u0 = u0 / w0; w0 = w0 / Num;    //Num 是总像素个数

        // 背景像素统计
        for (int j = i + 1; j <= 255; j++)
        {w1 = w1 + histogram[j];// 以 i 为阈值,统计前景像素个数
            u1 = u1 + j * histogram[j];// 以 i 为阈值,统计前景像素灰度总和  histogram[j]是像素值为 j 的像素个数 
        }
        u1 = u1 / w1; w1 = w1 / Num;
        // 后面的 u1 是总灰度和  除以 w1 总个数是前景的灰度均值
// 后面的 w1 是总个数 除以 Num 当前才是比例 
        double variance = w0 * w1 * (u1 - u0) * (u1 - u0); // 以后类间方差计算
        if (variance > 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<uchar>(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;
}

(威少的黑白图还有点像利拉德)
都差不多

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

退出移动版