图像分割 - 阈值处理 - 多阈值处理(OTSU)

news2024/11/25 13:50:28

目录

1. 多阈值处理介绍

2. 代码讲解

3. 完整代码


1. 多阈值处理介绍

之前介绍的都是全局单个阈值对图像的分割。固定阈值法,阈值是人工根据灰度直方图的波谷进行设置的。全局阈值法,根据不停的迭代两个区域间的平均灰度进行分割。OUST最大类间方差法,是根据两个子区域不同类之间的最大方差分割。

事实上,OTSU大津法可以扩展到任意数量的阈值

只需要将之前两个类的类间方差更改为三个类即可:

  •  P1是第一个区域的像素概率,及落在第一个区域的像素点 / 总像素点个数
  •  P2 、 P3 是落在第二、第三区域的概率。因此满足 P1+P2+P3 = 1
  •  mG 是整幅图像的平均灰度 , m1、m2、m3 是三个区域各自的平均灰度
  •  它们有着下面的关系:

 这里只要保证类间方差σB 最大的话,就可以完成三个区域的分割

因为分割三个区域,需要两个阈值k1、k2,因此阈值的范围需要注意

灰度值的范围:

第一区域G1----------------k1-----------------第二区域-----------------k2---------------------第三区域

迭代的过程从k1开始,k1的范围是:1~L-3 ,因为0是没有意义的,灰度值0的前面没有第一区域,同样,如果k1取到最后的两个灰度值的话,就没有k2以及第二第三区域了

然后k2开始迭代,k2的范围是:k1+1~L - 2 ,也是同样的道理,假设L=256的话,k2最多取到254,要不然第三区域也就没有了

注意,这个迭代过程是类似于打印九九乘法表的方式迭代,不能先迭代出k1,在迭代出k2

 

2. 代码讲解

我们所有的工作就是为了求等号右边的值,然后通过迭代k1、k2,找到最大的类间方差σB

首先,计算全体图像的灰度直方图hist,定义灰度范围grayScale

然后计算出图片像素点的个数,为了求P1、P2、P3 各个区域的像素概率

最后求出mG 整幅图像的平均灰度

 

然后,开始迭代k1,因为k1的位置就可以确定第一区域G1的像素区域。如下,灰度值小于等于k1的都是第一区域G1的像素点

通过切片,找出G1区域的灰度动态范围和像素点的直方图。

然后计算P1的值和G1区域的平均灰度。这里为了防止G1区域没有像素点做了判断

然后开始迭代k2,大于等于k2的为第三区域。

下面的代码就是计算G3区域的像素概率P3和平均灰度m3

 

 最后就是计算G2区域的值,通过之前P和m对应的关系,可以之间用公式计算得出

然后判断类间方差varB是否是最大的,是的话保存k1、k2、varB到T1、T2、varMax里面。

 最后就是多阈值处理,将两个阈值和图像返回即可

3. 完整代码

import cv2
import numpy as np


# 多阈值处理
def double_threshold_processing(x):   # x 为传入的图像
    hist = cv2.calcHist([x], [0], None, [256], [0, 256])  # 图像的灰度直方图  shape = (256,1)
    grayScale = np.arange(256).reshape(1, -1)             # 灰度级 [0,255]  shape =(1,256)
    sum_pixels = x.shape[0] * x.shape[1]                  # 图像总共像素点的个数
    mG = x.mean()                                         # 整幅图像的平均灰度

    T1,T2,varMax = 0,0,0.0        # 双阈值T1、T2,类间方差varMax

    for k1 in range(1,254):     # k1范围在1 - 253之间 1 ~ L-3

        gray_G1 = grayScale[:, :k1 + 1]               # 灰度值 0~k1 的子区域G1
        hist_G1 = hist[:k1 + 1, :]                    # 子区域G1的直方图 0~k1 ,对应每个灰度值的像素点
        sum_gray_G1 = np.dot(gray_G1, hist_G1)        # G1 区域所有像素点灰度值总和 = 灰度值 * 对应像素点的个数
        sum_pixels_G1 = sum(hist_G1)                  # G1 像素数量
        P1 = sum_pixels_G1 / sum_pixels               # G1 像素占比
        m1 = (sum_gray_G1 / sum_pixels_G1) if sum_pixels_G1 > 0 else 0        # G1 像素的平均灰度

        for k2 in range(k1+1,255):     # k2范围在 k1+1 ~ 254 之间 k1+1 ~ L-2
            gray_G3 = grayScale[:,k2:]                # 灰度值 k2~L-1 的子区域G3
            hist_G3 = hist[k2:,:]                     # 子区域G3的直方图 k2~L-1 ,对应每个灰度值的像素点
            sum_gray_G3 = np.dot(gray_G3,hist_G3)     # G3 区域所有像素点灰度值总和 = 灰度值 * 对应像素点的个数
            sum_pixels_G3 = sum(hist_G3)              # G3 像素数量
            P3 = sum_pixels_G3 / sum_pixels           # G3 像素占比
            m3 = (sum_gray_G3 / sum_pixels_G3) if sum_pixels_G3 > 0 else 0        # G3 平均灰度

            P2 = 1.0 - P1 - P3              # G2 区域的像素占比
            m2 = ((mG - P1 * m1 - P3 * m3) / P2) if P2 > 0 else 0   # G2 平均灰度

            varB = P1 * (m1 - mG) ** 2 + P2 * (m2 - mG) ** 2 + P3 * (m3 - mG) ** 2  # 类间方差

            if varB > varMax:        # 保存最大的类间方差
                T1,T2,varMax = k1,k2,varB

    x[x <= T1] = 0
    x[(x>T1)&(x<T2)] = 123  # 中间的灰度,可以更改
    x[x >= T2] = 255

    return T1,T2,x


img = cv2.imread("img.tif",0)
ret1,ret2,dst = double_threshold_processing(img.copy())         # 多阈值处理
print(ret1,ret2)

cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey()
cv2.destroyAllWindows()

处理的结果:返回的两个阈值为:80 、 178

双阈值处理的方法应用于灰度直方图有两个波谷的情况,如下

 

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

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

相关文章

centos7 环境安装 PM2 管理 node

前言&#xff1a; 由于最新的项目中用到的框架是 ssr 框架。 Vue使用的ssr是 nuxt.js&#xff0c;由于 nuxt.js 和普通的Vue项目不同&#xff0c;所以部署到Linux服务器的方式和普通的Vue项目是有区别的。 1、PM2 介绍 PM2 是一款非常优秀的 Node 进程管理工具&#xff0c;它…

用于科学研究的TCO反式环辛烯:1312010-03-9,(4E)-TCO-CycP-O-PNB ester

(4E)-TCO-CycP-O-PNB ester物理数据&#xff1a; CAS&#xff1a;1312010-03-9| 中文名&#xff1a;(4E)-反式环辛烯-CycP-O-PNB ester&#xff0c; (4E)-反式环辛烯-CYCP-O-PNB-酯 | 英文名&#xff1a;(4E)-TCO-CycP-O-PNB ester 结构式&#xff1a; 英文别名&#xff1a; …

试用信号灯实现如图所示的进程同步关系

试用信号灯实现如图所示的进程同步关系 信号量的个数要等于具有直接前驱的进程个数 P2,P3,P4,P5这些进程有前驱&#xff0c;所以设S2S3S4S50 因为P1执行完&#xff0c;P2,P3,P4才能执行因为P1没有直接前驱&#xff0c;所以直接释放P2.P3.P4的信号量S2,S3,S4P1{V(S2)V(S3)V(…

03-HTML

1 HTML入门 1.1 初识HTML 1.1.1 概述 网络世界已经跟我们息息相关&#xff0c;当我们打开一个网站&#xff0c;首先映入眼帘的就是一个个华丽多彩的网页。这些网页&#xff0c;不仅呈现着基本的内容&#xff0c;还具备优雅的布局和丰富的动态效果&#xff0c;这一切都是如何…

图像分割简介

相比于目标检测只是将目标位置检测出来而言&#xff0c;目标分割能够更精准的将图像进行划分。图像分割在计算机视觉中的地位 为后续检测、识别等提供技术支持。 图像分割难点以及处理 难点&#xff1a;图像特征的组合难以表达&#xff1f; 比如 图中人的头发和裤子是黑色&a…

《FFmpeg Basics》中文版-10-为视频添加文字

正文 视频中包含的文本数据可以显着提高其信息质量。 在视频中添加文字的相关介绍 如何将一些文本添加到视频输出中的两种常用方法是使用前一章中的字幕或叠加技术(overlay)。 具有许多可能性的最高级选项是使用表中描述的抽象滤镜&#xff1a; 描述从文本文件或字符串在视频…

成像雷达量产突破:木牛携手全球合作伙伴突破智驾瓶颈

时隔三年的全球工程机械行业大展&#xff0c;第33届2022德国慕尼黑Bauma展&#xff0c;于近期圆满收官。作为2022年为数不多的全球性展会&#xff0c;吸引了60多个国家和地区的3100余家工程机械企业聚首&#xff0c;行业新品竞相角逐&#xff0c;数字智能化的创新产品成为本次展…

最近公共祖先(lca)

题目描述 如题&#xff0c;给定一棵有根多叉树&#xff0c;请求出指定两个点直接最近的公共祖先。 输入格式 第一行包含三个正整数 N,M,S&#xff0c;分别表示树的结点个数、询问的个数和树根结点的序号。 接下来 N−1 行每行包含两个正整数 x,y&#xff0c;表示 x 结点和 y 结…

[附源码]java毕业设计景区门票系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C# 通过字符串找对应名称的变量、Winform跨容器调用变量、递归遍历XML

C# 通过字符串找对应名称的变量、Winform跨容器调用变量、递归遍历XML 通过字符串&#xff0c;找对应名称的变量 ExceptionRecord er new ExceptionRecord();//新建类的对象&#xff08;变量在这个类中&#xff09; var fieldInfo er.GetType().GetField("Params"…

《Google软件工程之道》软件工程随想

写在之前&#xff1a;今年年初给自己安排了任务&#xff0c;每个月写一遍感悟性的文章。促使自己沉淀并思考。 这篇文章的内容本来只是一些想法&#xff0c; 想想还是记下来。几年以后自己再读这篇文章也许是另一种体会吧 编程和软件工程之间有三个关键的区别&#xff1a;时间、…

基于遗传算法的自主式水下潜器路径规划问题(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

2022/11/18拓展班上机课

Vs的使用 新建项目 新建源文件 关闭scanf_s和printf_s检查&#xff1a;project -> 属性 -> C/C -> 常规 ->SDL&#xff1a;否 char* str"..."出现”"const char *" 类型的值不能用于初始化 "char *" 类型的实体“错误&#xff…

2022.11.17补题祭

前言&#xff1a; 考完期中考试了&#xff01;&#xff01;生物逆袭了&#xff01;&#xff01;全年级前十&#xff08;可能是因为题目太简单我比较细心吧&#xff09;但还是错了一些不该错的题目......&#xff08;生物惨痛87分&#xff09; 感觉这次期中考试情况良好&#…

荧光标记PEG衍生物——Fluorescein-PEG-Azide,FITC-PEG-N3,荧光素peg叠氮

荧光标记PEG衍生物——Fluorescein-PEG-Azide&#xff0c;FITC-PEG-N3&#xff0c;中文名为荧光素-聚乙二醇-叠氮&#xff0c;其所属分类为Azide PEG Fluorescent PEG。 Fluorescein-PEG-Azide的分子量均可定制&#xff1a;荧光素-peg 20000-叠氮/Fluorescein-PEG 5000-Azide、…

47-用户和权限管理

47-用户和权限管理用户的管理和相关管理命令用户的基础概念用户UID区分用户类别创建用户- useradd修改用户- usermod删除用户- userdel修改用户密码- passwd实验&#xff1a;用户的管理文件用户组的基础概念用户组GID用户组分类创建组- groupadd修改组-groupmod删除组- groupde…

qt 样式表 qss

Qt样式表是一个可以自定义部件外观的十分强大的机制﹐除了那些能够通过子类化QStyle更改的外观,其余的都可以使用Qt样式表来美化。 实现办法&#xff1a;调用setStyleSheet 函数&#xff0c;其中styleSheet一般通过读取配置文件.qss实现。 void setStyleSheet(const QString&a…

volatile如何保证可见性

在Java中&#xff0c; volatile关键字可以保证变量的可见性&#xff0c;如果我们将变量声明为 volatile&#xff0c;这就指示 JVM&#xff0c;这个变量是共享且不稳定的&#xff0c;每次使用它都到主存中进行读取。 Java内存模型&#xff1a; 1.Java所有变量都存储在主…

关于java语言当中的this关键字

/*** 关于java语言当中的this关键字&#xff1a;&#xff08;其内存图见下图&#xff09;* 1、this是一个关键字&#xff0c;翻译为&#xff1a;“这个”* 2、this是一个引用&#xff0c;它是一个变量&#xff0c;this变量中保存的内存地址指向了自身&#xff0c;this存…

APISpace接口推荐

APISpace 上面有各种类型的API&#xff0c;短信类、天气环境类、快递物流类、数据智能类等等&#xff0c;并且所有的API都提供的免费的调用次数&#xff0c;这么多的API肯定有你中意的&#xff01;&#xff01;&#xff01;我们超多的热门API推荐给大家&#xff1a; IP归属地A…