C#,图像二值化(06)——全局阈值的大津OTSU算法及其源代码

news2024/10/5 12:57:11

1、大津OTSU算法

最大类间方差法是1979年由日本学者大津(Nobuyuki Otsu)提出的,是一种自适应阈值确定的方法,又叫大津法,简称OTSU,是一种基于全局的二值化算法,它是根据图像的灰度特性,将图像分为前景和背景两个部分。当取最佳阈值时,两部分之间的差别应该是最大的,在OTSU算法中所采用的衡量差别的标准就是较为常见的最大类间方差。前景和背景之间的类间方差如果越大,就说明构成图像的两个部分之间的差别越大,当部分目标被错分为背景或部分背景被错分为目标,都会导致两部分差别变小,当所取阈值的分割使类间方差最大时就意味着错分概率最小。

2、Image Threshold

If the intensity of a pixel in the input image is greater than a threshold, the corresponding output pixel is marked as white (foreground), and if the input pixel intensity intensity is less than or equal to the threshold, the output pixel location is marked black (background).

Image thresholding is used in many applications as a pre-processing step. For example, you may use it in medical image processing to reveal tumor in a mammogram or localize a natural disaster in satellite images.

A problem with simple thresholding is that you have to manually specify the threshold value. We can manually check how good a threshold is by trying different values but it is tedious and it may break down in the real world.

So, we need a way to automatically determine the threshold. The Otsu’s technique named after its creator Nobuyuki Otsu is a good example of auto thresholding.

Before we jump into the details of the technique let’s understand how image thresholding relates to image segmentation.
 

3、Otsu thresholding


To improve on the segmentation, we next investigated a smarter thresholding approach: Otsu’s method. Otsu thresholding assumes that there are two classes of pixels in the image which we wish to separate. Additionally, Otsu’s method assumes that the two classes are separated by a roughly bimodal intensity histogram. The algorithm will then find the optimal threshold that separates the two classes via an exhaustive search for the threshold that minimizes the variance between the two classes. Our golf course images seemed to fit the assumptions of the algorithm: the two classes of pixels are “trees” and “the rest” and the intuition for our bimodal intensity histogram is “trees are dark”, “the rest is light”.

Using Otsu’s method for thresholding worked much better than the simple thresholding: large parts of the playable rough are now included in the segmented mask. There are some small false-positives such as the masked pixels in the tree crowns on the right upper side of the image. However, those small areas of noise were easily fixed via morphological operations such as opening, erosion and dilation.

One area where we noted that Otsu’s method broke down is in an image that contains shadows such as the example below. Otsu’s method operates on grayscale images so it can’t distinguish the deep dark green color of the tree canopy from the dark shadows of a tree. This is very visible in the upper center of the picture where shadows on the right end of the horizontal tree line are being included. However, for our golf course image segmentation, these shadows should be excluded.
 

4、大津OTSU算法的源代码(两个版本)

using System;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

namespace Legalsoft.Truffer.ImageTools
{
    public static partial class BinarizationHelper
    {

        #region 灰度图像二值化 全局算法 大津OTSU 算法(两种代码)

        /// <summary>
        /// 图像二值化的大津算法
        /// Otsu's Thresholding
        /// https://blog.csdn.net/weixin_35811044/article/details/85255924
        /// </summary>
        /// <param name="data">灰度化的图片数据</param>
        /// <returns></returns>
        public static int Otsu_Threshold(byte[,] data)
        {
            int height = data.GetLength(0);
            int width = data.GetLength(1);

            int[] histv = Gray_Histogram(data);
            double[] histogram = Histogram_Normalize(histv);
            int pixelNumb = height * width;
            double[] variances = new double[256];

            for (int T = 0; T < histogram.Length; T++)
            {
                double n1 = 0, n2 = 0;
                double total1 = 0, total2 = 0;
                double aver1 = 0, aver2 = 0;
                double w1 = 0, w2 = 0;
                double ft1 = 0, ft2 = 0;

                for (int i = 0; i < T; i++)
                {
                    n1 += histogram[i];
                    total1 += histogram[i] * i;
                }
                for (int j = T; j < variances.Length; j++)
                {
                    n2 += histogram[j];
                    total2 += histogram[j] * j;
                }
                w1 = n1 / pixelNumb;
                w2 = n2 / pixelNumb;
                aver1 = (n1 == 0) ? 0 : (total1 / n1);
                aver2 = (n2 == 0) ? 0 : (total2 / n2);
                for (int i = 0; i < T; i++)
                {
                    ft1 += (Math.Pow((i - aver1), 2) * histogram[i]);
                }
                for (int j = T; j < 256; j++)
                {
                    ft2 += (Math.Pow((j - aver2), 2) * histogram[j]);
                }
                ft1 = (n1 == 0) ? 0 : (ft1 / n1);
                ft2 = (n2 == 0) ? 0 : (ft2 / n2);
                variances[T] = w1 * ft1 + w2 * ft2;
            }

            double min = variances[0];
            int threshold = 0;
            for (int i = 1; i < variances.Length; i++)
            {
                if (variances[i] < min)
                {
                    min = variances[i];
                    threshold = i;
                }
            }
            return threshold;
        }

        /// <summary>
        /// 大津算法之二
        /// </summary>
        /// <param name="histogram"></param>
        /// <returns></returns>
        public static int Ostu_Threshold_Second(int[] histogram)
        {
            int left = Histogram_Left(histogram);
            int right = Histogram_Right(histogram);

            int amount = Histogram_Sum(histogram);
            double PixelIntegral = Histogram_Sum(histogram, 1);

            int Threshold = 0;
            double PixelBack = 0.0;
            double PixelIntegralBack = 0.0;
            double SigmaB = -1.0;
            for (int i = left; i <= right; i++)
            {
                PixelBack = PixelBack + histogram[i];
                double PixelFore = amount - PixelBack;
                double OmegaBack = (double)PixelBack / (double)amount;
                double OmegaFore = (double)PixelFore / (double)amount;
                PixelIntegralBack += histogram[i] * (double)i;
                double PixelIntegralFore = PixelIntegral - PixelIntegralBack;
                double MicroBack = (double)PixelIntegralBack / PixelBack;
                double MicroFore = (double)PixelIntegralFore / PixelFore;
                double Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore);
                if (Sigma > SigmaB)
                {
                    SigmaB = Sigma;
                    Threshold = i;
                }
            }
            return Threshold;
        }

        /// <summary>
        /// 图像二值化的大津算法
        /// </summary>
        /// <param name="data">灰度化的图片数据</param>
        public static void Otsu_Algorithm(byte[,] data)
        {
            int threshold = Otsu_Threshold(data);
            Threshold_Algorithm(data, threshold);
        }

        #endregion

    }
}

5、大津OTSU算法的计算效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/124520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git简介以及安装

目录 一、Git简介 1、版本控制系统简介 2、 Git的安装 a、安装git b、Git 的配置 二&#xff0c;本地仓库 三、GIT分支操作 1、关于分支 2. 分支基本操作 3、分支合并 4、冲突 一、Git简介 1、版本控制系统简介 版本控制系统&#xff08;VCS&#xff09;是将『什么…

【数据结构】直接插入排序,希尔排序,选择排序,堆排序

文章目录排序的概念直接插入排序希尔排序选择排序堆排序排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在…

keras环境搭建

目录 1. 安装miniconda 2. 安装CPU版本的tensorflow 2. 安装keras 3. 安装依赖库 4. 测试 环境&#xff1a;win10&#xff0c;无独立显卡&#xff0c;不用GPU加速。 1. 安装miniconda Miniconda3-latest-Windows-x86_64.exe &#xff08;1&#xff09;安装目录可自选&a…

生成对抗:Pix2Pix

cGAN : Pix2Pix 生成对抗网络还有一个有趣的应用就是&#xff0c;图像到图像的翻译。例如:草图到照片&#xff0c;黑白图像到RGB&#xff0c;谷歌地图到卫星视图&#xff0c;等等。Pix2Pix就是实现图像转换的生成对抗模型&#xff0c;但是Pix2Pix中的对抗网络又不同于普通的GAN…

计网第三章.数据链路层—可靠传输

以下来自湖科大计算机网络公开课的笔记 文章目录0.基本概念1. 停止等待协议SW2. 回退N帧协议GBN3. 选择重传SR首先&#xff0c;这部分说的可靠传输的实现机制不只限于数据链路层&#xff0c;而是适用于整个计算机网络体系 0.基本概念 一般情况下&#xff0c;有线链路的误码率…

Docker 中的挂载卷

我们现在有这样一个需求。 我们有一个 Spring 的项目是部署在容器中的&#xff0c;如果不进行任何配置的话&#xff0c;这个项目运行的所有日子都会在容器中。 当容器重启说着终止后&#xff0c;上面的日志比较难进行查看。 我们希望我们的日志同时也记录在操作系统中&#…

阿贡国家实验室:量子中继器及其在量子网络中的作用

很多人小时候都玩过传声筒游戏&#xff1a;A将消息小声告诉B&#xff0c;然后B将他听到的内容小声告诉C&#xff0c;依此类推&#xff0c;玩过的人都知道&#xff0c;最后传达到的信息往往和真实消息完全不同。 从某种意义上说&#xff0c;这和中继器技术的重要性强相关。中继器…

MySQL锁,锁的到底是什么?

只要学计算机&#xff0c;「锁」永远是一个绕不过的话题。MySQL锁也是一样。 一句话解释MySQL锁&#xff1a; MySQL锁是解决资源竞争的一种方案。 短短一句话却包含了3点值得我们注意的事情&#xff1a; 对什么资源进行竞争&#xff1f;竞争的方式&#xff08;或者说情形&a…

舆情监控和应急处理方案,如何做好网络舆情监控?

舆情监控是指通过不同的渠道&#xff0c;如社交媒体、新闻媒体、博客、论坛等&#xff0c;对公众的言论进行收集、分析、评估和反馈的过程。舆情监控的目的是帮助企业或组织了解公众的观点和情绪&#xff0c;并且能够及时做出回应&#xff0c;避免可能出现的舆论危机。接下来TO…

2022年度投影仪行业数据分析报告:十大热门品牌排行榜

在当前的大环境下&#xff0c;线下娱乐受阻&#xff0c;而用户对于足不出户的观影、娱乐需求推动着智能投影设备的增长。近几年来&#xff0c;投影仪行业保持着较快速度的增长&#xff0c;面对整体市场需求不振的形势&#xff0c;投影仪仍在保持正向增长。随着家用智能投影在市…

Charles - 阻塞请求、修改请求与响应内容、重定向请求地址、指定文件为响应内容

1、阻塞请求 1、鼠标放在指定接口上 > 右键 > 勾选 Block List 2、重新访问这接口&#xff0c;这条请求被阻塞&#xff0c;不会有返回信息 取消阻塞接口&#xff1a; 鼠标放在指定接口上 > 右键 > 取消勾选 Block List 2、修改请求与响应内容 第一步&#xff1…

【一文看懂 ES 核心】存储查询集群

一文看懂 ES 核心 Elasticsearch 作为一个搜索引擎&#xff0c;其可以提供高效的搜索匹配数据的能力&#xff0c;对于这类工具了解其运行原理其实是有一套功法的。 聊存储&#xff0c;ES 是如何存储数据的&#xff1f;聊方法&#xff0c;ES 是如何进行搜索匹配的&#xff1f;…

【Linux】文件描述符、文件操作、重定向的模拟实习

目录 一、重温C语言文件操作 1.1 文件打开方式 1.2 文件写操作 1.3 文件读操作 1.3 标准输入输出 二、系统接口的使用 2.1 open 函数 2.2 close 函数 2.3 write 函数 2.4 read 函数 三、文件描述符 3.1 如何管理文件 3.2 0 & 1 & 2 3.3 文件描述符的分配…

种草!超好用的PDF转换器上线啦~

宝子们 重磅福利来啦 你还在为每次转换文件头疼吗 老铁&#xff0c;大拿版万能转换器正式上线啦 以前的文件转换器&#xff0c;不是充会员就是收费高 最坑的是花钱还解决不了问题 每次转换文件内容有误.... 特殊符号或者公式更是无法有效转换 为了整顿这种局面&#xff0c…

KKT条件理解

我们知道拉格朗日函数是用于等式约束的优化问题求解的&#xff0c;然KKT条件是针对含有不等式约束的优化问题的。 首先&#xff0c;我们先给出优化目标&#xff1a; 因此&#xff0c;根据优化目标&#xff0c;我们同样可以构造处拉格朗日函数&#xff0c;并对其进行优化&#…

ssh免密登录

准备两台linux主机 主机A&#xff1a;192.168.92.131 主机B&#xff1a;192.168.92.132 使用主机B去免密访问主机A 在主机B上执行 ssh-keygen -t rsa ssh-keygen 生成密码对 -t rsa 指定生成 rsa 密钥对 密钥对文件默认放在 家目录下面的 .ssh 目录下 root 用户默认放在 /ro…

一、数据库开发与实战专栏导学及数据库基础概念入门

文章目录一、专栏导学1.1 课程内容1.2 学习安排1.3 适合人群1.4 学习方法二、认识数据库2.1 生活中的数据库2.2 数据管理技术的3个发展阶段2.3 数据库、关系型数据库、非关系型数据库概念2.4 为什么要使用数据库2.5 数据库系统及其组成部分2.6 常用数据库访问接口简介2.7 数据库…

【2】Go语言的语法

一、Go语言基础组成 Go语言基础组成&#xff1a; 包申明引入包函数变量语句&表达式注释实例&#xff1a; package main //申明包 import "fmt" /* 这是一个朴实无华的注释 */ func main() { fmt.Printf("mogu") } 实现流程&#xff1a; 第一行&#…

kafka简介

目录 partition和consumer group offset的管理 kafka的事务 幂等producer 事务producer 怎么理解trasactional.id 两阶段2pc简介 kafka的消息传输保证 producer端 broker端 consumer端 消息挤压 kafak的存储 kafka的高性能 附录-kafka demo kafaka的发布-订阅模…

Rust之常用集合(三):哈希映射(Hash Map)

开发环境 Windows 10Rust 1.66.0VS Code 1.74.2项目工程 这里继续沿用上次工程rust-demo 在哈希图中存储带有关联值的键 我们常见的集合中的最后一个是哈希映射。HashMap<K, V>类型使用散列函数存储K类型的键到V类型的值的映射&#xff0c;这决定了它如何将这些键和值…