灰度图像的自动阈值分割

第一种:Otsu (大津法)

一、基于cv2的API调用

1、代码实现

直接给出相关代码:

import cv2
import matplotlib.pylab as plt

path = r"D:\Desktop\00aa\1.png"
img = cv2.imread(path, 0)

def main2():
    ret, thresh1 = cv2.threshold(img, 0, 1, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    print(ret)  # 输出阈值。thresh1是阈值图像

    titles = ['Original Image', 'After Binarization']
    images = [img, thresh1]

    for i in range(2):
        plt.subplot(1, 2, i + 1)
        plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([])
        plt.yticks([])

    plt.show()

main2()

2、参数详解

ret, binary_image = cv2.threshold(image, threshold_value, max_value, type)

cv2.threshold()的参数如下:

  • image:要处理的输入图像,可以是灰度图像或彩色图像,类型为uint8或者uint16,否则会报错
  • threshold_value:设定的阈值,如果像素值大于该阈值,则将其设为max_value,否则将其设为0。即:用于分割像素的阈值。
  • max_value:高于阈值的像素所设置的值,默认为255。即:高于threshold_value的设置为该值,也就是最后二值图像中的最大值。
  • type:阈值化的类型,有以下几种可选:
    • cv2.THRESH_BINARY:二值化阈值化,大于阈值的像素值设为max_value,小于等于阈值的像素值设为0。
    • cv2.THRESH_BINARY_INV:反二值化阈值化,大于阈值的像素值设为0,小于等于阈值的像素值设为max_value。
    • cv2.THRESH_TRUNC:截断阈值化,大于阈值的像素值设为阈值,小于等于阈值的像素值不变。
    • cv2.THRESH_TOZERO:阈值化为0,大于阈值的像素值不变,小于等于阈值的像素值设为0。
    • cv2.THRESH_TOZERO_INV:反阈值化为0,大于阈值的像素值设为0,小于等于阈值的像素值不变。

3、为什么用的是cv2.THRESH_BINARY+cv2.THRESH_OTSU

将 cv2.THRESH_BINARY 和 cv2.THRESH_OTSU 结合使用可以发挥它们的优势,尤其适用于那些具有不同对比度区域的图像。这种组合利用大津算法自动选择最佳阈值,然后将图像进行二值化。

但是经过测试,没有THRESH_BINARY的结果也是一样的,所以需不需要根据自己需求。

1)了解 cv2.THRESH_BINARY

一种基本的二值化方法,它使用一个用户指定的固定阈值将图像中的像素分为两类:高于阈值和低于阈值。简而言之,像素值大于阈值的被设为一个值(通常是255),而像素值小于阈值的被设为另一个值(通常是0)。

ret, binary_image = cv2.threshold(image, threshold_value, max_value, cv2.THRESH_BINARY)
  • image: 输入的灰度图像。
  • threshold_value: 用于分割像素的阈值。
  • max_value: 高于阈值的像素所设置的值。
  • cv2.THRESH_BINARY: 指定使用二进制阈值化。
2)了解 cv2.THRESH_OTSU

大津算法,它是一种自动确定阈值的方法。该算法会分析图像的直方图,找到能够最佳区分前景和背景的阈值。这使得它特别适用于前景和背景对比度差异较大的图像。

ret, binary_image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
  • image: 输入的灰度图像。
  • 0: 这里将阈值设置为0,但实际上会被 cv2.THRESH_OTSU 自动确定。
  • 255: 高于阈值的像素所设置的值。
  • cv2.THRESH_BINARY+cv2.THRESH_OTSU: 结合了二进制阈值和大津法。

4、注意

输入的灰度图像必须是uint8或者uint16类型,如果不是需要进行转换。

img = img.astype(np.uint16)

此外,数据中如果有负值,那么计算返回的阈值会一直显示为最大值,此时需要将负值去除或重置为正数,也可以利用最大最小归一化技术在乘以255。

import numpy as np

path = r"D:\Desktop\00aa\1.png"
img = cv2.imread(path, 0)

def normalize(arr):
    min_val = np.min(arr)
    max_val = np.max(arr)
    normalized_arr = (arr - min_val) / (max_val - min_val)
    return normalized_arr

img = normalize(img)*255
img = img.astype(np.uint16)

在cv2.threshold函数中,我们设置的两个数值,第一个就是阈值(OTSU会自动学习,设置多少无所谓),根据该阈值进行分割;第二个是将二值图像中的最大值设置为多少,即设置5,那么的到的二值图像就是0和5。

二、使用numpy实现

import cv2
import matplotlib.pylab as plt
import numpy as np

path = r"D:\Desktop\00aa\1.png"
img = cv2.imread(path, 0)

def OTSU(img_gray, GrayScale): # GrayScale:灰度图中灰度值的最大值,这里需要在将此值加1。即:灰度图最大值+1
    assert img_gray.ndim == 2, "must input a gary_img"  # shape有几个数字, ndim就是多少
    img_gray = np.array(img_gray).ravel().astype(np.uint8)
    u1 = 0.0  # 背景像素的平均灰度值
    u2 = 0.0  # 前景像素的平均灰度值
    th = 0.0

    # 总的像素数目
    PixSum = img_gray.size
    # 各个灰度值的像素数目
    PixCount = np.zeros(GrayScale)
    # 各灰度值所占总像素数的比例
    PixRate = np.zeros(GrayScale)
    # 统计各个灰度值的像素个数
    for i in range(PixSum):
        # 默认灰度图像的像素值范围为GrayScale
        Pixvalue = img_gray[i]
        PixCount[Pixvalue] = PixCount[Pixvalue] + 1

    # 确定各个灰度值对应的像素点的个数在所有的像素点中的比例。
    for j in range(GrayScale):
        PixRate[j] = PixCount[j] * 1.0 / PixSum
    Max_var = 0
    # 确定最大类间方差对应的阈值
    for i in range(1, GrayScale):  # 从1开始是为了避免w1为0.
        u1_tem = 0.0
        u2_tem = 0.0
        # 背景像素的比列
        w1 = np.sum(PixRate[:i])
        # 前景像素的比例
        w2 = 1.0 - w1
        if w1 == 0 or w2 == 0:
            pass
        else:  # 背景像素的平均灰度值
            for m in range(i):
                u1_tem = u1_tem + PixRate[m] * m
            u1 = u1_tem * 1.0 / w1
            # 前景像素的平均灰度值
            for n in range(i, GrayScale):
                u2_tem = u2_tem + PixRate[n] * n
            u2 = u2_tem / w2
            # print(u1)
            # 类间方差公式:G=w1*w2*(u1-u2)**2
            tem_var = w1 * w2 * np.power((u1 - u2), 2)
            # print(tem_var)
            # 判断当前类间方差是否为最大值。
            if Max_var < tem_var:
                Max_var = tem_var  # 深拷贝,Max_var与tem_var占用不同的内存空间。
                th = i
    return th

def main():
    # 将图片转为灰度图
    th = OTSU(img, 256)
    print("使用numpy的方法:" + str(th))

    ret, thresh1 = cv2.threshold(img, th, 1, cv2.THRESH_BINARY)

    titles = ['Original Image', 'After Binarization']
    images = [img, thresh1]

    for i in range(2):
        plt.subplot(1, 2, i + 1)
        plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([])
        plt.yticks([])

    plt.show()

main()

两种实现结果基本一致

第二种:自适应阈值分割(局部阈值化)

自适应阈值分割,也称为局部阈值化,是根据像素的邻域块的像素值分布来确定该像素位置上的阈值。这种方法的好处是每个像素位置的阈值是根据其周围邻域像素的分布来确定的,因此不是固定不变的。不同亮度、对比度和纹理的局部图像区域将拥有不同的局部阈值。

常用的局部自适应阈值有:1)局部邻域块的均值;2)局部邻域块的高斯加权和。
 

在OPenCV中实现自适应阈值分割的API是:

dst = cv.adaptiveThreshold(src, maxval, thresh_type, type, Block Size, C)

参数:

  • src: 输入图像,一般是灰度图
  • Maxval:灰度中的最大值,一般为255,用来指明像素超过或小于阈值(与type类型有关),赋予的最大值
  • thresh_type : 阈值的计算方法,主要有以下两种:
  • type: 阈值方式,与threshold中的type意义相同
  • block_size: 计算局部阈值时取邻域的大小,如果设为11,就取11*11的邻域范围,一般为奇数。
  • C: 阈值计算方法中的常数项,即最终的阈值是邻域内计算出的阈值与该常数项的差值

返回:

  • dst:自适应阈值分割的结果

即type类型:

代码演示:

import cv2 as cv
import matplotlib.pyplot as plt

# 1. 图像读取
img = cv.imread(r"D:\Desktop\00aa\1.png", 0) # 转为灰度图

# 2.固定阈值/阈值分割 threshold(要处理的图像,一般是灰度图, 设定的阈值, 灰度中的最大值, 阈值分割的方式)
ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)

# 3.自适应阈值
# 3.1 邻域内求均值 cv.adaptiveThreshold(输入图像, 灰度中的最大值, 阈值的计算方法, 阈值方式,计算局部阈值时取邻域的大小,阈值计算方法中的常数项)
th2 = cv.adaptiveThreshold(
    img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 11, 4)
# 3.2 邻域内高斯加权
th3 = cv.adaptiveThreshold(
    img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 17, 6)

# 4 结果绘制
titles = ['Original drawing', 'Global threshold (v = 127)', 'Adaptive threshold (averaging)',
          'Adaptive threshold (Gaussian weighted)']
images = [img, th1, th2, th3]
plt.figure(figsize=(10, 6))
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

参考:图像二值化阈值调整、OpenCV 中的二值化

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件产品研发过程 - 三、详细设计

软件产品研发过程 - 三、详细设计 详细设计是在软件开发过程中&#xff0c;基于概要设计&#xff08;将功能按子功能进行拆分&#xff0c;画面跳转关系、UI原型、画面上所有功能点及每个功能点对应的业务流程&#xff09;&#xff0c;以程序开发的角度来设计概要设计中每个功能…

GRE实验

一&#xff1a;实验要求 1、本实验采用静态路由部署&#xff1b;ISP上不配置任何静态路由条目&#xff1b; 2、在R1、R3上部署GRE隧道&#xff0c;使得私网能够互通。 二&#xff1a;实验配置 r1 配置 ISP配置 r3配置 配置静态路由 建立GRE隧道 三&#xff1a;实验结果

微信会议活动微展示在线活动报名源码系统 带完整的搭建教程

随着微信的普及&#xff0c;微信会议活动已成为企业、团体和个人进行信息交流、业务推广和品牌宣传的重要平台。然而&#xff0c;如何高效地管理、展示和报名参加这些会议活动&#xff0c;一直是许多组织者面临的难题。下面&#xff0c;小编给大家分享一款微信会议活动微展示在…

android camera系列(Camera1、Camera2、CameraX)的使用以及输出的图像格式

一、Camera 1.1、结合SurfaceView实现预览 1.1.1、布局 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-au…

cartographer离线建图报错:data_.trajectory_nodes.SizeOfTrajectoryOrZero

cartographer离线建图报错: data_.trajectory_nodes.SizeOfTrajectoryOrZero [FATAL] [1706177325.876019302, 1706015603.398505596]: F0125 18:08:45.000000 17607 pose_graph_2d.cc:1314] Check failed: data_.trajectory_nodes.SizeOfTrajectoryOrZero(trajectory_id) &…

git用法总结

以gitee为例&#xff0c;GitHub也可参考本文 创建远程仓库 在自己的gitee主页 创建本地仓库 在文件夹下&#xff0c;右键→git bash here git init添加gitignore vi .gitignoregitignore里的内容根据自己实际情况设置&#xff0c;这里举个例子 # #开头的是注释 # Prer…

DevSecOps 参考模型介绍

目录 一、参考模型概述 1.1 概述 二、参考模型分类 2.1 DevOps 组织型模型 2.1.1 DevOps 关键特性 2.1.1.1 模型特性图 2.1.1.2 特性讲解 2.1.1.2.1 自动化 2.1.1.2.2 多边协作 2.1.1.2.3 持续集成 2.1.1.2.4 配置管理 2.1.2 DevOps 生命周期 2.1.2.1 研发过程划分…

查看php-fpm占用内存情况

1、查看每个php-fpm占用的内存大小 ps -ylC php-fpm --sort:rss 2 查看单个php-fpm进程消耗内存的明细 pmap $(pgrep php-fpm) | less pmap pmap命令用于显示一个或多个进程的内存状态 pmap [ -x | -d ] [ -q ] pids 参数&#xff1a; -x extended Show the extended f…

对于小微企业而言,数字化转型的重要性是什么?

数字化转型对于小微企业至关重要&#xff0c;原因如下&#xff1a; 1.效率和生产力&#xff1a;采用数字工具和技术可以简化业务流程、自动化重复性任务并提高整体效率。这使得小型企业能够用更少的资源完成更多的工作&#xff0c;最终提高生产力。 2.节省成本&#xff1a;数…

DevSecOps 发展历史概述

目录 一、发展概述 1.1概述说明 二、DevSecOps 发展关键里程碑 2.1 2012年Gartner首次提出DevSecOps概念 2.2 2016年Gartner发布DevSecOps议题报告 2.3 2017年美国RSAC大会开辟DevSecOps专题 2.4 2018年美国RSAC大会提出黄金管道概念 2.5 2019年Gartner 发布了DevSecOps…

如何在Excel中隐藏部分数字或文本?这里提供几个方法

假设你有一张关于员工的一般信息表&#xff0c;但有些是私人的&#xff0c;比如社会安全号码。现在你想隐藏这些社会安全号码的一部分&#xff0c;如下截图所示&#xff0c;你如何快速解决它&#xff1f; 使用单元格格式部分隐藏 若要在Excel中隐藏部分社会保障号码&#xff…

Linux本地部署SVN服务结合内网穿透实现远程访问

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

ORM-05-javalite activejdbc 入门介绍

拓展阅读 The jdbc pool for java.(java 手写 jdbc 数据库连接池实现) The simple mybatis.&#xff08;手写简易版 mybatis&#xff09; ActiveJDBC ActiveJDBC 可以直接通过读取表的信息&#xff0c;来处理数据库相关操作。 优点 java model 中不需要任何的属性&#xff0…

绿原酸市场调研:预计2029年将达到1.8亿美元

绿原酸是一种有机化合物&#xff0c;化学式为C16H18O9&#xff0c;是金银花的主要抗菌、抗病毒有效药理成分之一。绿原酸具有较广泛的抗菌作用&#xff0c;但在体内能被蛋白质灭活。与咖啡酸相似&#xff0c;口服或腹腔注射时&#xff0c;可提高大鼠的中枢兴奋性。可增加大鼠及…

JavaScript柯里化与部分应用

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ 目录 ✨ 前言 ✨ 正文 一、函数柯里化(Currying) 什么是柯里化 柯里化实现…

python爬各平台评论并数据分析——数据采集、评论情绪分析、新闻热度

一、爬取数据 小问题汇总 1.python之matplotlib使用系统字体 用于解决python绘图中&#xff0c;中文字体显示问题 2.cookie与视频页面id&#xff08;b站、微博等&#xff09;查看 F12打开网页开发者模式&#xff0c;然后F5刷新&#xff0c;进入控制台中的网络&#xff0c;…

为何外贸公司应该采用CRM客户管理软件?

在外贸行业中&#xff0c;客户关系管理尤为关键。在当下的大数据背景下&#xff0c;所有规模的外贸公司都迫切地需要进行数字化改造。无论是大型公司还是小型业务&#xff0c;他们都希望通过深入分析客户数据&#xff0c;为用户提供更优的体验&#xff0c;并据此调整企业战略。…

自动化批量导入机器到Jumpserver:提高效率与一致性的关键步骤

Ansible批量主机机器到Jumpserver 1、背景 在现代 IT 环境中&#xff0c;随着机器数量的增加和复杂性的提高&#xff0c;手动管理和配置机器变得越来越困难和耗时。为了提高效率并确保一致性&#xff0c;自动化工具成为了不可或缺的一部分。Jumpserver 是一个功能强大的堡垒机…

Linux之系统安全与应用

Linux系统提供了多种机制来确保用户账号的正当&#xff0c;安全使用。 系统安全措施 一. 清理系统账号 1.1 将用户设置为无法登录 Linux系统中除手动创建的各种账号外&#xff0c;还包括随系统或程序安装过程而生成的其他大量账号。除了超级用户root以外&#xff0c;其他的…

企业能源消耗监测管理系统是否可以做好能源计量与能耗分析?

能源消耗与分析是能源科学管理的基础&#xff0c;也可促进能源管理工作的改善&#xff0c;在企业中能源管理系统的作用也愈加重要。 首先&#xff0c;能源计量是能源管理的基础&#xff0c;通过能源精准计老化&#xff0c;容易出现测量设备不准确以及其他一些人为因素原因导致…