灰度图像变换——阈值化处理
1. OTSU阈值化
最大类间方差算法,步骤如下:
统计每个像素在整幅图中的个数——计算每个像素的概率分布——对灰度值进行遍历搜索,计算当前灰度值下前景背景类间概率——通过目标函数计算出类内与类间方差下对应的阈值。
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74int OTSU(Mat srcImg)//输入灰度图像
{
int nCols = srcImg.cols;//纵方向x
int nRows = srcImg.rows;//横方向y
int threshold = 0;//输出的灰度阈值
int nSumPix[256];//灰度级统计数组
float nProDis[256];//灰度级概率分布数组
for (int i = 0; i < 256; i++)//初始化统计数组
{
nSumPix[i] = 0;
nProDis[i] = 0;
}
for (int i = 0; i < nRows; i++)//统计灰度
{
for (int j = 0; j < nCols; j++)
{
nSumPix[(int)srcImg.at<uchar>(i, j)]++;
}
}
for (int i = 0; i < 256; i++)//计算概率分布
{
nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
}
//遍历灰度级[0, 255],计算出最大类间方差下的阈值
float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
double delta_max = 0.0;
for (int i = 0; i < 256; i++)
{
w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
for (int j = 0; j < 256; j++)
{
if (j <= i)//背景
{
w0 += nProDis[j];
u0_temp += j * nProDis[j];
}
else //前景
{
w1 += nProDis[j];
u1_temp += j * nProDis[j];
}
}
//求平均灰度
u0 = u0_temp / w0;
u1 = u1_temp / w1;
delta_temp = (float)(w0 * w1 * pow((u0 - u1), 2));//求方差
if (delta_temp > delta_max)//找出最大方差
{
delta_max = delta_temp;
threshold = i;
}
}
return threshold;
}
int main()
{
……
Mat srcGray;
int ostuThresHold = OTSU(srcGray);//得到阈值
Mat otImg = Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1);//创建二值图像
for (size_t i = 0; i < srcGray.rows; i++)
{
for (size_t j = 0; j < srcGray.cols; j++)
{
if (srcGray.at<uchar>(i, j) > ostuThresHold)//灰度像素读取操作
otImg.at<uchar>(i, j) = 255;
else
otImg.at<uchar>(i, j) = 0;
}
}
imshow("otImg_2", otImg);
waitKey(0);
return 0;
}
2. 固定阈值化
利用阈值化函数threshold:1
double threshold (InputArray src, OutputArray dst, double thresh, double maxval, int type);
- src:单通道图像组
- dst:输出图像组(与输入图像同样尺寸和类型)
- thresh:表示二值化的分界阈值[0, 255]
- maxVal:表示二值化的最大值[0, 255]
OpenCV提供了THRESH_BINARY和THRESH_BINARY_INV两种默认参数,或者定义为:1
const int maxVal = 255;
- type:表示阈值化处理的类型
0、1:非黑[255]即白[0]
2、3、4:可利用参数maxVal自设
| type 代码类型 | 值 | 含义 |
|---|---|---|
| THRESH_BINARY 二进制阈值化 |
0 | |
| THRESH_BINARY_INV 反二进制阈值化 |
1 | |
| THRESH_TRUNC 截断阈值化 |
2 | |
| THRESH_TOZERO 阈值化为0 |
3 | |
| THRESH_TOZERO_INV 反阈值化为0 |
4 |
3. 自适应阈值化
利用函数adaptiveThreshold:1
void adaptiveThreshold (InputArray src, OutputArray dst, double maxVal, int adaptiveMethod, int thresholdType, int blockSize, double C);
- adaptiveMethod:自适应算法
0:ADAPTIVE_THRESH_MEAN_C
1:ADAPTIVE_THRESH_GAUSSIAN_C - ThresholdType:阈值类型
0:THRESH_BINARY
1:THRESH_BINART_INV - blockSize:表示邻块大小用来计算区域阈值,一般为3、5、7……
- C:常数
4. 双阈值化
对于图像中有明显的双分界特征,可以利用双阈值法进行操作。不过需要预先设定好两个阈值量,相当于上界和下界,然后将落在二者中间的像素设定为maxVal,其余的像素设定为0。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17int main()
{
……
Mat srcImg;
//初始化参数
const int maxVal = 255;
int low_threshold=150;
int high_threshold=210;
Mat temp1, temp2, resImg;
//小阈值操作
threshold(srcImg, temp1, low_threshold, maxVal, THRESH_BINARY);
//大阈值操作
threshold(srcImg, temp2, high_threshold, maxVal, THRESH_BINARY_INV);
//矩阵与运算得到二值化结果
bitwise_and(temp1, temp2, resImg);
……
}





