OpenCV4入门教程029:全局阈值和局部阈值

索引地址:系列索引

二值图像介绍:二值图像介绍

阈(yu同玉)值

阈(你要是读fa伐我也没意见)的意思是界限,故阈值又叫临界值,是指一个效应能够产生的最低值或最高值。此一名词广泛用于各方面,包括建筑学、生物学、飞行、化学、电信、电学、心理学等,如生态阈值。

全局二值化

根据自定义阀值对图像进行二值化处理,即灰度值大于阀值时设改像素灰度值为255,灰度值小于阈值时设该像素灰度值为0

局部二值化

在局部范围内根据特定算法算出局部的阀值,这个局部的大小可以自己决定(例8*8,算法也可以自己决定,本篇文章所用的用法是局部平局的灰度值作为阀值。得到局部阀值再进行局部二值化处理)。一般情况下,我们使用全局阈值。

简单来说,全局阈值是一个阈值对一整幅图有效,而局部阈值对一张图中的一部分有效。

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "opencv2/opencv.hpp"
#include <iostream>
#include <string>

using namespace cv;
using namespace std;

Mat image3;
Mat target3;

//全局阈值二值化
void globalTwoValue(Mat src, int value) {
target3 = Mat::zeros(src.size(), src.type());

for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++) {
break;
if (value > (int)src.at<uchar>(i, j))
target3.at<uchar>(i, j) = 0;
else
target3.at<uchar>(i, j) = 255;
}
}
}
// 8*8局部二值化,阈值=局部平均灰度值
void localTwoValue(Mat src) {
// 1.先算出一列有几个8,剩下几个像素
int countRow = src.rows / 8;
int rowLeft = src.rows % 8;

// 2.算出一列有几个8,剩下几个像素
int countCol = src.cols / 8;
int colLeft = src.cols % 8;

target3 = Mat::zeros(src.size(), src.type());

for (int k = 0; k < countRow; k++) {
for (int l = 0; l < countCol; l++) {
int value = 0;
for (int i = k * 8; i < (k + 1) * 8; i++) {
for (int j = l * 8; j < (l + 1) * 8; j++) {
value += (int)src.at<uchar>(i, j);
}
}
value = value / 64;
for (int i = k * 8; i < (k + 1) * 8; i++) {
for (int j = l * 8; j < (l + 1) * 8; j++) {
if ((int)src.at<uchar>(i, j) < value)
target3.at<uchar>(i, j) = 0;
else
target3.at<uchar>(i, j) = 255;
}
}
}
}

//底部不足8*8部分
if (rowLeft != 0) {
for (int k = countRow; k < countRow + rowLeft; k++) {
for (int l = 0; l < countCol; l++) {
int value = 0;
for (int i = countRow * 8; i < countRow * 8 + rowLeft; i++) {
for (int j = l * 8; j < (l + 1) * 8; j++) {
value += (int)src.at<uchar>(i, j);
}
}
value = value / (8 * rowLeft);
for (int i = countRow * 8; i < countRow * 8 + rowLeft; i++) {
for (int j = l * 8; j < (l + 1) * 8; j++) {
if ((int)src.at<uchar>(i, j) < value)
target3.at<uchar>(i, j) = 0;
else
target3.at<uchar>(i, j) = 255;
}
}
}
}
}
//右侧不足8*8部分
if (colLeft != 0) {
for (int k = 0; k < countRow; k++) {
for (int l = countCol; l < countCol + colLeft; l++) {
int value = 0;
for (int i = k * 8; i < (k + 1) * 8; i++) {
for (int j = countCol * 8; j < countCol * 8 + colLeft; j++) {
value += (int)src.at<uchar>(i, j);
}
}
value = value / (8 * colLeft);
for (int i = k * 8; i < (k + 1) * 8; i++) {
for (int j = countCol * 8; j < countCol * 8 + colLeft; j++) {
if ((int)src.at<uchar>(i, j) < value)
target3.at<uchar>(i, j) = 0;
else
target3.at<uchar>(i, j) = 255;
}
}
}
}
}
//右下角 rowleft * colleft 部分
if (rowLeft != 0 && colLeft != 0) {
int value = 0;
for (int i = 8 * countRow; i < src.rows; i++) {
for (int j = 8 * countCol; j < src.cols; j++) {
value += (int)src.at<uchar>(i, j);
}
}
value = value / (rowLeft * colLeft);
for (int i = 8 * countRow; i < src.rows; i++) {
for (int j = 8 * countCol; j < src.cols; j++) {
if ((int)src.at<uchar>(i, j) < value)
target3.at<uchar>(i, j) = 0;
else
target3.at<uchar>(i, j) = 255;
}
}
}
}

int main() {
//加上0表示读入灰度图
image3 = imread("1.jpg", 0);

if (image3.empty()) {
printf("could not load pic!\n");
return -1;
}

imshow("image3", image3);

localTwoValue(image3);

imshow("target3", target3);

waitKey(0);

return 0;
}

效果如下:

局部阈值

参考资料


OpenCV4入门教程029:全局阈值和局部阈值
https://blog.jackeylea.com/opencv/introduction-of-opencv-threshold/
作者
JackeyLea
发布于
2020年6月7日
许可协议