自适应阈值大津法(OTSU)介绍及代码实现

2024-08-27 00:32

本文主要是介绍自适应阈值大津法(OTSU)介绍及代码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://blog.csdn.net/a153375250/article/details/50970104

算法原理
最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定法,又叫大津法,简称OTSU。

我用最简单的方式解释一下算法原理:

这个算法的思想就是假设阈值T将图像分成了前景和背景两个部分。

求出这两个部分的类间方差:

前景像素个数占比x(前景平均灰度 - 全图平均灰度)2 + 背景像素个数占比x(背景平均灰度 - 全图平均灰度)2

将阈值从0~255遍历一次,使上述类间方差最大的阈值T即为所求。

类间方差计算
我们接下来将算法原理中的类间方差化简为一个比较简单的形式,下面的过程也是代码实现的过程。

定义变量:

总像素数:N
前景像素数:fN
背景像素数:bN
前景像素灰度和:fSum
背景像素灰度和:bSum
前景像素平均灰度:fu
背景像素平均灰度:bu
图像总灰度值:Sum
图像平均灰度:u
前景像素占比:fw
背景图像占比:bw
类间方差:g
1
2
3
4
5
6
7
8
9
10
11
12
前景、背景占比:

前景像素占比:fw = fN/N
背景像素占比:bw = bN/N
1
2
前景、背景占比满足:

fw + bw =1  (1)
1
图片平均灰度值:

图片灰度直方图 : Histogram[256]
图片总灰度值 Sum : for(i=0; i<N; i++){ Sum += Histogram[i];}
图片平均灰度值 u : Sum/N
1
2
3
阈值为T时前景平均灰度:

阈值为T时前景像素数 fN : for(i=0; i<=T; i ++) { fN += Histogram[i];}
阈值为T时前景像素灰度和 fSum : for(i=0; i<=T; i++) { fSum += Histogram[i]*i;}
阈值为T时前景平均灰度 fu : fSum/fN
1
2
3
阈值为T时背景平均灰度:

阈值为T时背景像素数 bN : N-fN
阈值为T时背景像素灰度和 bSum : Sum-fSum
阈值为T时背景平均灰度 bu : bSum/bN    
1
2
3
平均灰度满足:

u = fu*fw + bu*bw  (2)
1
类间方差:

类间方差 g:fw*(fu-u)^2+bw*(bu-u)^2  (3)
1
将(1)(2)带入(3)式:

g = bw*fw*(fu-bu)^2
1
代码实现
假设读入图片为单通道Mat型灰度图,我们可以用以下代码实现:

#include <opencv2/opencv.hpp>  
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>

using namespace std;
using namespace cv;

Mat otsuGray(const Mat src) {
    Mat img = src;
    int c = img.cols; //图像列数
    int r = img.rows; //图像行数
    int T = 0; //阈值
    uchar* data = img.data; //数据指针
    int ftNum = 0; //前景像素个数
    int bgNum = 0; //背景像素个数
    int N = c*r; //总像素个数
    int ftSum = 0; //前景总灰度值
    int bgSum = 0; //背景总灰度值
    int graySum = 0;
    double w0 = 0; //前景像素个数占比
    double w1 = 0; //背景像素个数占比
    double u0 = 0; //前景平均灰度
    double u1 = 0; //背景平均灰度
    double Histogram[256] = {0}; //灰度直方图
    double temp = 0; //临时类间方差
    double g = 0; //类间方差

    //灰度直方图
    for(int i = 0; i < r ; i ++) {
        for(int j = 0; j <c; j ++) {
            Histogram[img.at<uchar>(i,j)]++;
        }
    }
    //求总灰度值
    for(int i = 0; i < 256; i ++) {
        graySum += Histogram[i]*i;
    }

    for(int i = 0; i < 256; i ++) {
        ftNum += Histogram[i];  //阈值为i时前景个数
        bgNum = N - ftNum;      //阈值为i时背景个数
        w0 = (double)ftNum/N; //前景像素占总数比
        w1 = (double)bgNum/N; //背景像素占总数比
        if(ftNum == 0) continue;
        if(bgNum == 0) break;
        //前景平均灰度
        ftSum += i*Histogram[i];
        u0 = ftSum/ftNum;

        //背景平均灰度
        bgSum = graySum - ftSum;
        u1 = bgSum/bgNum;

        g = w0*w1*(u0-u1)*(u0-u1);
        if(g > temp) {
            temp = g;
            T = i;
        }
    }

    for(int i=0; i<img.rows; i++)
    {
        for(int j=0; j<img.cols; j++)
        {
            if((int)img.at<uchar>(i,j)>T)
                img.at<uchar>(i,j) = 255;
            else
                img.at<uchar>(i,j) = 0;
        }
    }
    return img;
}
--------------------- 
作者:Easy-Sir 
来源:CSDN 
原文:https://blog.csdn.net/a153375250/article/details/50970104 
版权声明:本文为博主原创文章,转载请附上博文链接!

这篇关于自适应阈值大津法(OTSU)介绍及代码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1110119

相关文章

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位

Java使用Spire.Barcode for Java实现条形码生成与识别

《Java使用Spire.BarcodeforJava实现条形码生成与识别》在现代商业和技术领域,条形码无处不在,本教程将引导您深入了解如何在您的Java项目中利用Spire.Barcodefor... 目录1. Spire.Barcode for Java 简介与环境配置2. 使用 Spire.Barco