二值化技术详解
一、技术背景
二值化是图像处理中最基础的操作之一,它将灰度图像转换为只有黑白两色的图像。二值化后的图像便于进行轮廓检测、形态学操作、形状分析等后续处理。
本文详细介绍 Binary、BinaryInv、Otsu 等多种二值化模式的原理与区别,以及在 SEM 项目中 MorphologicalOperate.Binarize() 的应用。
二、数学原理
2.1 基本二值化(Binary)
基本二值化使用固定阈值将图像分为黑白两类:
g(x,y)={maxval,if f(x,y)>thresh0,otherwise g(x,y) = \begin{cases} maxval, & \text{if } f(x,y) > thresh \\ 0, & \text{otherwise} \end{cases} g(x,y)={maxval,0,if f(x,y)>threshotherwise
其中,threshthreshthresh 为阈值,maxvalmaxvalmaxval 为最大值(通常为255)。
2.2 反向二值化(BinaryInv)
反向二值化与基本二值化相反:
g(x,y)={maxval,if f(x,y)≤thresh0,otherwise g(x,y) = \begin{cases} maxval, & \text{if } f(x,y) \leq thresh \\ 0, & \text{otherwise} \end{cases} g(x,y)={maxval,0,if f(x,y)≤threshotherwise
2.3 截断二值化(Truncate)
截断二值化不改变低于阈值的像素:
g(x,y)={thresh,if f(x,y)>threshf(x,y),otherwise g(x,y) = \begin{cases} thresh, & \text{if } f(x,y) > thresh \\ f(x,y), & \text{otherwise} \end{cases} g(x,y)={thresh,f(x,y),if f(x,y)>threshotherwise
2.4 阈值归零(ThresholdToZero)
高于阈值的像素保持不变,低于阈值的设为0:
g(x,y)={f(x,y),if f(x,y)>thresh0,otherwise g(x,y) = \begin{cases} f(x,y), & \text{if } f(x,y) > thresh \\ 0, & \text{otherwise} \end{cases} g(x,y)={f(x,y),0,if f(x,y)>threshotherwise
2.5 反向阈值归零(ThresholdToZeroInv)
低于阈值的像素保持不变,高于阈值的设为0:
g(x,y)={0,if f(x,y)>threshf(x,y),otherwise g(x,y) = \begin{cases} 0, & \text{if } f(x,y) > thresh \\ f(x,y), & \text{otherwise} \end{cases} g(x,y)={0,f(x,y),if f(x,y)>threshotherwise
2.6 Otsu 自适应阈值
Otsu方法通过最大化类间方差自动确定阈值:
σb2(k)=ω0ω1(μ0−μ1)2 \sigma_b^2(k) = \omega_0\omega_1(\mu_0 - \mu_1)^2 σb2(k)=ω0ω1(μ0−μ1)2
最佳阈值 k∗=argmaxkσb2(k)k^* = \arg\max_{k} \sigma_b^2(k)k∗=argmaxkσb2(k)
三、代码实现
以下代码来自 e:\SEM\Methods\MorphologicalOperate.cs:
csharp
public static Mat Binarize(Mat img)
{
var gray = ToGray(img);
Mat result = new Mat();
Cv2.Threshold(gray, result, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.BinaryInv);
return result;
}
private static Mat ToGrayAndBinary(Mat img)
{
var gray = ToGray(img);
Cv2.Threshold(gray, gray, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
return gray;
}
public static Mat ToGray(Mat img)
{
if (img.Channels() > 1)
{
Mat gray = new Mat();
Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
return gray;
}
return img.Clone();
}
二值化类型组合
在OpenCV中,可以通过位或运算组合不同的阈值类型:
csharp
// Otsu + BinaryInv:自动阈值 + 反向二值化
Cv2.Threshold(gray, result, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.BinaryInv);
// Otsu + Binary:自动阈值 + 正常二值化
Cv2.Threshold(gray, result, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
OpenCV API
csharp
double Cv2.Threshold(
Mat src, // 输入灰度图像
Mat dst, // 输出图像
double thresh, // 阈值(Otsu时被忽略)
double maxval, // 最大值
ThresholdTypes type // 阈值类型
);
返回值为使用的阈值(Otsu时返回计算得到的阈值)。
四、参数调优
4.1 阈值类型选择
| 类型 | 特点 | 适用场景 |
|---|---|---|
| Binary | 亮区域为白,暗区域为黑 | 目标为亮色区域 |
| BinaryInv | 暗区域为白,亮区域为黑 | 目标为暗色区域(SEM图像常见) |
| Truncate | 压缩高亮区域 | 限制过曝区域 |
| ThresholdToZero | 保留亮区域 | 提取亮特征 |
| ThresholdToZeroInv | 保留暗区域 | 提取暗特征 |
4.2 Otsu 与固定阈值的选择
| 场景 | 建议方法 |
|---|---|
| 图像光照均匀,有明确双峰 | Otsu |
| 图像光照变化大 | 自适应阈值(Adaptive Threshold) |
| 需要稳定控制阈值 | 固定阈值 |
| 多幅图像批量处理 | Otsu(自动适应每张图) |
4.3 maxval 参数
通常设置为255(8位图像的最大值),但可以根据需要调整:
- 设置为127:产生灰度二值图
- 设置为1:产生0-1二值图
五、常见问题
Q1:使用 Otsu 时阈值参数设为多少?
解决方案 :使用 Otsu 时,thresh 参数会被忽略,可以设为任意值(通常设为0)。实际阈值由算法自动计算。
Q2:二值化结果全黑或全白?
原因:阈值设置不当或图像对比度极低。
解决方案:
- 使用 Otsu 自动确定阈值
- 先进行 CLAHE 对比度增强
- 检查图像直方图分布
Q3:目标区域在二值化后不连续?
原因:阈值选择不当,目标区域灰度分布不均匀。
解决方案:
- 使用形态学闭运算连接断裂区域
- 考虑使用自适应阈值方法
- 先进行高斯模糊平滑图像
Q4:如何获取 Otsu 计算的具体阈值?
csharp
double threshold = Cv2.Threshold(gray, result, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
Console.WriteLine($"Otsu阈值: {threshold}");
Q5:Binary 和 BinaryInv 如何选择?
选择原则:
- 目标区域灰度值较高:使用 Binary
- 目标区域灰度值较低:使用 BinaryInv
在 SEM 图像分析中,孔隙、裂纹等目标区域通常呈现为暗色(低灰度值),因此常用 BinaryInv。
Q6:Otsu 与自适应阈值的区别?
| 特性 | Otsu | 自适应阈值 |
|---|---|---|
| 阈值数量 | 全局1个 | 局部多个 |
| 适用场景 | 光照均匀 | 光照不均匀 |
| 计算速度 | 快 | 较慢 |
| 细节保留 | 一般 | 好 |