机器视觉opencv教程(二):二值化、自适应二值化

文章目录

  • 机器视觉opencv教程(二):二值化、自适应二值化
    • 一、二值化图基础概念
    • 二、传统二值化方法(基于全局固定阈值)
      • 1. 阈值法(THRESH_BINARY)
      • 2. 反阈值法(THRESH_BINARY_INV)
      • 3. 截断阈值法(THRESH_TRUNC)
      • 4. 低阈值零处理(THRESH_TOZERO)
      • 5. 超阈值零处理(THRESH_TOZERO_INV)
    • 三、OTSU 阈值法(自动找最优阈值)
      • 1. 核心原理
      • 2. 代码实现(需与传统二值化方法结合)
      • 3. 特点与适用场景
    • 四、自适应二值化(局部动态阈值)
      • 1. 核心问题(传统方法的缺陷)
      • 2. 自适应二值化原理
      • 4. 关键参数说明
    • 五、补充:常见问题与注意事项

机器视觉opencv教程(二):二值化、自适应二值化

一、二值化图基础概念

  • 定义:二值化图是仅含两种像素值的图像,通常为 0(纯黑色)255(纯白色)
  • 操作前提:二值化的处理对象必须是灰度图(无法直接对彩色图进行二值化),本质是通过 “阈值判断” 将灰度图的连续亮度值(0~255)映射为两种离散值,突出前景与背景的边界。
  • 核心目的:简化图像数据(仅 1 个通道 + 2 种值)、消除灰度噪声、强化目标区域(如文字识别中突出文字、工业检测中突出缺陷)。

在这里插入图片描述

二、传统二值化方法(基于全局固定阈值)

传统二值化通过设定全局唯一阈值(thresh)最大值(maxval,通常为 255),对灰度图所有像素统一判断,常见 5 种方法:

1. 阈值法(THRESH_BINARY)

  • 原理:像素值与阈值比较
    • 若像素值 ≤ thresh → 设为 0(黑)
    • 若像素值 > thresh → 设为 maxval(白)
  • 特点:亮部(> 阈值)保留为白色,暗部(≤阈值)转为黑色,适合前景比背景亮的场景(如白底黑字)。
import cv2
import numpy as np# 1. 读取彩色图→转为灰度图(二值化前提)
image_np = cv2.imread('./gogogo.png')
# 【补充】检查图片读取状态
if image_np is None:raise ValueError("图片读取失败,请确认路径正确!")
image_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 2. 设定参数
thresh = 150  # 全局阈值(需手动调整,根据图像明暗度适配)
maxval = 255  # 二值化后的最大值(通常为255,纯白)# 3. OpenCV接口实现(推荐,高效)
# ret:返回的阈值(与设定的thresh一致,传统方法中无实际作用)
# image_thresh:二值化结果(单通道图)
ret, image_thresh = cv2.threshold(image_gray, thresh, maxval, cv2.THRESH_BINARY)# # 4. 手动实现(理解原理用)
# image_shape = image_gray.shape
# image_thresh = np.zeros((image_shape[0], image_shape[1]), dtype=np.uint8)
# for i in range(image_shape[0]):  # 遍历高度(行)
#     for j in range(image_shape[1]):  # 遍历宽度(列)
#         if image_gray[i, j] > thresh:
#             image_thresh[i, j] = maxval
#         else:
#             image_thresh[i, j] = 0# 5. 显示结果
cv2.imshow('灰度图', image_gray)
cv2.imshow('THRESH_BINARY二值化图', image_thresh)
cv2.waitKey(0)  # 按任意键关闭窗口
cv2.destroyAllWindows()  # 释放资源

2. 反阈值法(THRESH_BINARY_INV)

  • 原理:与阈值法完全相反
    • 若像素值 > thresh → 设为 0(黑)
    • 若像素值 ≤ thresh → 设为 maxval(白)
  • 特点:暗部保留为白色,亮部转为黑色,适合前景比背景暗的场景(如黑底白字)。
import cv2
import numpy as np# 1. 彩色图→灰度图
image_np = cv2.imread('./gogogo.png')
if image_np is None:raise ValueError("图片读取失败!")
image_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 2. 设定参数
thresh = 127  # 常用默认阈值(可根据图像调整)
maxval = 255# 3. OpenCV接口实现(核心参数:cv2.THRESH_BINARY_INV)
ret, image_thresh = cv2.threshold(image_gray, thresh, maxval, cv2.THRESH_BINARY_INV)# # 4. 手动实现(原理参考阈值法,判断条件反转)
# image_shape = image_gray.shape
# image_thresh = np.zeros((image_shape[0], image_shape[1]), dtype=np.uint8)
# for i in range(image_shape[0]):
#     for j in range(image_shape[1]):
#         if image_gray[i, j] > thresh:
#             image_thresh[i, j] = 0
#         else:
#             image_thresh[i, j] = maxval# 5. 显示
cv2.imshow('THRESH_BINARY_INV二值化图', image_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 特点:暗部保留为白色,亮部转为黑色,适合前景比背景暗的场景(如黑底白字)。

3. 截断阈值法(THRESH_TRUNC)

  • 原理:限制像素值上限
    • 若像素值 > thresh → 设为 thresh(截断为阈值)
    • 若像素值 ≤ thresh → 保持原值不变
  • 特点:图像最大亮度为阈值,可抑制过亮区域(如强光噪声),但不是严格 “二值图”(仍含多个灰度值)。
import cv2
import numpy as np# 1. 彩色图→灰度图
image_np = cv2.imread('./gogogo.png')
if image_np is None:raise ValueError("图片读取失败!")
image_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 2. 设定参数
thresh = 150  # 截断阈值(超过该值的亮度会被“压平”)
maxval = 255  # 此方法中maxval无实际作用(可设任意值)# 3. OpenCV接口实现(核心参数:cv2.THRESH_TRUNC)
ret, image_thresh = cv2.threshold(image_gray, thresh, maxval, cv2.THRESH_TRUNC)# # 4. 手动实现
# image_shape = image_gray.shape
# image_thresh = np.zeros((image_shape[0], image_shape[1]), dtype=np.uint8)
# for i in range(image_shape[0]):
#     for j in range(image_shape[1]):
#         if image_gray[i, j] > thresh:
#             image_thresh[i, j] = thresh
#         else:
#             image_thresh[i, j] = image_gray[i, j]# 5. 显示(对比灰度图,亮部会明显变暗)
cv2.imshow('原灰度图', image_gray)
cv2.imshow('THRESH_TRUNC截断图', image_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

4. 低阈值零处理(THRESH_TOZERO)

  • 原理:暗部置零,亮部保留
    • 若像素值 ≤ thresh → 设为 0(黑)
    • 若像素值 > thresh → 保持原值不变
  • 特点:仅保留亮部细节,暗部直接变黑,适合突出高亮度目标(如金属表面的反光缺陷)。

5. 超阈值零处理(THRESH_TOZERO_INV)

  • 原理:亮部置零,暗部保留
    • 若像素值 > thresh → 设为 0(黑)
    • 若像素值 ≤ thresh → 保持原值不变
  • 特点:仅保留暗部细节,亮部直接变黑,适合突出低亮度目标(如暗背景中的深色物体)。

三、OTSU 阈值法(自动找最优阈值)

1. 核心原理

  • OTSU(大津法)是自动阈值选择算法,无需手动调参:
    1. 将灰度图像素分为 “前景”(> 阈值)和 “背景”(≤阈值)两类;
    2. 遍历所有可能阈值(从灰度最小值 + 1 到最大值 - 1),计算 “类间方差”;
    3. 类间方差最大时的阈值即为 “最优阈值”(此时前景与背景区分最明显)。

2. 代码实现(需与传统二值化方法结合)

import cv2
import numpy as np# 1. 彩色图→灰度图
image_np = cv2.imread('./flower.png')
if image_np is None:raise ValueError("图片读取失败!")
image_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 2. 设定参数(thresh仅为初始值,OTSU会自动覆盖)
thresh = 127  # 初始值无意义,OTSU会计算最优阈值
maxval = 255# 3. OpenCV接口实现(核心:cv2.THRESH_OTSU + 传统方法)
# ret:返回OTSU计算出的最优阈值(不再是初始值127)
ret, image_thresh = cv2.threshold(image_gray, thresh, maxval, cv2.THRESH_BINARY + cv2.THRESH_OTSU  # 结合阈值法,也可结合其他方法
)
print(f"OTSU自动计算的最优阈值:{ret}")  # 输出最优阈值,便于后续参考# # 4. 手动实现(理解OTSU算法逻辑,实际用OpenCV接口即可)
# min_val = image_gray.min()
# max_val = image_gray.max()
# var_dict = {}  # 存储“阈值→类间方差”
# 
# for t in range(min_val + 1, max_val):
#     # 分割前景(>t)和背景(≤t)
#     foreground = image_gray[image_gray > t]
#     background = image_gray[image_gray ≤ t]
#     # 计算类间方差(公式:w0*(u0-u)^2 + w1*(u1-u),w为权重,u为均值)
#     w0 = len(foreground) / (image_gray.size)
#     w1 = len(background) / (image_gray.size)
#     u0 = foreground.mean() if len(foreground) > 0 else 0
#     u1 = background.mean() if len(background) > 0 else 0
#     u = (w0*u0) + (w1*u1)
#     class_var = w0 * (u0 - u)**2 + w1 * (u1 - u)**2
#     var_dict[t] = class_var
# # 找类间方差最大的阈值
# best_thresh = max(var_dict, key=var_dict.get)
# print(f"手动计算的最优阈值:{best_thresh}")# 5. 保存+显示结果
cv2.imwrite('OTSU二值化图.png', image_thresh)  # 保存结果
cv2.imshow('OTSU二值化图', image_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

3. 特点与适用场景

  • 优势:自动适配图像明暗,无需手动调阈值,比固定阈值更鲁棒;
  • 适用:前景与背景灰度差异明显的图像(如文档扫描图、简单目标检测);
  • 注意:仅适用于 “双峰灰度分布”(灰度直方图有两个明显峰值,分别对应前景和背景),若图像灰度分布均匀,效果较差。

四、自适应二值化(局部动态阈值)

1. 核心问题(传统方法的缺陷)

传统二值化(含 OTSU)用全局固定阈值,若图像明暗分布不均(如左侧亮、右侧暗),会导致部分区域二值化过度(亮区暗部变黑)或不足(暗区亮部变白)。

2. 自适应二值化原理

  • 对图像每个像素,用其局部邻域(如 3×3、5×5 窗口)的亮度计算 “局部阈值”,而非全局统一阈值;
  • 每个像素的阈值由自身周围像素决定,能自适应不同区域的明暗差异。
import cv2
import numpy as np# 1. 读取彩色图→转为灰度图
image_np = cv2.imread('./gogogo.png')  # 建议用明暗不均的图测试(如逆光拍摄的图)
if image_np is None:raise ValueError("图片读取失败!")
image_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 2. 自适应二值化(核心函数:cv2.adaptiveThreshold)
image_binary = cv2.adaptiveThreshold(image_gray,                # 输入:单通道灰度图255,                       # 二值化最大值(通常为255)cv2.ADAPTIVE_THRESH_GAUSSIAN_C,  # 局部阈值计算方法:高斯加权平均(推荐,更平滑)# cv2.ADAPTIVE_THRESH_MEAN_C,   # 备选:局部邻域均值(计算更快,可能有噪声)cv2.THRESH_BINARY,         # 二值化方法(可换为THRESH_BINARY_INV)blockSize=7,               # 局部邻域大小(必须为奇数,如3、5、7,越大越平滑)C=5                        # 从局部阈值中减去的常数(正数:降低二值化严格度,减少黑块)
)# 3. 显示对比(与全局阈值法对比,明暗不均区域效果更优)
# 全局阈值法(对比用)
ret_global, image_global = cv2.threshold(image_gray, 127, 255, cv2.THRESH_BINARY)cv2.imshow('原灰度图', image_gray)
cv2.imshow('全局阈值二值化', image_global)
cv2.imshow('自适应二值化', image_binary)
cv2.waitKey(0)
cv2.destroyAllWindows()

4. 关键参数说明

参数作用
blockSize局部邻域大小(奇数),越大对明暗不均的适应能力越强,但细节保留越少;
C阈值修正常数,正数→局部阈值降低(更多像素变白),负数→局部阈值升高(更多像素变黑);
阈值计算方法ADAPTIVE_THRESH_GAUSSIAN_C(高斯加权,效果好) vs ADAPTIVE_THRESH_MEAN_C(均值,速度快);

五、补充:常见问题与注意事项

  1. 图片读取失败:确保路径正确(相对路径需与代码文件同级,绝对路径需写全),格式支持(JPG、PNG、BMP 等);
  2. 二值化结果过暗 / 过亮:
    • 全局阈值法:调整thresh(暗→降低阈值,亮→升高阈值);
    • 自适应法:调整C(暗→增大C,亮→减小C)或blockSize
  3. OTSU 效果差:检查图像灰度直方图是否为 “单峰”(明暗分布均匀),此类图需用自适应二值化;
  4. 代码效率:手动实现仅用于理解原理,实际项目用 OpenCV 接口(C++ 优化,速度远快于 Python 循环)。

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

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

相关文章

leetcode 461 汉明距离

一、问题描述二、解题思路采用位运算的思想来解决这个问题,首先,将x和y进行异或,x和y对应二进制位不同就会得到1,然后统计所有1的个数,即为汉明距离。三、代码实现时间复杂度:T(n)O(n)空间复杂度&#xff1…

ClickHouse 客户端

ClickHouse 客户端 ClickHouse提供两种客户端接口,分别基于 HTTP 和 TCP 协议 基于 HTTP 协议 主要用来支持轻量级的简单操作,方便跨平台和编程语言。 测试clickhouse联通性: $ curl http://localhost:8123/ Ok.在运行状况检查脚本中使用…

DBeaver 连接 PostgreSQL 教程

🛠️ DBeaver 连接 PostgreSQL 教程1️⃣ 安装 DBeaver打开官网:https://dbeaver.io/download/下载 Community Edition(免费版),选择对应系统(Windows / macOS / Linux)。安装完成后&#xff0c…

Komo Searc-AI驱动的搜索引擎

本文转载自:Komo Searc-AI驱动的搜索引擎 - Hello123工具导航 ** 一、🔍 Komo Search 是什么? Komo Search 是一款基于人工智能技术的新一代交互式搜索引擎,它彻底改变了我们获取信息的方式 —— 从被动检索变成主动对话。不同于…

HTML 和 JavaScript 关联的基础教程

HTML 和 JavaScript 是构建现代网页的核心技术。HTML 负责页面结构&#xff0c;JavaScript 负责动态交互。以下是两者的基本关联方式。内联方式&#xff1a;直接在 HTML 中嵌入 JavaScript在 HTML 文件中&#xff0c;可以通过 <script> 标签直接编写 JavaScript 代码。这…

淘宝四个月造了一个超越美团的“美团”

本周三&#xff0c;美团发布最新一季财报&#xff0c;利润承压导致股价爆跌。只隔一天&#xff0c;阿里也发布了最新季报&#xff0c;最大的亮点是“淘宝闪购”即时零售业务&#xff0c;日均订单量站稳8000万单&#xff0c;峰值订单更是达到了1.2亿单。8000万单这个数字令市场眼…

Java开发MongoDB常见面试题及答案

基础概念题1. 什么是MongoDB&#xff1f;它的主要特点是什么&#xff1f;答案&#xff1a; MongoDB是一个开源的NoSQL文档型数据库&#xff0c;主要特点包括&#xff1a;文档存储&#xff1a;使用BSON格式存储数据&#xff0c;类似JSON结构无Schema约束&#xff1a;灵活的数据结…

AI视频生成工具全景对比:元宝AI、即梦AI、清影AI和Vidu AI

AI视频生成技术正以前所未有的速度发展&#xff0c;成为内容创作领域的重要革新力量。本文将全面对比四款主流AI视频生成工具&#xff1a;元宝AI、即梦AI、清影AI生视频和Vidu AI&#xff0c;从公司背景、技术路线、产品特点、发展历程和市场定位等多个维度进行深入分析。一、基…

2026届大数据毕业设计选题推荐-基于Python的出行路线规划与推荐系统 爬虫数据可视化分析

&#x1f525;作者&#xff1a;it毕设实战小研&#x1f525; &#x1f496;简介&#xff1a;java、微信小程序、安卓&#xff1b;定制开发&#xff0c;远程调试 代码讲解&#xff0c;文档指导&#xff0c;ppt制作&#x1f496; 精彩专栏推荐订阅&#xff1a;在下方专栏&#x1…

基于SpringBoot的高校科研项目管理系统【2026最新】

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【开题答辩全过程】以 在线考试系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

Marin说PCB之POC电路layout设计仿真案例---11

上节文章中大家不知道发现没有我们RX0_96712_FAKRA_3--TDR结果显示芯片端口阻抗还是偏低一些&#xff0c;但是这个该如何去改善优化设计呢&#xff1f;因为目前的PCB设计上&#xff0c;RX0_96712_FAKRA_3这个信号在芯片焊盘处是已经做了隔层参考的优化处理了&#xff1a;RX0_96…

【踩坑】修复 clear 报错 terminals database is inaccessible

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 主要原因&#xff1a;Anaconda3 路径中的 clear 命令干扰了系统中的 clear 命令。 可能操作&#xff1a;你可能在安装后将 anaconda 目录移动了&#…

重学JS-005 --- JavaScript算法与数据结构(五)回顾 DOM 操作

文章目录style.displayinnerText学到的代码写法小总结style.display 使用元素的 style.display 属性&#xff0c;将属性的值设置为 “block” 或 “none”&#xff0c;可以显示或隐藏元素。 resetGameBtn.style.display block; optionsContainer.style.display none;innerT…

ArcGIS:如何设置地图文档的相对路径或者发布为地图包

设置好的地图文档在分享给别人使用或查看时&#xff0c;可能会出现这样的问题&#xff1a;这是因为地图文档里面的数据存储的是绝对路径&#xff0c;当别人打开时&#xff0c;地图文档无法识别到正确的数据路径。遇到这样的问题有三种解决办法&#xff1a;点击未能加载的数据&a…

深入解析 Java interrupt

Java 中断(Interrupt)机制详解 Java 的中断机制是一种协作式的线程间通信机制&#xff0c;用于请求另一个线程停止当前正在执行的操作。 Thread thread Thread.currentThread(); thread.interrupt(); // 设置当前线程的中断状态 检查中断状态 // 检查中断状态 boolean isI…

SOME/IP-SD事件组订阅

<摘要> 本文将结合AUTOSAR R22-11版本的《PRS_SOMEIPServiceDiscoveryProtocol》规范&#xff0c;解析SOME/IP-SD协议中的事件组订阅机制。针对“事件组订阅”&#xff0c;将从背景概念、设计意图、实际案例及图示等角度展开分析&#xff0c;通过通俗易懂的阐述和图文表格…

龙虎榜——20250829

上证指数今天收小阳线继续站上5天均线&#xff0c;量能稍有回落但仍在200天均量线上&#xff0c;目前均线多头排列依然强势&#xff0c;小级别暂未出现反转信号&#xff0c;但需要注意高低切换的风险。深证指数今天量能略有回落收阳线&#xff0c;创了阶段新高&#xff0c;走势…

vue在函数内部调用onMounted

在 Vue 3 中&#xff0c;函数内部定义的 onMounted 回调&#xff0c;若该函数从未被调用&#xff0c;则 onMounted 不会执行。这一结论的核心逻辑与 Vue 组合式 API&#xff08;Composition API&#xff09;的“调用时机”和“生命周期钩子注册规则”直接相关&#xff0c;具体可…

可解释人工智能XAI

可解释人工智能&#xff08;XAI&#xff09;方法&#xff08;例如常见的XGBoost-SHAP方法&#xff09;可以捕捉到非线性的关系&#xff0c;但这种方法忽略了地理单元之间的空间效应&#xff1b;而传统的空间模型&#xff08;例如常见的GWR&#xff09;虽然考虑了空间效应&#…