Opencv的Gamma转换与二值化处理

1. 头文件和命名空间

1
2
3
4
5
6
7
#include <opencv2/opencv.hpp>  // 包含OpenCV库的所有主要功能
#include <iostream> // 输入输出流,用于在控制台显示信息
#include <vector> // 向量容器,用于存储数据
#include <cmath> // 数学函数库

using namespace cv; // 使用OpenCV的命名空间,这样就不用写cv::了
using namespace std; // 使用标准库的命名空间

通俗理解:就像在游戏开始前要导入各种工具包,这些#include就是告诉编译器我们需要用到哪些工具。

2. Gamma变换函数详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Gamma变换函数 - 就像调整手机屏幕的亮度曲线
Mat gammaCorrection(const Mat& src, double gamma) {
// Mat是OpenCV的"图片容器",可以想象成一个装图片数据的盒子
// const Mat& src 表示输入图片,&表示引用(不复制数据),const表示不会修改原图

// 创建查找表 - 就像制作一个亮度转换表
Mat lookupTable(1, 256, CV_8U);
// 这个表有1行,256列,每个元素是8位无符号整数(0-255)

uchar* p = lookupTable.ptr(); // 获取表的指针,方便操作数据
for (int i = 0; i < 256; ++i) {
// 计算新的亮度值:pow(i/255.0, gamma) * 255.0
// 就像把0-255的亮度值按照gamma曲线重新映射
p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma) * 255.0);
// saturate_cast确保计算结果在0-255范围内,不会溢出
}

Mat dst; // 创建输出图片的容器
LUT(src, lookupTable, dst); // 使用查找表转换图片
// LUT = Look Up Table,就像根据转换表把每个像素的亮度值换成新的

return dst; // 返回处理后的图片
}

Gamma变换原理

  • gamma < 1:增强暗部细节(让暗的地方变亮)
  • gamma > 1:增强亮部细节(让亮的地方更突出)
  • gamma = 1:不做任何改变

3. 二值化函数详解

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
// 自适应二值化处理 - 把图片变成黑白两色
Mat adaptiveBinary(const Mat& src) {
Mat gray, binary; // 创建灰度图和二值图的容器

// 判断输入图片是彩色还是灰度
if (src.channels() == 3) {
// 如果是彩色图片(3个通道:蓝、绿、红)
cvtColor(src, gray, COLOR_BGR2GRAY);
// cvtColor是颜色转换函数,把BGR彩色图转成灰度图
} else {
gray = src.clone(); // 如果已经是灰度图,就复制一份
// clone()是深拷贝,创建完全独立的新副本
}

// 自适应阈值二值化 - 智能黑白化
adaptiveThreshold(gray, binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C,
THRESH_BINARY, 11, 2);
// 参数解释:
// gray: 输入灰度图
// binary: 输出二值图
// 255: 超过阈值的像素设为白色(255)
// ADAPTIVE_THRESH_GAUSSIAN_C: 使用高斯加权计算局部阈值
// THRESH_BINARY: 二值化模式(大于阈值=白,小于阈值=黑)
// 11: 邻域大小(计算阈值时考虑的局部区域大小)
// 2: 从平均权重中减去的常数

return binary; // 返回黑白图片
}

4. 主函数详细解析

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
int main() {
// 读取图像 - 就像从文件里加载一张图片
Mat src = imread("src.png");
// Mat是OpenCV的核心类,用来存储图片数据
// 可以想象成一种智能的图片容器

if (src.empty()) { // 检查图片是否加载成功
cout << "无法读取图像文件 src.png" << endl;
return -1; // 返回-1表示程序异常结束
}

// 显示图片信息
cout << "图像尺寸: " << src.size() << endl; // 图片的宽度和高度
cout << "图像通道数: " << src.channels() << endl; // 颜色通道数(3=彩色,1=灰度)

// 创建窗口并显示原始图像
namedWindow("原始图像", WINDOW_NORMAL); // 创建可调整大小的窗口
imshow("原始图像", src); // 在窗口中显示图片

// 步骤1: Gamma变换增强对比度
double gamma = 0.5; // Gamma值,这里设为0.5来增强暗部细节
Mat gamma_img = gammaCorrection(src, gamma);
// 调用我们之前写的Gamma变换函数

namedWindow("Gamma变换后", WINDOW_NORMAL);
imshow("Gamma变换后", gamma_img);

// 步骤2: 转换为灰度图
Mat gray;
cvtColor(gamma_img, gray, COLOR_BGR2GRAY);
// 把Gamma处理后的彩色图转成灰度图,减少计算量

// 步骤3: 自适应二值化
Mat binary = adaptiveBinary(gray);
// 调用二值化函数,得到黑白图片

// 步骤4: 形态学操作去除噪声 - 就像给图片"美容"
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 创建3x3的矩形结构元素,用于形态学操作

morphologyEx(binary, binary, MORPH_OPEN, kernel);
// 开运算:先腐蚀后膨胀,去除小噪点,平滑边界

// 显示最终的二值化结果
namedWindow("二值化结果", WINDOW_NORMAL);
imshow("二值化结果", binary);

// 保存处理后的图像
vector<int> compression_params; // 创建整数向量存储压缩参数
compression_params.push_back(IMWRITE_PNG_COMPRESSION); // 添加压缩类型
compression_params.push_back(9); // 压缩级别(0-9,9=最高压缩)

imwrite("processed_result.png", binary, compression_params);
cout << "处理后的图像已保存为 processed_result.png" << endl;

// 等待按键 - 程序停在这里,直到用户按任意键
waitKey(0);

return 0; // 程序正常结束
}

核心概念解释

1. Mat 是什么?

Mat 是OpenCV的图片容器类,可以理解为:

  • 一个智能的图片数据盒子
  • 自动管理内存,不用手动分配和释放
  • 存储像素数据、尺寸、颜色通道等信息

2. 关键函数的作用:

  • imread():读取图片文件
  • imshow():显示图片
  • imwrite():保存图片
  • cvtColor():颜色空间转换
  • namedWindow():创建显示窗口
  • waitKey():等待用户输入

3. 处理流程总结:

  1. 读图 → 2. Gamma增强 → 3. 转灰度 → 4. 二值化 → 5. 去噪 → 6. 显示保存

完整可运行代码

把以下代码保存为 main.cpp

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
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

// Gamma变换:调整图片亮度曲线
Mat gammaCorrection(const Mat& src, double gamma) {
Mat lookupTable(1, 256, CV_8U);
uchar* p = lookupTable.ptr();
for (int i = 0; i < 256; ++i) {
p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma) * 255.0);
}

Mat dst;
LUT(src, lookupTable, dst);
return dst;
}

// 二值化:把图片变成黑白两色
Mat adaptiveBinary(const Mat& src) {
Mat gray, binary;

if (src.channels() == 3) {
cvtColor(src, gray, COLOR_BGR2GRAY);
} else {
gray = src.clone();
}

adaptiveThreshold(gray, binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C,
THRESH_BINARY, 11, 2);
return binary;
}

int main() {
// 1. 读取图片
Mat src = imread("src.png");
if (src.empty()) {
cout << "错误:找不到src.png文件!" << endl;
return -1;
}

// 2. Gamma变换增强
Mat gamma_img = gammaCorrection(src, 0.5);

// 3. 二值化处理
Mat binary = adaptiveBinary(gamma_img);

// 4. 显示结果
imshow("原始图像", src);
imshow("处理结果", binary);

// 5. 保存结果
imwrite("processed_result.png", binary);
cout << "处理完成!结果已保存为processed_result.png" << endl;

waitKey(0);
return 0;
}

这样解释后,你应该能理解每一行代码的作用了!这个程序的核心思想就是:先调整亮度让数字更明显,然后转换成黑白图让数字突出显示