OpenCV 图像阈值处理

OpenCV 图像阈值处理 教程(中文)重点讲解 OpenCV 中用于图像阈值处理的核心功能,主要基于 imgproc 模块的 thresholdadaptiveThreshold 函数。阈值处理是图像分割的基础,用于将图像转换为二值图像或突出特定像素范围,广泛应用于目标检测、边缘提取等场景。本教程提供清晰的 Python 代码示例、解释和注意事项,适合初学者快速上手。假设你已安装 OpenCV(opencv-python)。


一、图像阈值处理概述

  • 阈值处理:根据像素值与阈值的比较,将像素值设置为特定值(如 0 或 255),用于图像分割或增强。
  • 应用场景
  • 二值化:将图像分为前景和背景。
  • 预处理:为边缘检测、轮廓提取做准备。
  • 特征提取:突出特定灰度范围。
  • 关键函数
  • cv2.threshold:全局阈值处理。
  • cv2.adaptiveThreshold:自适应阈值处理,基于局部像素。
  • 输入要求:通常为灰度图像(单通道,uint8 类型)。

二、核心阈值处理功能与代码示例

以下按阈值处理类型分类,逐一讲解并提供 Python 示例代码。

2.1 全局阈值处理 (cv2.threshold)

全局阈值处理对整个图像应用单一阈值,适合光照均匀的图像。

支持的阈值类型

  • cv2.THRESH_BINARY:大于阈值设为最大值,小于等于设为 0。
  • cv2.THRESH_BINARY_INV:反向二值化。
  • cv2.THRESH_TRUNC:大于阈值设为阈值,小于不变。
  • cv2.THRESH_TOZERO:小于阈值设为 0,大于不变。
  • cv2.THRESH_TOZERO_INV:大于阈值设为 0,小于不变。

示例:全局阈值处理

import cv2
import numpy as np

# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
    print("错误:无法加载图像")
    exit()

# 应用不同阈值类型
thresh_value = 127
max_value = 255

# 二值化
_, thresh_binary = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_BINARY)
_, thresh_binary_inv = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_BINARY_INV)
_, thresh_trunc = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_TRUNC)
_, thresh_tozero = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_TOZERO)
_, thresh_tozero_inv = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_TOZERO_INV)

# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('THRESH_BINARY', thresh_binary)
cv2.imshow('THRESH_BINARY_INV', thresh_binary_inv)
cv2.imshow('THRESH_TRUNC', thresh_trunc)
cv2.imshow('THRESH_TOZERO', thresh_tozero)
cv2.imshow('THRESH_TOZERO_INV', thresh_tozero_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('thresh_binary.jpg', thresh_binary)
cv2.imwrite('thresh_binary_inv.jpg', thresh_binary_inv)
cv2.imwrite('thresh_trunc.jpg', thresh_trunc)
cv2.imwrite('thresh_tozero.jpg', thresh_tozero)
cv2.imwrite('thresh_tozero_inv.jpg', thresh_tozero_inv)

说明

  • threshold 返回两个值:阈值(通常为输入阈值)和处理后的图像。
  • thresh_value:阈值,范围 0-255,需根据图像调整。
  • max_value:通常设为 255(白色)。

2.2 自适应阈值处理 (cv2.adaptiveThreshold)

自适应阈值根据局部像素邻域动态计算阈值,适合光照不均的图像。

支持的自适应方法

  • cv2.ADAPTIVE_THRESH_MEAN_C:邻域均值作为阈值。
  • cv2.ADAPTIVE_THRESH_GAUSSIAN_C:邻域高斯加权均值作为阈值。

示例:自适应阈值处理

import cv2

# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
    print("错误:无法加载图像")
    exit()

# 自适应阈值
block_size = 11  # 邻域大小(奇数)
C = 2  # 常数偏移

# 均值自适应
thresh_mean = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                                   cv2.THRESH_BINARY, block_size, C)

# 高斯自适应
thresh_gaussian = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                                       cv2.THRESH_BINARY, block_size, C)

# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('均值自适应', thresh_mean)
cv2.imshow('高斯自适应', thresh_gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('thresh_mean.jpg', thresh_mean)
cv2.imwrite('thresh_gaussian.jpg', thresh_gaussian)

说明

  • block_size:邻域大小(奇数,如 11),影响局部阈值计算。
  • C:从计算的阈值中减去的常数,调整分割效果。
  • 高斯方法通常对复杂背景更有效。

2.3 自动阈值(Otsu 方法)

Otsu 方法自动选择最佳阈值,最大化类间方差,适合双峰直方图图像。

示例:Otsu 阈值处理

import cv2

# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
    print("错误:无法加载图像")
    exit()

# Otsu 阈值
_, thresh_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('Otsu 阈值', thresh_otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('thresh_otsu.jpg', thresh_otsu)

说明

  • THRESH_OTSU:自动计算阈值,忽略手动指定的阈值(设为 0)。
  • 常与 THRESH_BINARY 组合使用。

三、综合示例:阈值处理流水线

结合全局阈值、自适应阈值和 Otsu 方法:

import cv2
import numpy as np

def threshold_pipeline(image_path):
    """阈值处理流水线"""
    # 读取灰度图像
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        print("错误:无法加载图像")
        return

    # 1. 全局二值化
    _, thresh_binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

    # 2. 自适应阈值(高斯)
    thresh_adaptive = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                                           cv2.THRESH_BINARY, 11, 2)

    # 3. Otsu 阈值
    _, thresh_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    # 显示结果
    cv2.imshow('原始灰度图像', img)
    cv2.imshow('全局二值化', thresh_binary)
    cv2.imshow('自适应阈值', thresh_adaptive)
    cv2.imshow('Otsu 阈值', thresh_otsu)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    # 保存结果
    cv2.imwrite('thresh_binary.jpg', thresh_binary)
    cv2.imwrite('thresh_adaptive.jpg', thresh_adaptive)
    cv2.imwrite('thresh_otsu.jpg', thresh_otsu)

# 使用示例
threshold_pipeline('lena.jpg')  # 替换为你的图像路径

四、阈值处理应用:轮廓检测预处理

阈值处理常用于轮廓检测的预处理:

import cv2
import numpy as np

# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
    print("错误:无法加载图像")
    exit()

# 自适应阈值
thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                              cv2.THRESH_BINARY, 11, 2)

# 查找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓
img_color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(img_color, contours, -1, (0, 255, 0), 2)

# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('阈值图像', thresh)
cv2.imshow('轮廓', img_color)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('contours.jpg', img_color)

说明

  • 阈值处理生成二值图像,适合 findContours 提取轮廓。
  • 自适应阈值对复杂背景效果更好。

五、注意事项

  1. 输入图像
  • 阈值处理通常需要灰度图像(单通道)。
  • 确保图像为 uint8 类型。
  1. 参数调整
  • 全局阈值的 thresh_value 需根据图像灰度分布调整。
  • 自适应阈值的 block_size 应为奇数,过大或过小影响效果。
  1. 性能优化
  • 预处理(如高斯模糊)可减少噪声,提高阈值效果。
  • 使用 ROI 减少计算量。
  1. 错误处理
  • 检查 imread 返回值,防止图像加载失败。
  • 确保 block_sizeC 参数合理。
  1. 选择方法
  • 全局阈值适合光照均匀的图像。
  • 自适应阈值适合光照不均或复杂背景。
  • Otsu 方法适合双峰直方图图像。

六、资源

  • 官方文档:https://docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html
  • imgproc 模块:https://docs.opencv.org/master/d7/d1d/tutorial_how_to_use_IPP.html
  • 社区:在 X 平台搜索 #opencv 获取最新讨论。

如果你需要更深入的阈值处理示例(如多阈值组合、动态调整阈值)或 C++ 实现代码,请告诉我,我可以提供详细的解决方案或针对特定任务的优化!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注