当前位置: 首页 > news >正文

灰度图像的自动阈值分割

第一种:Otsu (大津法)

一、基于cv2的API调用

1、代码实现

直接给出相关代码:

import cv2
import matplotlib.pylab as pltpath = 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 nppath = 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_arrimg = 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 nppath = r"D:\Desktop\00aa\1.png"
img = cv2.imread(path, 0)def OTSU(img_gray, GrayScale): # GrayScale:灰度图中灰度值的最大值,这里需要在将此值加1。即:灰度图最大值+1assert 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):# 默认灰度图像的像素值范围为GrayScalePixvalue = img_gray[i]PixCount[Pixvalue] = PixCount[Pixvalue] + 1# 确定各个灰度值对应的像素点的个数在所有的像素点中的比例。for j in range(GrayScale):PixRate[j] = PixCount[j] * 1.0 / PixSumMax_var = 0# 确定最大类间方差对应的阈值for i in range(1, GrayScale):  # 从1开始是为了避免w1为0.u1_tem = 0.0u2_tem = 0.0# 背景像素的比列w1 = np.sum(PixRate[:i])# 前景像素的比例w2 = 1.0 - w1if w1 == 0 or w2 == 0:passelse:  # 背景像素的平均灰度值for m in range(i):u1_tem = u1_tem + PixRate[m] * mu1 = u1_tem * 1.0 / w1# 前景像素的平均灰度值for n in range(i, GrayScale):u2_tem = u2_tem + PixRate[n] * nu2 = u2_tem / w2# print(u1)# 类间方差公式:G=w1*w2*(u1-u2)**2tem_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 = ireturn thdef 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 中的二值化

相关文章:

灰度图像的自动阈值分割

第一种&#xff1a;Otsu &#xff08;大津法&#xff09; 一、基于cv2的API调用 1、代码实现 直接给出相关代码&#xff1a; import cv2 import matplotlib.pylab as pltpath r"D:\Desktop\00aa\1.png" img cv2.imread(path, 0)def main2():ret, thresh1 cv2.…...

利用Maven获取jar包

我有一个习惯&#xff0c;就是程序不在线依赖网络的任何包。以前用C#时候虽然用Nuget找包&#xff0c;但是添加引用后又马上把Nuget引用删了&#xff0c;再把Nuget下载的dll拷贝到工程再引用dll。 这样做的好处是&#xff1a; 1.别人得到程序代码可以直接编译&#xff0c;不用…...

将vue组件发布成npm包

文章目录 前言一、环境准备1.首先最基本的需要安装nodejs&#xff0c;版本推荐 v10 以上&#xff0c;因为需要安装vue-cli2.安装vue-cli 二、初始化项目1.构建项目2.开发组件/加入组件3. 修改配置文件 三、调试1、执行打包命令2、发布本地连接包3、测试项目 四、发布使用1、注册…...

江科大STM32 中

目录 6、TIM&#xff08;Timer&#xff09;定时器基本定时器通用定时器高级定时器示例程序&#xff08;定时器定时中断&定时器外部时钟&#xff09;TIM输出比较示例程序&#xff08;PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机&#xff09;TIM输入捕获示例程序&…...

vue+draggable+el-upload上传图片拖拽重排方法

vuedraggableel-upload上传图片拖拽重排方法 1.html <el-row><el-col><el-form-item label"添加视频/图片" prop"device_id"><div class"image-upload"><draggable v-model"fileList" update"dataDr…...

微信的新版canvas绘制的图案发生变形和偏移的问题

一,现象 this.context.beginPath(); this.context.moveTo(10, 10); this.context.lineTo(10, 100); this.context.lineTo(100, 100); this.context.lineTo(100, 10); this.context.lineTo(10, 10); this.context.stroke();本来绘制的是正方形,结果绘制出来是个矩形,边的宽度也…...

[ACM学习] 进制转换

进制的本质 本质是每一位的数位上的数字乘上这一位的权重 将任意进制转换为十进制 原来还很疑惑为什么从高位开始&#xff0c;原来从高位开始的&#xff0c;可以被滚动地乘很多遍。 将十进制转换为任意进制...

redis + 拦截器 :防止数据重复提交

1.项目用到,不是核心 我们干系统开发,不免要考虑一个点&#xff0c;数据的重复提交。 我想我们之前如果要校验数据重复提交要求&#xff0c;会怎么干?会在业务层&#xff0c;对数据库操作&#xff0c;查询数据是否存在,存在就禁止插入数据; 但是吧,我们每次crud操作都会连接…...

如何进行H.265视频播放器EasyPlayer.js的中性化设置?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…...

Ubuntu22.04安装4090显卡驱动

1、安装完Ubuntu系统&#xff0c;打完所有补丁后再进行后续操作 2、下载系统所需要的版本的NV显卡驱动&#xff0c;本次由于使用CUDA12.1&#xff0c;故选用的驱动版本为NVIDIA-Linux-x86_64-530.41.03.run 3、卸载NV驱动&#xff08;只是保险起见&#xff0c;并不是一定会卸…...

YOLOv8优化策略:注意力涨点系列篇 | 一种轻量级的加强通道信息和空间信息提取能力的MLCA注意力

🚀🚀🚀本文改进:一种轻量级的加强通道信息和空间信息提取能力 MLCA注意力 🚀🚀🚀在YOLOv8中如何使用 1)作为注意力机制使用;2)与c2f结合使用; 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研…...

【新书推荐】2.5节 有符号整数和无符号整数

本节内容&#xff1a;整数的编码规则。 ■数据的编码规则&#xff1a;计算机的二进制数对于计算机本身而言仅仅表示0和1。人们按照不同的编码规则赋予二进制数不同的含义。整数的编码规则分为有符号整数和无符号整数。 ■数据的存储规则&#xff1a;x86计算机以字节为单位&…...

RT-Thread: 串口操作、增加串口、串口函数

说明&#xff1a;本文记录RT-Thread添加串口的步骤和串口的使用。 1.新增串口 官方链接&#xff1a;https://www.rt-thread.org/document/site/rtthread-studio/drivers/uart/v4.0.2/rtthread-studio-uart-v4.0.2/ 新增串口只需要在 board.h 文件中定义相关串口的宏定…...

自然语言处理的新突破:如何推动语音助手和机器翻译的进步

一、语音助手方面的进展 语音助手作为人机交互的重要入口之一,其性能的提升离不开自然语言处理技术的进步。基于深度学习的语音识别和语义理解技术,使得语音助手可以更准确地分析用户意图,提供个性化服务。 语音识别精度的持续提高 语音识别是语音助手的基础。随着深度神经网…...

vue3 + jeecgBoot 获取项目IP地址

封装的useGlobSetting 函数 引入并使用 import { useGlobSetting } from //hooks/setting;const glob useGlobSetting();console.log(glob.uploadUrl) //http://192.168.105.57:7900/bs-axfd...

Java Server-Sent Events通信

Server-Sent Events特点与优势 后端可以向前端发送信息&#xff0c;类似于websocket&#xff0c;但是websocket是双向通信&#xff0c;但是sse为单向通信&#xff0c;服务器只能向客户端发送文本信息&#xff0c;效率比websocket高。 单向通信&#xff1a;SSE只支持服务器到客…...

[蓝桥杯]真题讲解:冶炼金属(暴力+二分)

蓝桥杯真题视频讲解&#xff1a;冶炼金属&#xff08;暴力做法与二分做法&#xff09; 一、视频讲解二、暴力代码三、正解代码 一、视频讲解 视频讲解 二、暴力代码 //暴力代码 #include<bits/stdc.h> #define endl \n #define deb(x) cout << #x << &qu…...

Fastbee开源物联网项目RoadMap

架构优化 代码简化业务&协议解耦关键组件支持横向拓展网络协议支持横向拓展&#xff0c;包括&#xff1a;mqtt broker,tcp,coap,udp,sip等协议插件化编码脚本化业务代码模版化消息总线 功能优化 网关/子网关&#xff1a;上线&#xff0c;绑定&#xff0c;拓扑&#xff0…...

Linux文件管理技术实践

shell shell的种类(了解) shell是用于和Linux内核进行交互的一个程序&#xff0c;他的功能和window系统下的cmd是一样的。而且shell的种类也有很多常见的有c shell、bash shell、Korn shell等等。而本文就是使用Linux最常见的bash shell对Linux常见指令展开探讨。 内置shell…...

Python如何按指定列的空值删除行?

目录 1、按指定列的空值删除行2、滑动窗口按指定列的值填充最前面的缺失值 1、按指定列的空值删除行 数据准备&#xff1a; df pd.DataFrame({C1: [1, 2, 3, 4], C2: [A, np.NaN, C, D], C3: [V1, V2, V3, np.NaN]}) print(df.to_string()) C1 C2 C3 0 1 A V1 1 …...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...