摘要: 本文深入探讨了 Otsu 二值化算法,详细阐述其原理,包括类间方差的计算与阈值确定机制。分别给出了该算法在 C#、Python 和 C++ 中的实现代码示例,并对代码进行了详细注释与分析。此外,还探讨了 Otsu 二值化算法在图像分割、目标检测、字符识别等多个领域的广泛应用,展示了其在计算机视觉与图像处理领域的重要地位与价值。
一、引言
在计算机视觉与图像处理领域,图像二值化是一项基础且关键的操作。它将图像中的像素根据一定的规则分为两类,通常为前景(目标)和背景,从而简化图像分析与处理过程。Otsu 二值化算法作为一种自动确定阈值的方法,在众多应用场景中表现出色,无需手动设定阈值,能够根据图像自身的特性自适应地找到最佳阈值,广泛应用于图像分割、目标识别、文档处理等多个领域。
二、Otsu 二值化算法原理
(一)灰度直方图基础
图像的灰度直方图是理解 Otsu 算法的重要基础。灰度直方图描述了图像中各个灰度级出现的频率。对于一幅灰度图像,其灰度值通常在 0(黑色)到 255(白色)之间。通过统计每个灰度值在图像中出现的像素数量,可构建灰度直方图。
设图像的灰度级为 L(对于 8 位灰度图像,L=256),图像中灰度值为i的像素数量为ni ,总像素数量为。
(二)类间方差公式推导
Otsu 算法的核心是最大化类间方差。假设通过阈值t将图像像素分为两类C0(灰度值范围为0到t)和C1(灰度值范围为t+1到L-1)。
两类的概率分别为:
两类的均值分别为:
图像的总均值为:
类间方差公式为:
通过遍历所有可能的阈值t(从0到L-2),计算对应的类间方差 ,使得最大的阈值t即为 Otsu 算法所求的最佳阈值。
三、Otsu 二值化算法在 C# 中的实现
(一)代码示例
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
class OtsuBinarization
{
public static Image<Gray, byte> OtsuBinarize(Image<Gray, byte> grayImage)
{
// 获取图像的宽度和高度
int width = grayImage.Width;
int height = grayImage.Height;
// 计算灰度直方图
int[] histogram = new int[256];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
byte pixelValue = grayImage[y, x].Intensity;
histogram[pixelValue]++;
}
}
// 总像素数量
int totalPixels = width * height;
// 初始化类间方差和最佳阈值
double maxVariance = 0;
int optimalThreshold = 0;
// 计算类间方差并寻找最佳阈值
double sum = 0;
double sumB = 0;
double wB = 0;
double wF = 0;
for (int t = 0; t < 256; t++)
{
sum += t * histogram[t];
}
for (int t = 0; t < 256; t++)
{
wB += histogram[t];
if (wB == 0)
{
continue;
}
wF = totalPixels - wB;
if (wF == 0)
{
break;
}
sumB += t * histogram[t];
double meanB = sumB / wB;
double meanF = (sum - sumB) / wF;
double variance = wB * wF * (meanB - meanF) * (meanB - meanF);
if (variance > maxVariance)
{
maxVariance = variance;
optimalThreshold = t;
}
}
// 根据最佳阈值进行二值化
Image<Gray, byte> binaryImage = new Image<Gray, byte>(width, height);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
byte pixelValue = grayImage[y, x].Intensity;
if (pixelValue <= optimalThreshold)
{
binaryImage[y, x] = new Gray(0);
}
else
{
binaryImage[y, x] = new Gray(255);
}
}
}
return binaryImage;
}
}
(二)代码分析
- 首先获取输入灰度图像的宽度和高度,用于后续遍历图像像素和计算相关参数。
- 构建一个长度为 256 的数组
histogram
来存储灰度直方图。通过两层循环遍历图像的每个像素,将像素的灰度值作为索引,增加对应histogram
数组元素的值,从而统计每个灰度级的像素数量。 - 计算图像的总像素数量
totalPixels
,用于后续计算各类的概率。 - 初始化类间方差
maxVariance
为 0,最佳阈值optimalThreshold
为 0。同时初始化一些用于计算类间方差的变量,如sum
(用于计算图像总灰度值之和)、sumB
(背景类灰度值之和)、wB
(背景类像素数量占比)、wF
(前景类像素数量占比)。 - 计算图像总灰度值之和
sum
,通过遍历灰度直方图,将每个灰度值乘以其对应的像素数量并累加。 - 主循环遍历所有可能的阈值
t
(从 0 到 255)。在循环内:- 首先计算背景类像素数量占比
wB
和前景类像素数量占比wF
。 - 计算背景类灰度值之和
sumB
,并进一步计算背景类均值meanB
和前景类均值meanF
。 - 根据类间方差公式计算当前阈值
t
下的类间方差variance
。 - 如果当前方差大于已记录的最大方差
maxVariance
,则更新最大方差和最佳阈值。
- 首先计算背景类像素数量占比
- 最后,根据最佳阈值
optimalThreshold
对图像进行二值化。再次遍历图像像素,如果像素灰度值小于等于最佳阈值,则将其在二值化图像中设为黑色(0),否则设为白色(255)。
四、Otsu 二值化算法在 Python 中的实现
(一)代码示例
import cv2
import numpy as np
def otsu_binarization(image):
# 将图像转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 计算灰度直方图
histogram = np.zeros(256)
height, width = gray_image.shape
for y in range(height):
for x in range(width):
pixel_value = gray_image[y, x]
histogram[pixel_value] += 1
# 总像素数量
total_pixels = height * width
# 初始化类间方差和最佳阈值
max_variance = 0
optimal_threshold = 0
# 计算类间方差并寻找最佳阈值
sum_gray = 0
sum_back = 0
w_back = 0
w_fore = 0
for t in range(256):
sum_gray += t * histogram[t]
for t in range(256):
w_back += histogram[t]
if w_back == 0:
continue
w_fore = total_pixels - w_back
if w_fore == 0:
break
sum_back += t * histogram[t]
mean_back = sum_back / w_back
mean_fore = (sum_gray - sum_back) / w_fore
variance = w_back * w_fore * (mean_back - mean_fore) ** 2
if variance > max_variance:
max_variance = variance
optimal_threshold = t
# 根据最佳阈值进行二值化
binary_image = np.zeros((height, width), dtype=np.uint8)
for y in range(height):
for x in range(width):
pixel_value = gray_image[y, x]
if pixel_value <= optimal_threshold:
binary_image[y, x] = 0
else:
binary_image[y, x] = 255
return binary_image
(二)代码分析
- 利用
cv2.cvtColor
函数将输入图像转换为灰度图像,方便后续处理。 - 构建一个长度为 256 的
histogram
数组来存储灰度直方图。通过两层循环遍历灰度图像的每个像素,统计每个灰度级的像素数量。 - 计算图像的总像素数量
total_pixels
。 - 初始化类间方差
max_variance
为 0,最佳阈值optimal_threshold
为 0,以及一些用于计算类间方差的变量sum_gray
(图像总灰度值之和)、sum_back
(背景类灰度值之和)、w_back
(背景类像素数量占比)、w_fore
(前景类像素数量占比)。 - 计算图像总灰度值之和
sum_gray
,通过遍历灰度直方图,将每个灰度值乘以其对应的像素数量并累加。 - 主循环遍历所有可能的阈值
t
(从 0 到 255)。在循环内:- 计算背景类像素数量占比
w_back
和前景类像素数量占比w_fore
。 - 计算背景类灰度值之和
sum_back
,进而计算背景类均值mean_back
和前景类均值mean_fore
。 - 根据类间方差公式计算当前阈值
t
下的类间方差variance
。 - 如果当前方差大于已记录的最大方差
max_variance
,则更新最大方差和最佳阈值。
- 计算背景类像素数量占比
- 最后,根据最佳阈值
optimal_threshold
对图像进行二值化。通过两层循环遍历图像像素,如果像素灰度值小于等于最佳阈值,则在二值化图像中设为黑色(0),否则设为白色(255)。
五、Otsu 二值化算法在 C++ 中的实现
(一)代码示例
#include <iostream>
#include <opencv2/opencv.hpp>
cv::Mat otsuBinarization(cv::Mat grayImage)
{
// 计算灰度直方图
int histogram[256] = { 0 };
int height = grayImage.rows;
int width = grayImage.cols;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
histogram[grayImage.at<uchar>(y, x)]++;
}
}
// 总像素数量
int totalPixels = height * width;
// 初始化类间方差和最佳阈值
double maxVariance = 0;
int optimalThreshold = 0;
// 计算类间方差并寻找最佳阈值
double sum = 0;
double sumB = 0;
double wB = 0;
double wF = 0;
for (int t = 0; t < 256; t++)
{
sum += t * histogram[t];
}
for (int t = 0; t < 256; t++)
{
wB += histogram[t];
if (wB == 0)
{
continue;
}
wF = totalPixels - wB;
if (wF == 0)
{
break;
}
sumB += t * histogram[t];
double meanB = sumB / wB;
double meanF = (sum - sumB) / wF;
double variance = wB * wF * (meanB - meanF) * (meanB - meanF);
if (variance > maxVariance)
{
maxVariance = variance;
optimalThreshold = t;
}
}
// 根据最佳阈值进行二值化
cv::Mat binaryImage(height, width, CV_8UC1);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (grayImage.at<uchar>(y, x) <= optimalThreshold)
{
binaryImage.at<uchar>(y, x) = 0;
}
else
{
binaryImage.at<uchar>(y, x) = 255;
}
}
}
return binaryImage;
}
(二)代码分析
- 首先计算输入灰度图像的灰度直方图。通过两层循环遍历图像的每个像素,将像素的灰度值作为索引,增加对应
histogram
数组元素的值。 - 计算图像的总像素数量
totalPixels
。 - 初始化类间方差
maxVariance
为 0,最佳阈值optimalThreshold
为 0,以及一些用于计算类间方差的变量sum
(图像总灰度值之和)、sumB
(背景类灰度值之和)、wB
(背景类像素数量占比)、wF
(前景类像素数量占比)。 - 计算图像总灰度值之和
sum
,通过遍历灰度直方图,将每个灰度值乘以其对应的像素数量并累加。 - 主循环遍历所有可能的阈值
t
(从 0 到 255)。在循环内:- 计算背景类像素数量占比
wB
和前景类像素数量占比wF
。 - 计算背景类灰度值之和
sumB
,并进一步计算背景类均值meanB
和前景类均值meanF
。 - 根据类间方差公式计算当前阈值
t
下的类间方差variance
。 - 如果当前方差大于已记录的最大方差
maxVariance
,则更新最大方差和最佳阈值。
- 计算背景类像素数量占比
- 最后,根据最佳阈值
optimalThreshold
对图像进行二值化。通过两层循环遍历图像像素,如果像素灰度值小于等于最佳阈值,则在二值化图像中设为黑色(0),否则设为白色(255)。
六、Otsu 二值化算法的应用
(一)图像分割
在图像分割中,Otsu 二值化算法可用于将目标物体从背景中分离出来。例如在医学图像中,将病变组织与正常组织分离,或者在工业检测中,将产品与背景区分开来。通过自动确定阈值,能够适应不同图像的光照、对比度等变化,提高分割的准确性和稳定性。
(二)目标检测
在目标检测任务中,二值化后的图像可以突出目标物体的轮廓,便于后续的特征提取与目标识别。例如在人脸识别系统中,先对图像进行 Otsu 二值化,然后提取人脸的边缘特征,与数据库中的模板进行匹配,从而实现人脸检测与识别。
(三)字符识别
在光学字符识别(OCR)领域,Otsu 二值化发挥着极为关键的作用。无论是印刷体文字还是手写体文字的识别,都需要将文字从复杂的背景图像中清晰地分离出来,以提取文字的笔画、结构等特征信息。通过对包含文字的图像进行 Otsu 二值化处理,可以有效地将文字像素与背景像素区分开来,得到仅包含黑白两种像素值的二值图像。在这种二值图像中,文字部分通常呈现为前景(白色像素),背景则被转换为黑色像素,从而为后续的字符分割、特征提取以及分类识别等操作提供了便利且高质量的图像基础。例如,在文档数字化处理过程中,大量的纸质文档需要被扫描并转换为可编辑的电子文本,Otsu 二值化能够快速准确地处理扫描图像中的文字部分,极大地提高了 OCR 系统的识别准确率和效率。
(四)交通监控与智能驾驶
在交通监控系统中,Otsu 二值化算法被广泛应用于车辆检测、车牌识别等任务。对于交通场景图像,通过二值化可以突出车辆的轮廓、形状以及车牌区域等关键信息。在车辆检测方面,能够快速确定图像中车辆的位置和大致范围,为交通流量统计、违章行为监测等提供基础数据支持。而在车牌识别中,二值化后的车牌图像更易于进行字符分割和识别,有助于实现高效准确的车牌号码读取,这对于智能交通管理系统的运行至关重要。在智能驾驶领域,Otsu 二值化算法也可用于对道路图像进行预处理,例如识别道路标识、区分道路与周围环境等,为自动驾驶车辆的决策和导航提供重要的视觉信息依据,保障自动驾驶过程的安全性和可靠性。
(五)工业视觉检测
工业生产线上,产品的质量检测往往依赖于机器视觉技术,Otsu 二值化算法是其中常用的图像处理手段之一。在零部件的表面缺陷检测中,如金属制品表面的划痕、裂纹检测,或者电子元器件的外观瑕疵检测等任务中,通过对采集到的产品图像进行二值化处理,可以凸显出缺陷部分与正常产品表面的差异。由于缺陷区域通常在灰度值或纹理特征上与正常区域有所不同,Otsu 二值化能够根据图像自身的灰度分布自动确定合适的阈值,将缺陷部分清晰地分离出来,便于后续通过形态学分析、特征提取等方法进一步判断缺陷的类型、大小和位置等信息,从而实现对产品质量的快速、准确检测,有效提高工业生产的自动化程度和产品质量控制水平。
(六)生物特征识别
除了人脸识别,在其他生物特征识别领域如指纹识别、虹膜识别等方面,Otsu 二值化也有着重要的应用。在指纹识别中,指纹图像经过二值化后,指纹的纹路细节更加突出,便于提取指纹的特征点,如端点、分叉点等,这些特征点构成了指纹的独特标识,用于与数据库中的指纹模板进行匹配识别。对于虹膜识别,二值化可以增强虹膜图像的对比度,突出虹膜的纹理结构,有助于提取虹膜的纹理特征,进而实现高精度的身份验证。通过 Otsu 二值化算法对生物特征图像进行预处理,能够提高生物特征提取的准确性和稳定性,提升整个生物特征识别系统的性能和可靠性,在安防监控、门禁系统等众多领域发挥着保障安全和身份识别的重要作用。
(七)遥感图像分析
在遥感图像处理与分析中,Otsu 二值化算法可用于土地利用分类、目标物提取等任务。例如,在对卫星遥感图像进行分析时,通过二值化可以将不同地物类型(如水体、植被、建筑用地等)进行初步分离。由于不同地物在遥感图像中的灰度特征存在差异,Otsu 二值化能够自动确定合适的阈值,将图像中的像素划分为不同类别,从而为进一步的精确分类和信息提取提供基础。在目标物提取方面,比如从遥感图像中提取特定的建筑物、道路等目标,二值化后的图像可以简化目标物的轮廓和区域,便于采用形态学操作、区域生长等方法进行目标物的精确提取和分析,为城市规划、资源监测、环境评估等领域提供有力的技术支持和数据依据。
综上所述,Otsu 二值化算法以其自动确定阈值的优势,在众多计算机视觉和图像处理领域得到了广泛而深入的应用,为提高各种图像处理任务的效率和准确性发挥着不可或缺的作用。随着技术的不断发展,其在新兴领域和复杂应用场景中的潜力也将不断被挖掘和拓展。