当前位置: 首页 > 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 …...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...