OpenCV计算机视觉实战(9)——阈值化技术详解

news2025/6/4 8:40:51

OpenCV计算机视觉实战(9)——阈值化技术详解

    • 0. 前言
    • 1. 全局阈值与自适应阈值
    • 2. Otsu 算法
    • 3. 实战案例:文档扫描中的二值化处理
    • 4. 算法对比
    • 小结
    • 系列链接

0. 前言

在图像处理领域,阈值化 (Binarization) 技术就像一把魔术剪刀,能够将复杂的灰度图像一分为二,提取出关键的前景信息。无论是光照均匀的实验室拍摄,还是手机拍摄的阴影斑驳文档,选择合适的阈值化方法都至关重要。本文将介绍 OpenCV 中的三大阈值化法——全局阈值、自适应阈值与 Otsu 算法,剖析它们的原理与优缺点,并通过一个真实的文档扫描案例演示如何在实际场景下灵活组合与应用。

1. 全局阈值与自适应阈值

阈值化 (Binarization) 是图像处理中的基础操作,旨在将灰度图像转换为黑白图像,以便于后续的轮廓提取、光学字符识别 (Optical Character Recognition, OCR) 或图像分割。OpenCV 提供的两种主要阈值化方法包括:

  • 全局阈值 (Global Thresholding):对整幅图像使用一个固定的阈值,适用于光照均匀的图像
  • 自适应阈值 (Adaptive Thresholding):根据图像的局部区域动态计算阈值,适用于光照不均或背景复杂的图像

接下来,读取图像并预处理,将图像转换为灰度图,使用中值滤波去除噪声,并对比两种不同的阈值化技术:

  • 全局阈值化:使用 cv2.threshold 函数,设置固定阈值 (如 127) 进行二值化
  • 自适应阈值化:使用 cv2.adaptiveThreshold 函数,分别采用均值法 (Mean) 和高斯加权法 (Gaussian) 进行局部阈值计算
import cv2

# 读取图像并转换为灰度
img = cv2.imread('1.jpeg', cv2.IMREAD_GRAYSCALE)
blur = cv2.medianBlur(img, 5)

# 全局阈值
_, th_global = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY)

# 自适应阈值 - Mean
th_mean = cv2.adaptiveThreshold(
    blur, 255,
    cv2.ADAPTIVE_THRESH_MEAN_C,
    cv2.THRESH_BINARY,
    blockSize=11, C=2
)

# 自适应阈值 - Gaussian
th_gauss = cv2.adaptiveThreshold(
    blur, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY,
    blockSize=11, C=2
)

# 显示结果
cv2.imshow('Global Thresholding', th_global)
cv2.imshow('Adaptive Mean Thresholding', th_mean)
cv2.imshow('Adaptive Gaussian Thresholding', th_gauss)
cv2.waitKey(0)
cv2.destroyAllWindows()

阈值化

关键函数解析:

  • cv2.threshold(src, thresh, maxval, type):对整个图像使用同一阈值进行二值化,其中 thresh 为阈值,maxval 为当像素值超过了阈值(或者小于阈值,根据 type 来决定)所赋予的值,type 可指定二值化操作的类型,包含以下 5 种类型:
    • cv2.THRESH_BINARY,超过阈值部分取 maxval (最大值),否则取 0
    • cv2.THRESH_BINARY_INVTHRESH_BINARY 的反转
    • cv2.THRESH_TRUNC,大于阈值部分设为阈值,否则不变
    • cv2.THRESH_TOZERO,大于阈值部分不改变,否则设为 0
    • cv2.THRESH_TOZERO_INVTHRESH_TOZERO 的反转
  • cv2.adaptiveThreshold(src, maxval, adaptiveMethod, thresholdType, blockSize, C):自适应阈值化,针对图像的每个局部区域 (blockSize × blockSize) 计算阈值,adaptiveMethod 可选 ADAPTIVE_THRESH_MEAN_C (局部平均值)或 ADAPTIVE_THRESH_GAUSSIAN_C (局部加权平均)

2. Otsu 算法

Otsu 算法是一种自动确定图像全局阈值的方法,特别适用于具有双峰 (bimodal) 直方图的图像。该算法通过最大化类间方差(或最小化类内方差)来找到最佳阈值,从而将图像分为前景和背景两部分。
Otsu 算法流程如下:

  1. 计算图像直方图:统计每个灰度级别的像素数量
  2. 遍历所有可能的阈值:对于每个可能的阈值 t,计算前景和背景的类内方差
  3. 选择最佳阈值:找到使类内方差最小(或类间方差最大)的阈值 t,作为最佳阈值

这种方法不需要手动设置阈值,适用于光照均匀且前景与背景对比明显的图像。

import cv2

# 读取图像
img = cv2.imread('1.jpeg', cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (5, 5), 0)

# Otsu 阈值化
otsu_thresh, th_otsu = cv2.threshold(
    blur, 0, 255,
    cv2.THRESH_BINARY + cv2.THRESH_OTSU
)

print(f"Otsu 选的阈值: {otsu_thresh}")

cv2.imshow('Otsu Thresholding', th_otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()

Otsu 算法

关键函数解析:

  • cv2.threshold:当 type 参数中包含 cv2.THRESH_OTSU 时,函数会自动计算最佳阈值,并返回该值
  • cv2.GaussianBlur(src, ksize, sigmaX):在执行 Otsu 前对图像做高斯模糊,可有效降低噪声对阈值选取的影响

3. 实战案例:文档扫描中的二值化处理

在实际应用中,如手机扫描文档,常常会遇到光照不均、阴影干扰等问题。为了获得清晰的扫描效果,我们可以结合自适应阈值和 Otsu 算法,进行多阶段的图像处理。


import cv2

# 1. 读取并灰度化
color = cv2.imread('doc_photo.jpg')
gray = cv2.cvtColor(color, cv2.COLOR_BGR2GRAY)

# 2. 降噪
blur = cv2.medianBlur(gray, 3)

# 3. 自适应阈值初筛
adaptive = cv2.adaptiveThreshold(
    blur, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY, 15, 8
)

# 4. Otsu 细化
otsu_val, final = cv2.threshold(
    adaptive, 0, 255,
    cv2.THRESH_BINARY + cv2.THRESH_OTSU
)

# 5. 保存并展示
cv2.imwrite('scanned_doc.png', final)
cv2.imshow('Scanned Document', final)
cv2.waitKey(0)
cv2.destroyAllWindows()

处理结果

关键函数解析:

  • cv2.cvtColor(src, code):图像色彩空间转换,此处将 BGR 转为灰度,为阈值化做准备
  • cv2.imwrite(filename, img):将二值化结果写入文件,方便后续查看或集成至扫描应用

4. 算法对比

通过以上对比,我们可以得出以下结论:

  • 全局阈值:适用于光照均匀、对比明显的图像,处理速度快,但对光照变化敏感
  • 自适应阈值:适用于光照不均、背景复杂的图像,能更好地保留细节,但计算量较大
  • Otsu 算法:适用于双峰直方图的图像,能自动确定最佳阈值,但对噪声敏感

在实际应用中,需要根据图像的具体特点选择合适的阈值化方法,或将多种方法结合,以获得最佳的处理效果。

小结

在本文中,我们深入探讨 OpenCV 中三种常用阈值化 (Binarization) 技术:全局阈值 (Global Thresholding)、自适应阈值 (Adaptive Thresholding) 以及 Otsu 算法 (Otsu’s Method),并通过一个“文档扫描”二值化应用案例展示如何在实际场景中选用合适的阈值化方法。我们首先对比全局阈值与自适应阈值的适用场景与优缺点,接着剖析 Otsu 算法自动阈值选择原理,最后实现一个简单的文档扫描脚本,用于在复杂光照下获得清晰的扫描效果。

系列链接

OpenCV计算机视觉实战(1)——计算机视觉简介
OpenCV计算机视觉实战(2)——环境搭建与OpenCV简介
OpenCV计算机视觉实战(3)——计算机图像处理基础
OpenCV计算机视觉实战(4)——计算机视觉核心技术全解析
OpenCV计算机视觉实战(5)——图像基础操作全解析
OpenCV计算机视觉实战(6)——经典计算机视觉算法
OpenCV计算机视觉实战(7)——色彩空间详解
OpenCV计算机视觉实战(8)——图像滤波详解

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

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

相关文章

【Tauri2】049——upload

前言 这篇就看看一个简单地插件——upload Upload | Taurihttps://tauri.app/plugin/upload/upload的英文意思是“上传(程序或信息)”。 看来是用来上传文件的。 支持移动端 正文 安装 pnpm tauri add upload 在前后端都会安装,即 .plug…

4、数据标注的武林秘籍:Label-Studio vs CVAT vs Roboflow

开篇痛点:90%的模型效果取决于数据质量 "标注3小时,训练5分钟"——这是很多AI工程师的真实写照。上周有位读者训练YOLOv12时发现,同样的代码,换批数据mAP直接跌了15%,根本原因是标注不规范!本文…

Linux 基础IO(上)

目录 前言 重谈文件 文件操作 1.打开和关闭 2.对文件打开之后操作 理解文件fd 1.文件fd的分配规则与重定向 2.理解shell中的重定向 3.关于Linux下一切皆文件 关于缓冲区 1.为什么要有缓冲区 2.缓冲区刷新策略的问题 3.缓冲区的位置 前言 本篇到了我们linux中的文件…

el-tree拖拽事件,限制同级拖拽,获取拖拽后节点的前后节点,同级拖拽合并父节点name且子节点加入目标节点里

node-drag-start:开始拖拽节点时触发​​(按下鼠标按钮),无论是否允许放置,此事件都会触发。 allow-drop 返回 true 才能触发@node-drag-end="handleDragend"、@node-drop="handleDrop"; (1)allow-drop:动态控制​​是否允许放置; (2)node-dr…

day62—DFS—太平洋大西洋水流问题(LeetCode-417)

题目描述 有一个 m n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。 这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , hei…

《Python基础》第2期:环境搭建

在开始编写 Python 代码前,还需要搭建 Python 的开发环境。 电脑是没办法直接读懂 Python 代码的,而是需要一个解释器,实时把代码翻译成字节码,字节码再转换成 0 和 1,电脑就能读懂了。 Python 的运行过程就是翻译一行…

WSL 安装 Debian 12 后,Linux 如何安装 curl , quickjs ?

在 WSL 的 Debian 12 系统中安装 curl 非常简单,你可以直接使用 APT 包管理器从官方仓库安装。以下是详细步骤: 1. 更新软件包索引 首先确保系统的包索引是最新的: sudo apt update2. 安装 curl 执行以下命令安装 curl: sudo…

[CSS3]vw/vh移动适配

vw/vh 目标: 能够使用vw单位设置网页元素的尺寸 相对单位相对视口的尺寸计算结果.vw全称viewport width; 1vw1/100视口宽度 vh全称viewport height; 1vh1/100视口高度 体验vw和vh单位 <!DOCTYPE html> <html lang"en"> <head><meta charset…

YOLOX 的动态标签分类(如 SimOTA)与 Anchor-free 机制解析2025.5.29

YOLOX 的动态标签分类&#xff08;如 SimOTA&#xff09;与 Anchor-free 机制是其核心改进中的两个关键部分&#xff0c;它们在目标检测中的作用和实现方式存在显著差异。以下从原理、实现细节及效果三个方面进行详细对比&#xff1a; 一、核心原理与目标 1. Anchor-free 机制…

724.寻找数组的中心下标前缀和

题目链接&#xff1a; https://leetcode.cn/problems/find-pivot-index/ 这道题目我们可以使用暴力解法&#xff0c;就一个下标前数组之和&#xff0c;再求一个下标后数组之和&#xff0c;时间复杂度达到n方&#xff0c;我们来写一下&#xff1a; int pivotIndex(vector<in…

软考-系统架构设计师-第十六章 层次式架构设计理论与实践

层次式架构设计理论与实践 16.2 表现层框架设计16.3 中间层框架设计16.4 数据访问层设计16.5 数据架构规划与设计16.6 物联网层次架构设计 软件体系结构为软件系统提供了结构、行为和属性的高级抽象&#xff0c;由构成系统的元素描述这些元素的相互作用、指导元素集成的模式以及…

Docker学习笔记:基础知识

本文是自己的学习笔记 1、什么是Docker2、Docker的架构设计2.1、镜像&#xff08;Image&#xff09;2.2、容器&#xff08;Container&#xff09;2.3、仓库&#xff08;Repository)2.4、Docker使用场景案例 1、什么是Docker Docker是基于Go语言实现的云开源项目。它的角色是作…

5.2 初识Spark Streaming

在本节实战中&#xff0c;我们初步探索了Spark Streaming&#xff0c;它是Spark的流式数据处理子框架&#xff0c;具备高吞吐量、可伸缩性和强容错能力。我们了解了Spark Streaming的基本概念和运行原理&#xff0c;并通过两个案例演示了如何利用Spark Streaming实现词频统计。…

Python趣学篇:交互式词云生成器(jieba + Tkinter + WordCloud等)

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、为什么要做词云&#xff1f;让文字"活"起来&#xff01;二、核心…

理解解释器架构:原理、组成与运行机制全解析

目录 前言1. 什么是解释器架构2. 解释器的基本组成2.1 被解释执行的程序2.2 解释器引擎2.3 解释器内部状态2.4 程序执行的当前状态2.5 存储器模型 3. 解释器的工作原理3.1 解析源代码3.2 初始化运行环境3.3 逐条执行语法结构3.4 维护程序状态3.5 内存管理与变量作用域 4. 举例&…

2025华为OD机试真题+全流程解析+备考攻略+经验分享+Java/python/JavaScript/C++/C/GO六种语言最佳实现

华为OD全流程解析&#xff0c;备考攻略 快捷目录 华为OD全流程解析&#xff0c;备考攻略一、什么是华为OD&#xff1f;二、什么是华为OD机试&#xff1f;三、华为OD面试流程四、华为OD薪资待遇及职级体系五、ABCDE卷类型及特点六、题型与考点七、机试备考策略八、薪资与转正九、…

设计模式——桥接设计模式(结构型)

摘要 桥接设计模式是一种结构型设计模式&#xff0c;用于将抽象与实现解耦&#xff0c;使二者可以独立变化。它通过将一个类拆分为“抽象”和“实现”两部分&#xff0c;并通过桥接关系组合&#xff0c;避免了类继承层次结构过于庞大。桥接模式包含抽象类、扩充抽象类、实现类…

LLaDa——基于 Diffusion 的大语言模型 打平 LLama 3

这里分享一篇文章《Large Language Diffusion Models》&#xff0c;来自人民大学高领人工智能学院&#xff0c;一篇尝试改变传统自回归范&#xff08;预测下一个token&#xff09; LLM 架构&#xff0c;探索扩散模型在 LLM 上的作用&#xff0c;通过随机掩码-预测逆向思维&…

2. 数据结构基本概念 (2)

本文部分ppt、视频截图来自&#xff1a;[青岛大学-王卓老师的个人空间-王卓老师个人主页-哔哩哔哩视频] 1. 数据结构基本概念 1.1 数据类型和抽象数据类型 (1) 数据类型(Data Type) 概念 数据类型是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称。 在使用…

STM32F407寄存器操作(多通道单ADC+DMA)

1.前言 又是半年没更新了&#xff0c;趁着端午放假有点时间&#xff0c;并且最近项目要用这块知识&#xff0c;我就顺带研究一下ADC吧。 一般来说ADC主要用法包含了1.单通道软件触发&#xff08;这是最简单和最常用的用法&#xff09;2.单通道多次采集&#xff08;需要快速采…