计算机视觉(四):二值化

二值化,就是将图像从彩色或灰度模式转换为只有两种颜色(通常是黑色和白色)的模式。这个过程的本质是设定一个阈值 (Threshold),将图像中所有像素的灰度值与这个阈值进行比较。

基本原理

二值化的核心原理非常简单:

  1. 灰度化:如果原始图像是彩色的,首先需要将其转换为灰度图像。这是因为彩色图像有三个通道(红、绿、蓝),而灰度图像只有一个灰度通道,每个像素的值代表其亮度,从 0(最黑)到 255(最白)。
  2. 设定阈值:选择一个介于 0 到 255 之间的数值作为阈值。这个阈值是二值化成功的关键。
  3. 像素比较与转换 :遍历图像中的每一个像素,执行以下操作:
    • 如果像素的灰度值大于设定的阈值,就将其灰度值设置为一个固定值(通常是 255,代表白色)。
    • 如果像素的灰度值小于或等于设定的阈值,就将其灰度值设置为另一个固定值(通常是 0,代表黑色)。

经过上述处理后,图像中的所有像素都只剩下两种可能的值:0 和 255,从而得到了一个黑白分明的二值化图像。

为什么要进行二值化?

二值化是许多图像处理和计算机视觉任务中的一个重要预处理步骤。它之所以重要,主要有以下几个原因:

  • 简化图像数据:将图像从多级灰度简化为黑白两色,极大地减少了数据量和处理的复杂性。这使得后续的算法(如边缘检测、轮廓提取)可以更快、更高效地运行。
  • 突出目标:通过合适的阈值,可以有效地将图像中的前景目标(如文字、物体)从背景中分离出来,使其更加突出和易于识别。
  • 便于分析和识别:在光学字符识别(OCR)、条形码识别、医学图像分析等领域,二值化是必不可少的步骤。它能帮助算法更准确地识别出字符或病变区域。

如何选择合适的阈值?

选择阈值是二值化的核心挑战。错误的阈值会导致信息丢失或引入噪声。根据不同的应用场景,选择阈值的方法主要分为以下两类:

  1. 全局阈值(Global Thresholding)
    • 概念:对整张图像使用同一个固定的阈值。
    • 方法
      • 手动设置:根据经验或对图像的初步分析来设定一个固定的值。
      • 自动计算 :通过算法自动寻找一个最优的阈值,例如大津法(Otsu's method)。大津法的基本思想是找到一个阈值,使得前景和背景的方差最大化,从而实现最佳的分离效果。
    • 局限性:当图像的光照不均匀时,全局阈值效果会很差。例如,如果图像左侧很亮而右侧很暗,一个固定的阈值就无法同时正确地分离两边的目标。
  2. 局部阈值(Local/Adaptive Thresholding)
    • 概念:将图像分割成许多小的区域,对每个小区域分别计算并应用不同的阈值。
    • 方法
      • 均值法(Mean):计算每个小区域内的像素平均值作为该区域的阈值。
      • 高斯法(Gaussian):在计算均值时,为中心像素附近的像素赋予更高的权重,从而得到一个加权平均值作为阈值。
    • 优势:这种方法能很好地处理光照不均或背景复杂的情况,因为它能够根据局部环境自动调整阈值。

灰度图

灰度图的本质

  • 单通道 :彩色图像通常有三个颜色通道(红、绿、蓝,即 RGB),每个像素由这三个通道的值组合而成,可以表示数百万种颜色。而灰度图只有一个通道,每个像素的值只代表其亮度灰度级别
  • 0-255 的数值 :在 8 位灰度图中,每个像素的取值范围通常是 0 到 255。
    • 0 代表最黑。
    • 255 代表最白。
    • 0 到 255 之间的值则代表不同深浅的灰色,值越大,颜色越亮。
  • 黑白过渡:与只有纯黑和纯白的二值化图像不同,灰度图能够平滑地表现出从黑到白的各种过渡,保留了图像的更多细节信息。

为什么需要灰度图?

将彩色图转换为灰度图是许多图像处理任务中的一个重要步骤,主要有以下几个原因:

  1. 简化数据:灰度图的数据量比彩色图小得多。彩色图需要三个字节(RGB)来存储一个像素,而灰度图只需要一个字节。这可以大大减少存储空间和处理时间。
  2. 突出亮度信息:在许多视觉任务中,例如边缘检测、轮廓识别、物体追踪等,算法主要依赖于图像的亮度或明暗变化。将图像转换为灰度图可以去除不必要的颜色信息,使算法能更专注于分析亮度差异,从而提高效率和准确性。
  3. 预处理步骤:在进行二值化、直方图均衡化等操作之前,通常需要先将图像转换为灰度图。

如何从彩色图得到灰度图?

将一张彩色图片转换为灰度图,最常见的方法是根据人眼对不同颜色的敏感度,对 RGB 三个通道的值进行加权平均

一个常用的转换公式是:

bash 复制代码
灰度值=0.299×红色值+0.587×绿色值+0.114×蓝色值

这个公式反映了人眼对绿色最敏感,其次是红色,对蓝色最不敏感。OpenCV 等库在进行彩色到灰度转换时,通常会采用类似的加权平均方法。

如果是YUV 转换为灰度图,由于 Y 分量 本身就直接代表了图像的亮度信息,而灰度图的本质就是亮度图,因此,从 YUV 转换为灰度图只需要提取 Y 分量即可。

OpenCV实现YUV到灰度图的转换

python 复制代码
import cv2
import numpy as np

# 1. 加载一张彩色图像 (OpenCV默认以 BGR 格式读取)
bgr_img = cv2.imread('your_image_path.jpg')

# 检查图像是否成功加载
if bgr_img is None:
    print("Error: Could not read the image.")
else:
    # 2. 将 BGR 图像转换为 YUV 格式
    # OpenCV 使用 YUV 而非 YCbCr,但原理相同
    yuv_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2YUV)
    
    # 3. 提取 Y 分量(亮度通道),作为灰度图
    # Y 分量是 YUV 图像的第一个通道
    gray_img = yuv_img[:,:,0]

    # 4. 显示原始彩色图像和生成的灰度图像
    cv2.imshow('Original BGR Image', bgr_img)
    cv2.imshow('Gray Image from Y Channel', gray_img)

    # 等待按键,然后关闭所有窗口
    cv2.waitKey(0)
    cv2.destroyAllWindows()

opencv实现二值化

cv2.threshold() 函数

python 复制代码
ret, dst = cv2.threshold(src, thresh, maxval, type)

参数解释:

  • src: 原始图像,必须是灰度图
  • thresh: 设定的阈值
  • maxval: 当像素值超过(或低于)阈值时,所赋予的最大值。通常是 255。
  • type: 值的类型,决定了如何应用阈值。这是最关键的参数,常用的类型包括:
    • cv2.THRESH_BINARY: 最基础的二值化。如果像素值大于 thresh,则设置为 maxval;否则设置为 0。
    • cv2.THRESH_BINARY_INV: 与 THRESH_BINARY 相反。如果像素值大于 thresh,则设置为 0;否则设置为 maxval
    • cv2.THRESH_TRUNC: 截断。如果像素值大于 thresh,则设置为 thresh;否则保持不变。
    • cv2.THRESH_TOZERO: 如果像素值大于 thresh,则保持不变;否则设置为 0。
    • cv2.THRESH_TOZERO_INV: 与 THRESH_TOZERO 相反。如果像素值大于 thresh,则设置为 0;否则保持不变。

返回值:

  • ret: 设定的阈值。当使用 Otsu's 或 Triangle 方法时,返回的是自动计算出的阈值。
  • dst: 二值化后的图像

实现基础二值化

python 复制代码
import cv2
import numpy as np

# 1. 加载图像并转换为灰度图
img = cv2.imread('your_image_path.jpg', cv2.IMREAD_GRAYSCALE)

# 检查图像是否成功加载
if img is None:
    print("Error: Could not read the image.")
else:
    # 2. 设定阈值并进行二值化处理
    # 设定阈值为127,最大值为255
    ret, binary_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
    
    # 打印返回的阈值(这里会是127)
    print(f"Threshold value returned: {ret}")

    # 3. 显示原始图像和二值化后的图像
    cv2.imshow('Original Grayscale Image', img)
    cv2.imshow('Binary Image', binary_img)
    
    # 等待按键,然后关闭所有窗口
    cv2.waitKey(0)
    cv2.destroyAllWindows()

使用 Otsu's 方法自动寻找阈值

python 复制代码
import cv2
import numpy as np

# 1. 加载图像并转换为灰度图
img = cv2.imread('your_image_path.jpg', cv2.IMREAD_GRAYSCALE)

if img is None:
    print("Error: Could not read the image.")
else:
    # 2. 使用 Otsu's 方法进行自动二值化
    # 注意:这里阈值参数传入 0,类型与 cv2.THRESH_OTSU 按位或
    ret, binary_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # 打印 Otsu's 算法自动计算出的阈值
    print(f"Otsu's threshold value: {ret}")

    # 3. 显示图像
    cv2.imshow('Original Grayscale Image', img)
    cv2.imshow('Otsu\'s Binary Image', binary_otsu)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
相关推荐
luoganttcc5 小时前
小鹏自动驾驶的BEV占用网络有哪些优势?
人工智能·机器学习·自动驾驶
聚客AI6 小时前
⚡从单机到分布式:双MCP服务器负载架构详解
人工智能·llm·mcp
martinzh6 小时前
Reflexion:让AI智能体学会反思的神奇技术
人工智能
艾醒6 小时前
大模型面试题剖析:全量微调与 LoRA 微调
人工智能·python·算法
可触的未来,发芽的智生6 小时前
微论-突触的作用赋能思考(可能是下一代人工智能架构的启发式理论)
人工智能·神经网络·架构·启发式算法
ZHOU_WUYI6 小时前
介绍GSPO:一种革命性的语言模型强化学习算法
人工智能·算法·语言模型
机器之心6 小时前
首个为具身智能而生的大规模强化学习框架RLinf!清华、北京中关村学院、无问芯穹等重磅开源
人工智能·openai
朱程7 小时前
写给自己的 LangChain 开发教程(四):RAG(1)
前端·人工智能
在钱塘江7 小时前
Langgraph从新手到老师傅-2-Agent是什么
人工智能·python