博客
关于我
OTSU算法(大津法—最大类间方差法)原理及实现
阅读量:798 次
发布时间:2023-04-15

本文共 3122 字,大约阅读时间需要 10 分钟。

大津法(OTSU)图像阈值分割算法详解

大津法(OTSU)是一种经典的图像二值化阈值分割算法,由日本学者大津在1979年提出。其核心思想是通过最大化图像两部分之间的类间方差来确定最优的阈值。这种方法被广泛认为是图像分割中阈值选取的最佳方案,因其计算简单且不受图像亮度和对比度的影响。


算法原理

大津法的核心在于计算图像中灰度级的类间方差,并找出使类间方差最大的阈值。具体步骤如下:

  • 初始化统计数据:首先统计图像中每个灰度级的像素数量,计算每个灰度级的概率分布(概率密度函数)。

  • 计算累计概率和累计均值:遍历所有灰度级,逐步累加概率和累计均值。

  • 计算类间方差:对于每个灰度级k,计算其与全局均值的类间方差。具体公式为:[\sigma^2 = \frac{(mG \cdot p_k - m_k)^2}{p_k \cdot (1 - p_k)}]其中,(mG)为图像全局均值,(p_k)为灰度级k的概率,(m_k)为灰度级k的累计均值。

  • 寻找最大类间方差:遍历所有灰度级,找出使得类间方差最大的k值,这个k值即为OTSU算法的阈值。


  • OpenCV实现

    OpenCV提供了OTSU算法的接口,函数定义如下:

    double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)

    代码实现

    #include 
    #include
    #include
    #include
    using namespace cv;int Otsu(Mat& src, Mat& dst, int thresh) { const int Grayscale = 256; int graynum[Grayscale] = {0}; int r = src.rows; int c = src.cols; for (int i = 0; i < r; ++i) { const uchar* ptr = src.ptr(i); for (int j = 0; j < c; ++j) { graynum[ptr[j]]++; } } double P[Grayscale] = {0}; double PK[Grayscale] = {0}; double MK[Grayscale] = {0}; double sumtmpPK = 0, sumtmpMK = 0; for (int i = 0; i < Grayscale; ++i) { P[i] = graynum[i] / (r * c); PK[i] = sumtmpPK + P[i]; sumtmpPK = PK[i]; MK[i] = sumtmpMK + i * P[i]; sumtmpMK = MK[i]; } double Var = 0; int best_thresh = thresh; for (int k = 0; k < Grayscale; ++k) { double numerator = (MK[Grayscale-1] * PK[k] - MK[k]); double denominator = PK[k] * (1 - PK[k]); if (denominator == 0) continue; double current_var = numerator * numerator / denominator; if (current_var > Var) { Var = current_var; best_thresh = k; } } if (best_thresh != thresh) { src.copyTo(dst); for (int i = 0; i < r; ++i) { uchar* ptr = dst.ptr(i); for (int j = 0; j < c; ++j) { if (ptr[j] > best_thresh) ptr[j] = 255; else ptr[j] = 0; } } } return best_thresh;}int main() { Mat src = cv::imread("I:\\Learning-and-Practice\\Img\\Fig1039(a)(polymersomes).tif"); if (src.empty()) { return -1; } if (src.channels() > 1) { cvtColor(src, src, CV_RGB2GRAY); } Mat dst, dst2; int thresh = 0; // 通过OTSU算法计算阈值 thresh = Otsu(src, dst, thresh); // 使用OpenCV自带函数计算阈值 double Otsu_thresh = threshold(src, dst2, thresh, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); cout << "Mythresh=" << thresh << endl; cout << "OpenCVthresh=" << Otsu_thresh << endl; namedWindow("src", CV_WINDOW_NORMAL); imshow("src", src); namedWindow("dst", CV_WINDOW_NORMAL); imshow("dst", dst); namedWindow("dst2", CV_WINDOW_NORMAL); imshow("dst2", dst2); waitKey(0); return 0;}

    功能说明

  • 初始化:统计图像中每个灰度级的像素数,计算每个灰度级的概率。
  • 累计计算:逐步累加概率和累计均值。
  • 类间方差计算:遍历所有灰度级,计算每个阈值对应的类间方差。
  • 寻找最优阈值:找出使类间方差最大的灰度级作为最终阈值。

  • 实施效果

    阈值分割效果

  • 图像分辨率:702 × 648
  • 分割质量:与OpenCV自带函数一致
  • 分辨率对比:本文实现与OpenCV自带函数对比,分割效果一致
  • 阈值准确性

    • 计算时间:约1ms,运行效率较高
    • 阈值精度:与OpenCV自带函数一致

    参考资料

    • OpenCV官方文档
    • GitHub:欢迎Star、Fork

    转载地址:http://xrrfk.baihongyu.com/

    你可能感兴趣的文章
    mysql 创建表,不能包含关键字values 以及 表id自增问题
    查看>>
    mysql 删除日志文件详解
    查看>>
    mysql 判断表字段是否存在,然后修改
    查看>>
    mysql 协议的退出命令包及解析
    查看>>
    mysql 取表中分组之后最新一条数据 分组最新数据 分组取最新数据 分组数据 获取每个分类的最新数据
    查看>>
    mysql 多个表关联查询查询时间长的问题
    查看>>
    mySQL 多个表求多个count
    查看>>
    mysql 多字段删除重复数据,保留最小id数据
    查看>>
    MySQL 多表联合查询:UNION 和 JOIN 分析
    查看>>
    MySQL 大数据量快速插入方法和语句优化
    查看>>
    mysql 如何给SQL添加索引
    查看>>
    mysql 字段区分大小写
    查看>>
    mysql 字段合并问题(group_concat)
    查看>>
    mysql 字段类型类型
    查看>>
    MySQL 字符串截取函数,字段截取,字符串截取
    查看>>
    MySQL 存储引擎
    查看>>
    mysql 存储过程 注入_mysql 视图 事务 存储过程 SQL注入
    查看>>
    MySQL 存储过程参数:in、out、inout
    查看>>
    mysql 存储过程每隔一段时间执行一次
    查看>>
    mysql 存在update不存在insert
    查看>>