知识点:
边缘保留滤波算法 – 均值迁移模糊(mean-shift blur):
均值迁移模糊是图像边缘保留滤波算法中一种,经常用来在对图像进行分水岭分割之前去噪声,可以大幅度提升分水岭分割的效果。其基本原理如下:
在n维空间中,有一定数量的样本,我们选定其中的一个样本,以该样本为中心,给定长度为半径画一个圆,求取该圆形区域内样本的质心,即密度最大的点,再以该点为中心继续执行上述迭代过程,直至最终收敛。
相关API:
void pyrMeanShiftFiltering( InputArray src, OutputArray dst,
double sp, double sr, int maxLevel = 1,
TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) );
- src:The source 8-bit, 3-channel image.
- dst:The destination image of the same format and the same size as the source.
- sp:The spatial window radius. 空间窗口半径
- sr:The color window radius. 颜色窗口半径
- maxLevel:Maximum level of the pyramid for the segmentation. 定义金字塔的最大层数。按默认即可
- termcrit:均值迁移终止条件。为了提高效率,我们通常会给定一个人为的终止条件。默认值的5表示最大迭代次数为5次,1表示两次迁移的dx和dy的差值小于等于1,迁移终止。两个终止条件可结合使用,也可分开使用。通常默认即可。
其执行过程如下:
以输入图像上src上任一点P0为圆心,建立物理空间上半径为sp,色彩空间上半径为sr的球形空间,物理空间上坐标为x、y,色彩空间上坐标为R、G、B(或HSV),构成一个5维的向量空间。
其中物理空间的范围x和y是图像的长和宽,色彩空间的范围R、G、B分别是0~255。
类比于3 x 3卷积窗口的默认值为[-1, 0, 1],我们可以对图像的空间窗口和颜色值窗口计算均值,得到dx和dy,以及新的RGB颜色值。
在这个过程中,关键参数是sp和sr的设置,二者设置的值越大,对图像色彩的平滑效果越明显,同时函数耗时也越多。
代码演示:
#ifndef DAY27
#define DAY27
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void gaussian_noise(Mat &image);
void day27() {
Mat src = Mat::zeros(Size(400, 400), CV_8UC3);
src(Rect(0, 0, 200, 200)).setTo(Scalar(64, 64, 64));
src(Rect(200, 0, 200, 200)).setTo(Scalar(128, 128, 128));
src(Rect(0, 200, 200, 200)).setTo(Scalar(192, 192, 192));
src(Rect(200, 200, 200, 200)).setTo(Scalar(255, 255, 255));
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
Mat dst;
pyrMeanShiftFiltering(src, dst, 15, 50, 1, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 5, 1));
imshow("几何图-均值迁移模糊", dst);
src = imread("G:/opencvTest/girl.jpg");
if (src.empty()) {
printf("could not load image...\n");
return;
}
imshow("input", src);
gaussian_noise(src);
pyrMeanShiftFiltering(src, dst, 15, 50, 1, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 5, 1));
imshow("人物-均值迁移模糊", dst);
waitKey();
}
void gaussian_noise(Mat &image) {
Mat noise = Mat::zeros(image.size(), image.type());
// 通过randn产生高斯随机噪声来填充矩阵,15是高斯均值,30是高斯方差
randn(noise, 15, 30);
Mat dst;
add(image, noise, dst);
imshow("gaussian noise", dst);
dst.copyTo(image);
}
#endif // !DAY27
结果展示: