Files

140 lines
7.0 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* ============================================================
* 实验 3:高斯模糊 (Gaussian Blur)
* 知识点:cv::GaussianBlur
* ============================================================
*
* 【实验目标】
* 1. 理解"模糊"本质上是什么(图像怎么变模糊的)
* 2. 掌握 cv::GaussianBlur 函数的参数含义
* 3. 观察不同卷积核大小对模糊效果的影响
*
* 【生活化比喻】
* 高斯模糊就像透过一块"毛玻璃"或"近视眼镜"看东西:
* - 原来的图像每个像素都很清晰(边界分明)
* - 模糊后,每个像素和它周围的像素颜色混在一起了
* - 核(kernel)越大,相当于毛玻璃越厚,混的范围越大,越模糊
*
* 为什么叫"高斯"?
* - 高斯(Gauss)是一位伟大的数学家
* - 他发现了一种"钟形曲线"(正态分布),用来描述自然界的很多现象
* - 在图像上,就是用这个钟形曲线来决定"周围的像素各占多大权重"
* - 距离中心越近的像素权重越大(理所当然嘛,最近的邻居影响最大)
*
* 在 RoboMaster 中为什么需要模糊?
* - 消除图像噪声(摄像头传感器本身的噪点)
* - 让后续的边缘检测、颜色提取更稳定
* - 像是"先把细节捋平,再找关键特征"
*
* 【函数详解】
* cv::GaussianBlur(src, dst, ksize, sigmaX, sigmaY, borderType)
*
* src :输入图像(可以是一张有明显边缘的图)
* dst :输出图像(大小和类型与输入相同)
* ksize :高斯核的大小,必须是奇数!(如 (3,3), (5,5), (15,15))
* 为什么是奇数?因为要有一个"中心像素",核以它为中心对称展开
* sigmaX :X 方向上的高斯标准差(控制左右方向的模糊程度)
* 如果设为 0,OpenCV 会根据 ksize 自动帮你算一个合适的值
* sigmaY :Y 方向上的高斯标准差(控制上下方向的模糊程度)
* 如果设为 0,等于 sigmaX
* borderType :边界处理方式(可选参数,默认即可)
*/
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
int main()
{
std::cout << "[步骤 1] 正在生成测试图片(含清晰边缘和纹理)..." << std::endl;
// 创建一张 400×400 的白色画布
cv::Mat original(400, 400, CV_8UC3, cv::Scalar(255, 255, 255));
// 画各种形状 —— 这些形状有清晰的边缘,模糊后效果明显
// 蓝色实心圆
cv::circle(original, cv::Point(100, 100), 60, cv::Scalar(255, 0, 0), -1);
// 绿色矩形框
cv::rectangle(original, cv::Point(200, 50), cv::Point(350, 150),
cv::Scalar(0, 200, 0), 3);
// 红色三角形(用 line 画三条线)
cv::line(original, cv::Point(50, 320), cv::Point(200, 200),
cv::Scalar(0, 0, 255), 5);
cv::line(original, cv::Point(200, 200), cv::Point(350, 320),
cv::Scalar(0, 0, 255), 5);
cv::line(original, cv::Point(350, 320), cv::Point(50, 320),
cv::Scalar(0, 0, 255), 5);
// 写文字(文字边缘也是测试模糊的好素材)
cv::putText(original, "OpenCV", cv::Point(80, 370),
cv::FONT_HERSHEY_SIMPLEX, 1.2, cv::Scalar(0, 0, 0), 3);
// 画一些散点(模拟噪声,模糊后会被消除)
for (int i = 0; i < 300; i++)
{
int x = rand() % 400; // 随机 X 坐标(0~399)
int y = rand() % 400; // 随机 Y 坐标(0~399)
// 每个点画一个 2×2 的小方块(因为单个像素可能看不清)
cv::rectangle(original, cv::Point(x, y), cv::Point(x + 2, y + 2),
cv::Scalar(0, 0, 0), -1);
}
cv::imwrite("original.jpg", original);
std::cout << " -> 原始图片已保存为 original.jpg(注意看上面的散点噪声)" << std::endl;
// ==========================================
// 核心实验:对比不同模糊程度
// ==========================================
// --- 模糊程度 1:轻微模糊(ksize = 3×3)---
// 3×3 的核非常小,只混合当前像素和它最近的 8 个邻居
// 效果:能消除最细小的噪点,但基本保留图像结构
std::cout << "[步骤 2] 应用轻微高斯模糊 (ksize = 3x3)..." << std::endl;
cv::Mat blur_light;
cv::GaussianBlur(original, blur_light, cv::Size(3, 3), 0, 0);
cv::imwrite("blur_3x3.jpg", blur_light);
std::cout << " -> 已保存为 blur_3x3.jpg(轻微模糊,细节基本保留)" << std::endl;
// --- 模糊程度 2:中度模糊(ksize = 9×9)---
// 9×9 的核覆盖了 81 个像素的范围
// 效果:散点噪声明显消失,边缘变得柔和
std::cout << "[步骤 3] 应用中度高模糊 (ksize = 9x9)..." << std::endl;
cv::Mat blur_medium;
cv::GaussianBlur(original, blur_medium, cv::Size(9, 9), 0, 0);
cv::imwrite("blur_9x9.jpg", blur_medium);
std::cout << " -> 已保存为 blur_9x9.jpg(中度模糊,噪声消失,边缘变软)" << std::endl;
// --- 模糊程度 3:重度模糊(ksize = 21×21)---
// 21×21 的核非常大,覆盖了 441 个像素的范围
// 效果:图像变得严重模糊,细节几乎全部丢失
// 这在实际应用中通常不会用这么大的核,这里纯粹为了演示
std::cout << "[步骤 4] 应用重度高斯模糊 (ksize = 21x21)..." << std::endl;
cv::Mat blur_heavy;
cv::GaussianBlur(original, blur_heavy, cv::Size(21, 21), 0, 0);
cv::imwrite("blur_21x21.jpg", blur_heavy);
std::cout << " -> 已保存为 blur_21x21.jpg(重度模糊,近乎一片朦胧)" << std::endl;
// --- 模糊程度 4:X/Y 方向不同模糊程度 ---
// 前面三个例子 sigmaX 和 sigmaY 都设为 0(自动计算)
// 这里我们手动指定不同方向的标准差:X 方向模糊大,Y 方向模糊小
std::cout << "[步骤 5] 应用各向异性模糊 (sigmaX=15, sigmaY=3)..." << std::endl;
cv::Mat blur_aniso;
cv::GaussianBlur(original, blur_aniso, cv::Size(0, 0), 15, 3);
// 注意:当 ksize 设为 (0,0) 时,OpenCV 会根据 sigma 自动计算合适的核大小
// sigmaX=15(水平方向大模糊)比 sigmaY=3(垂直方向小模糊)大很多
// 所以效果是:水平方向被"抹平"得很厉害,垂直方向相对清晰
cv::imwrite("blur_anisotropic.jpg", blur_aniso);
std::cout << " -> 已保存为 blur_anisotropic.jpg(水平方向很糊,垂直方向较清晰)" << std::endl;
// 总结
std::cout << std::endl;
std::cout << "===== 实验 3 完成 =====" << std::endl;
std::cout << "你学会了:" << std::endl;
std::cout << " 1. GaussianBlur 用高斯分布对像素进行加权平均" << std::endl;
std::cout << " 2. ksize 越大,模糊范围越大(必须是奇数!)" << std::endl;
std::cout << " 3. sigma 控制模糊的标准差(0 表示自动计算)" << std::endl;
std::cout << " 4. 模糊是后续边缘检测、颜色提取的重要预处理步骤" << std::endl;
return 0;
}