图像噪声
- 噪声类型
椒盐噪声、高斯噪声、其他噪声
- 噪声生成
(1)生成椒盐噪声:利用RNG 随机产生坐标点位置,然后对src相应的位置赋黑色的或者白色的像素值
API:RNG
//RNG
int uniform(int a, int b);
//salt and pepper
RNG rng(12345);
int h = src.rows;
int w = src.cols;
int nums = 10000;
for (int i = 0; i < nums; i++) {
int x = rng.uniform(0, w);
int y = rng.uniform(0, h);
if (i % 2 == 1) {
src.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
}
else {
src.at<Vec3b>(y, x) = Vec3b(0, 0, 0);
}
}
(2)生成高斯噪声:利用 randn, 生成正太分布随机图像
API :randn
CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev);
//gausi noise
Mat image = src.clone();
Mat noise = Mat::zeros(image.size(), image.type());
randn(noise, Scalar(25, 15, 45), Scalar(60, 40, 30));
imshow("noise", noise);
Mat dst;
add(image, noise, dst);
imshow("gaussian noise", dst);
图像去噪
- 对于不同的噪声类型,应该选择合适的去噪方法,已达到最好的去噪效果
- 中值滤波和均值滤波
中值滤波属于统计排序滤波器,对于椒盐噪声去噪效果较好,ksize 取奇数,可以看出 ksize 对于滤波结果的影响较大
API:medianBlur
CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );
void add_salt_pepper_noise(Mat &image);//给图像添加椒盐噪声
void add_gaussian_noise(Mat& image);//给图像添加高斯噪声
//图像去噪
int main() {
Mat src = imread("F:/code/images/gaoyy.png");
if (src.empty()) {
printf("fail to read");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
//加椒盐噪声
add_salt_pepper_noise(src);
imshow("salt_pepper_noise", src);
//加高斯噪声
//add_gaussian_noise(src);
//imshow("gaussian_noise", src);
//中值滤波 对椒盐去噪
Mat dst;
medianBlur(src, dst, 5);
imshow("meidan denoise demo", dst);
//高斯滤波 对椒盐去噪很不理想
Mat dst2;
GaussianBlur(src, dst2, Size(5,5),0);
imshow("gaussian denoise demo", dst2);
waitKey(0);
destroyAllWindows();
return 0;
}
void add_salt_pepper_noise(Mat& image){
//salt and pepper noise
RNG rng(12345);
int h = image.rows;
int w = image.cols;
int nums = 10000;
for (int i = 0; i < nums; i++) {
int x = rng.uniform(0, w);
int y = rng.uniform(0, h);
if (i % 2 == 1) {
image.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
}
else {
image.at<Vec3b>(y, x) = Vec3b(0, 0, 0);
}
}
return;
}
void add_gaussian_noise(Mat& image){
//gausi noise
Mat noise = Mat::zeros(image.size(), image.type());
randn(noise, Scalar(25, 15, 45), Scalar(60, 40, 30));
add(image, noise, image);
return;
}
通过实验发现,中值滤波对椒盐噪声去噪效果很好,高斯滤波对椒盐噪声去噪效果很差;中值滤波和高斯滤波对高斯噪声去噪效果都很差!期待其它的方法对高斯噪声进行去噪,也就是后面的边缘保留滤波
- 边缘保留滤波
1.均值与高斯滤波的缺点:
均值:没有考虑中心像素点对整个输出像素的贡献,给定相同的权重,导致都会被模糊
高斯:考虑了中心像素点对输出像素的贡献,权重符合高斯分布,但是没考虑到如果中心像素点和周围像素点差值过大的情况是有边缘和梯度存在,而应当保留这种边缘信息。
2.**边缘保留滤波算法:**高斯双边、均值迁移、非局部均值去噪、局部均方差
高斯双边:
- API:
bilateralFilter
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
double sigmaColor, double sigmaSpace,
int borderType = BORDER_DEFAULT );
- 高斯双边对高斯噪声去噪:
//高斯双边
Mat dst3;
bilateralFilter(src, dst3, 0, 100, 10);
imshow("bilateral ", dst3);
-
高斯双边滤波(模糊):对input图片采用双边滤波得到bilateral,可见效果非常棒,细节都保留得很好!早期的 ps 中的磨皮算法就是基于高斯双边滤波
非局部均值滤波:Non-Local Means (NLM)真正的图像去噪方法 -
考虑到了图像的 自相似 性质,它充分利用了图像中的冗余信息,在去噪的同时能够最大程度的保持图像的细节特征。
-
API
此算法在 opencv 中有两个API,一个是针对灰度图fastNlMeansDenoising
,一个是针对彩色图fastNlMeansDenoisingColored
,这个算法运行非常慢,可以尝试快速的版本API
CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst,
float h = 3, float hColor = 3,
int templateWindowSize = 7, int searchWindowSize = 21);
CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3,
int templateWindowSize = 7, int searchWindowSize = 21);
- 实例
//非局部均值滤波
Mat dst4;
fastNlMeansDenoisingColored(src, dst4, 3.0, 3.0, 7, 21);
imshow("NLM denoise color", dst4);
Mat gray, dst5;
cvtColor(src, gray, COLOR_BGR2GRAY);
fastNlMeansDenoising(gray, dst5, 3.0, 7, 21);
imshow("NLM denoise gray", dst5);
PS:增加 templateWindowSize 、 searchWindowSize 可以改变滤波效果