深入理解全局阈值的原理、实现与应用
全局阈值是一种简单的图像二值化方法,使用单一阈值将整个图像的像素分为前景和背景两类。
全局阈值是最基本的图像二值化方法,它使用一个固定的阈值T将灰度图像转换为二值图像。对于图像中的每个像素值f(x,y),二值化规则如下:
g(x,y) = { 255, if f(x,y) > T
{ 0, if f(x,y) ≤ T
其中g(x,y)是二值化后的像素值,T是全局阈值。全局阈值方法适用于光照均匀、前景和背景对比明显的图像。
常见的全局阈值选择方法包括:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def global_threshold_builtin(image_path, threshold=127):
"""
使用OpenCV内置函数实现全局阈值
:param image_path: 输入图像路径
:param threshold: 阈值
:return: 原图和二值化后的图像
"""
# 读取图像
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 应用全局阈值
_, binary = cv2.threshold(gray, threshold, 255, cv2.THRESH_BINARY)
return img, cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
def manual_global_threshold(image_path, threshold=127):
"""
手动实现全局阈值
:param image_path: 输入图像路径
:param threshold: 阈值
:return: 二值化后的图像
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 手动应用阈值
binary = np.zeros_like(img)
binary[img > threshold] = 255
binary[img <= threshold] = 0
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
def mean_based_threshold(image_path):
"""
基于平均灰度值的全局阈值
:param image_path: 输入图像路径
:return: 原图和基于平均值的二值化结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 计算平均灰度值
mean_val = np.mean(img)
# 应用平均值作为阈值
_, binary = cv2.threshold(img, mean_val, 255, cv2.THRESH_BINARY)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
def histogram_based_threshold(image_path):
"""
基于直方图分析的全局阈值
:param image_path: 输入图像路径
:return: 原图、直方图和二值化结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 计算直方图
hist, bins = np.histogram(img.flatten(), 256, [0, 256])
# 寻找直方图的谷底(两峰之间的最低点)
# 这是一个简化的实现,实际应用中可能需要更复杂的算法
peaks = []
for i in range(1, len(hist)-1):
if hist[i-1] < hist[i] > hist[i+1]: # 局部最大值
peaks.append(i)
# 如果找到两个峰值,取它们之间的谷底
if len(peaks) >= 2:
peak1 = peaks[0]
peak2 = peaks[-1] # 取第一个和最后一个峰值
valley = (peak1 + peak2) // 2
threshold = valley
else:
# 如果找不到明显峰值,使用平均值
threshold = np.mean(img)
# 应用阈值
_, binary = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
def multiple_threshold_comparison(image_path):
"""
比较不同阈值的二值化效果
:param image_path: 输入图像路径
:return: 原图和不同阈值的二值化结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 计算不同阈值
thresholds = {
'Mean': int(np.mean(img)),
'Median': int(np.median(img)),
'127': 127,
'Otsu': 0 # Otsu阈值将在下面单独计算
}
# 计算Otsu阈值
_, otsu_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
thresholds['Otsu'] = int(otsu_thresh)
results = {}
for name, thresh in thresholds.items():
_, binary = cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY)
results[name] = cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), results
def adaptive_manual_threshold(image_path):
"""
自适应全局阈值选择
:param image_path: 输入图像路径
:return: 原图和自适应阈值二值化结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 计算图像的统计信息
mean_val = np.mean(img)
std_val = np.std(img)
min_val = np.min(img)
max_val = np.max(img)
# 根据统计信息选择阈值
# 这里使用一种启发式方法:考虑均值和标准差
if std_val < 30: # 低对比度图像
threshold = (min_val + max_val) // 2
elif std_val > 80: # 高对比度图像
threshold = mean_val
else: # 中等对比度图像
threshold = mean_val - 0.2 * std_val # 稍微调整阈值
# 确保阈值在合理范围内
threshold = np.clip(threshold, 0, 255)
# 应用阈值
_, binary = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
def histogram_analysis(image_path):
"""
直方图分析辅助阈值选择
:param image_path: 输入图像路径
:return: 原图、直方图和分析结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 计算直方图
hist, bins = np.histogram(img.flatten(), 256, [0, 256])
# 计算累积直方图
cum_hist = np.cumsum(hist)
total_pixels = cum_hist[-1]
# 寻找累积直方图的拐点(可能的阈值)
# 计算直方图的二阶导数来寻找峰值
first_deriv = np.diff(hist)
second_deriv = np.diff(first_deriv)
# 寻找可能的阈值点(在两个峰值之间)
# 这里使用一个简化的算法
threshold = int(np.mean(img))
# 应用阈值
_, binary = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
# 使用示例
if __name__ == "__main__":
# 注意:需要提供实际的图像路径
# img, result = global_threshold_builtin('image.jpg', 127)
# manual_img, manual_result = manual_global_threshold('image.jpg', 127)
# mean_img, mean_result = mean_based_threshold('image.jpg')
# hist_img, hist_result = histogram_based_threshold('image.jpg')
# multi_img, multi_results = multiple_threshold_comparison('image.jpg')
# adapt_img, adapt_result = adaptive_manual_threshold('image.jpg')
# hist_analysis_img, hist_analysis_result = histogram_analysis('image.jpg')
pass