实验5目录
实验内容
- 读入图像,给图像加上不同类别的噪声;
- 分别采用均值滤波器、中值滤波器、自适应中值滤波器去除图像噪声;
- 分析比较不同滤波器对不同噪声的去除效果。
运行效果
项目组织格式:
原图:
加了椒盐噪声之后的图像:
加了高斯噪声之后的图像:
盐噪声的均值滤波:
高斯噪声的均值滤波:
盐噪声的中值滤波:
高斯噪声的中值滤波:
盐噪声的自适应中值滤波:
高斯噪声的自适应中值滤波:
项目源码
Headers
DigitalGraphicExp5.h
// DigitalGraphicExp5.h
#pragma once
#include "addSaltNoise.h"
#include "addGaussNoise.h"
#include "aveFilter.h"
#include "midFilter.h"
#include "adaptiveFilter.h"
#include <opencv.hpp>
midFilter.h
// midFilter.h
#pragma once
#include <opencv2/opencv.hpp>
cv :: Mat midFilter(const cv :: Mat &src);
randomInt.h
// randomInt.h
#pragma once
#include <cstdlib>
int random_num_generator(int a, int b);
aveFilter.h
// aveFilter.h
#pragma once
#include <opencv2/opencv.hpp>
cv :: Mat aveFilter(const cv :: Mat &src);
addSaltNoise.h
// addSaltNoise.h
#pragma once
#include <opencv2/opencv.hpp>
/*
* Param1 : Mat
* Param2 : n noise points
*/
cv :: Mat addSaltNoise(const cv :: Mat & src_img, int n);
addGaussNoise.h
// addGaussNoise.h
#pragma once
#include <limits>
#include <opencv2/opencv.hpp>
cv :: Mat addGaussianNoise(cv :: Mat &srcImag);
adaptiveFilter.h
// adaptiveFilter.h
#pragma once
#include "adaptiveFilter.h"
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
Mat adaptiveFilter(const Mat &src, int minSize = 3, int maxSize = 7);
Sources
DigitalGraphicExp5.cpp
// DigitalGraphicExp5.cpp
//
#include "pch.h"
#include <iostream>
#include "DigitalGraphicExp5.h"
using namespace cv;
using namespace std;
int main()
{
String imageName = "../media/cat.jpg";
Mat src_img = imread(imageName, IMREAD_COLOR);
if (src_img.empty()) {
cout << "OPEN ERROR" << endl;
return -1;
}
imshow("SRC IMG", src_img);
Mat saltImg = addSaltNoise(src_img, 100);
imshow("SALT IMG", saltImg);
Mat gaussImg = addGaussianNoise(src_img);
imshow("GAUSS IMG", gaussImg);
Mat aveFixedSaltImg = aveFilter(saltImg);
imshow("AVERAGE FIXED SALT IMG", aveFixedSaltImg);
Mat aveFixedGaussImg = aveFilter(gaussImg);
imshow("AVERAGE FIXED GAUSS IMG", aveFixedGaussImg);
Mat midFixedSaltImg = midFilter(saltImg);
imshow("MID FIXED SALT IMG", midFixedSaltImg);
Mat midFixedGaussImg = midFilter(gaussImg);
imshow("MID FIXED GAUSS IMG", midFixedGaussImg);
Mat adaptiveFixedSaltImg = adaptiveFilter(saltImg);
imshow("ADAPTIVE FIXED SALT IMG", adaptiveFixedSaltImg);
Mat adaptiveFixedGaussImg = adaptiveFilter(gaussImg);
imshow("ADAPTIVE FIXED GAUSS IMG", adaptiveFixedGaussImg);
waitKey();
return 0;
}
randomInt.cpp
// randomInt.cpp
#include "randomInt.h"
int random_num_generator(int a, int b) {
int temp = int(double(rand()) / RAND_MAX * (b - a) + a);
return temp;
}
midFilter.cpp
// midFilter.cpp
#include "midFilter.h"
using namespace cv;
static uchar returnMid(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,
uchar n6, uchar n7, uchar n8, uchar n9) {
uchar arr[9] = { n1, n2, n3, n4, n5, n6, n7, n8, n9 };
// Shell sort
for (int gap = 9 / 2; gap > 0; gap /= 2)
for (int i = gap; i < 9; ++i)
for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
swap(arr[j], arr[j + gap]);
return arr[4];
}
Mat midFilter(const Mat &src) {
Mat _dst(src.size(), src.type());
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols) {
_dst.at<Vec3b>(i, j)[0] = returnMid(src.at<Vec3b>(i, j)[0], src.at<Vec3b>(i + 1, j + 1)[0],
src.at<Vec3b>(i + 1, j)[0], src.at<Vec3b>(i, j + 1)[0], src.at<Vec3b>(i + 1, j - 1)[0],
src.at<Vec3b>(i - 1, j + 1)[0], src.at<Vec3b>(i - 1, j)[0], src.at<Vec3b>(i, j - 1)[0],
src.at<Vec3b>(i - 1, j - 1)[0]);
_dst.at<Vec3b>(i, j)[1] = returnMid(src.at<Vec3b>(i, j)[1], src.at<Vec3b>(i + 1, j + 1)[1],
src.at<Vec3b>(i + 1, j)[1], src.at<Vec3b>(i, j + 1)[1], src.at<Vec3b>(i + 1, j - 1)[1],
src.at<Vec3b>(i - 1, j + 1)[1], src.at<Vec3b>(i - 1, j)[1], src.at<Vec3b>(i, j - 1)[1],
src.at<Vec3b>(i - 1, j - 1)[1]);
_dst.at<Vec3b>(i, j)[2] = returnMid(src.at<Vec3b>(i, j)[2], src.at<Vec3b>(i + 1, j + 1)[2],
src.at<Vec3b>(i + 1, j)[2], src.at<Vec3b>(i, j + 1)[2], src.at<Vec3b>(i + 1, j - 1)[2],
src.at<Vec3b>(i - 1, j + 1)[2], src.at<Vec3b>(i - 1, j)[2], src.at<Vec3b>(i, j - 1)[2],
src.at<Vec3b>(i - 1, j - 1)[2]);
}
else
_dst.at<Vec3b>(i, j) = src.at<Vec3b>(i, j);
}
return _dst;
}
aveFilter.cpp
// aveFilter.cpp
#include "aveFilter.h"
using namespace cv;
Mat aveFilter(const Mat &src) {
Mat dst(src.size(), src.type());
for (int i = 0; i < src.rows ; ++i)
for (int j = 0; j < src.cols ; ++j) {
// Does not deal with the borders
if ((i - 1 >= 0) && (j - 1) >= 0 && (i + 1) < src.rows && (j + 1) < src.cols) {
dst.at<Vec3b>(i, j)[0] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i - 1, j - 1)[0] + src.at<Vec3b>(i - 1, j)[0] + src.at<Vec3b>(i, j - 1)[0] +
src.at<Vec3b>(i - 1, j + 1)[0] + src.at<Vec3b>(i + 1, j - 1)[0] + src.at<Vec3b>(i + 1, j + 1)[0] + src.at<Vec3b>(i, j + 1)[0] +
src.at<Vec3b>(i + 1, j)[0]) / 9;
dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i - 1, j - 1)[1] + src.at<Vec3b>(i - 1, j)[1] + src.at<Vec3b>(i, j - 1)[1] +
src.at<Vec3b>(i - 1, j + 1)[1] + src.at<Vec3b>(i + 1, j - 1)[1] + src.at<Vec3b>(i + 1, j + 1)[1] + src.at<Vec3b>(i, j + 1)[1] +
src.at<Vec3b>(i + 1, j)[1]) / 9;
dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] + src.at<Vec3b>(i - 1, j - 1)[2] + src.at<Vec3b>(i - 1, j)[2] + src.at<Vec3b>(i, j - 1)[2] +
src.at<Vec3b>(i - 1, j + 1)[2] + src.at<Vec3b>(i + 1, j - 1)[2] + src.at<Vec3b>(i + 1, j + 1)[2] + src.at<Vec3b>(i, j + 1)[2] +
src.at<Vec3b>(i + 1, j)[2]) / 9;
}
else {
// Deal with borders
dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
}
}
return dst;
}
addSaltNoise.cpp
// addSaltNoise.cpp
#include "addSaltNoise.h"
#include "randomInt.h"
using namespace cv;
Mat addSaltNoise(const Mat & src_img, int n)
{
Mat dst_img = src_img.clone();
// Add pepper
for (int k = 0; k < n; k++) {
// Choose the row and col randomly
// Create the pepper noise
int i = random_num_generator(0, dst_img.rows - 1);
int j = random_num_generator(0, dst_img.cols - 1);
// Only deal with BGR imgs
dst_img.at<Vec3b>(i, j)[0] = 255;
dst_img.at<Vec3b>(i, j)[1] = 255;
dst_img.at<Vec3b>(i, j)[2] = 255;
}
for (int k = 0; k < n; k++) {
// Select the noise point randomly
// Add the salt noise
int i = random_num_generator(0, dst_img.rows - 1);
int j = random_num_generator(0, dst_img.cols - 1);
dst_img.at<Vec3b>(i, j)[0] = 0;
dst_img.at<Vec3b>(i, j)[1] = 0;
dst_img.at<Vec3b>(i, j)[2] = 0;
}
return dst_img;
}
addGaussNoise.cpp
// addGaussNoise.cpp
#include "addGaussNoise.h"
using namespace cv;
using namespace std;
static double generateGaussianNoise(double mu, double sigma)
{
// Define threshold
const double epsilon = numeric_limits<double>::min();
static double z0, z1;
static bool flag = false;
flag = !flag;
// Generate x randomly when flag is false
if (!flag)
return z1 * sigma + mu;
double u1, u2;
// Generate random variable
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
// Generate random varaible
z0 = sqrt(-2.0*log(u1)) * cos(2 * CV_PI*u2);
z1 = sqrt(-2.0*log(u1)) * sin(2 * CV_PI*u2);
return z0 * sigma + mu;
}
// Add Gauss noise to the img
Mat addGaussianNoise(Mat &srcImag)
{
Mat dstImage = srcImag.clone();
int channels = dstImage.channels();
int rowsNumber = dstImage.rows;
int colsNumber = dstImage.cols*channels;
if (dstImage.isContinuous())
{
colsNumber *= rowsNumber;
rowsNumber = 1;
}
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
// Add Gaussian noise
int val = dstImage.ptr<uchar>(i)[j] +
generateGaussianNoise(2, 0.8) * 32;
if (val < 0)
val = 0;
if (val > 255)
val = 255;
dstImage.ptr<uchar>(i)[j] = (uchar)val;
}
}
return dstImage;
}
adaptiveFilter.cpp
// adaptiveFilter.cpp
#include "adaptiveFilter.h"
static uchar adaptiveProcessKernel(const Mat &src, int row, int col, int kernelSize, int maxSize)
{
vector<uchar> pixels;
for (int a = -kernelSize / 2; a <= kernelSize / 2; a++)
for (int b = -kernelSize / 2; b <= kernelSize / 2; b++)
{
pixels.push_back(src.at<uchar>(row + a, col + b));
}
sort(pixels.begin(), pixels.end());
auto min = pixels[0];
auto max = pixels[kernelSize * kernelSize - 1];
auto med = pixels[kernelSize * kernelSize / 2];
auto zxy = src.at<uchar>(row, col);
if (med > min && med < max)
{
// to B
if (zxy > min && zxy < max)
return zxy;
else
return med;
}
else
{
kernelSize += 2;
if (kernelSize <= maxSize)
return adaptiveProcessKernel(src, row, col, kernelSize, maxSize);
// Expand the size of the Img, and continue the process A
else
return med;
}
}
Mat adaptiveFilter(const Mat &src, int minSize , int maxSize) {
Mat dst(src.size(), src.type());
// Expand the border of the img
// Scan the img
std::vector<cv::Mat> bgr;
cv::split(src, bgr);
copyMakeBorder(bgr[0], bgr[0], maxSize / 2, maxSize / 2, maxSize / 2, maxSize / 2, BorderTypes::BORDER_REFLECT);
copyMakeBorder(bgr[1], bgr[1], maxSize / 2, maxSize / 2, maxSize / 2, maxSize / 2, BorderTypes::BORDER_REFLECT);
copyMakeBorder(bgr[2], bgr[2], maxSize / 2, maxSize / 2, maxSize / 2, maxSize / 2, BorderTypes::BORDER_REFLECT);
for (int j = maxSize / 2; j < bgr[0].rows - maxSize / 2; j++)
{
for (int i = maxSize / 2; i < bgr[0].cols - maxSize / 2; i++)
{
bgr[0].at<uchar>(j, i) = adaptiveProcessKernel(bgr[0], j, i, minSize, maxSize);
bgr[1].at<uchar>(j, i) = adaptiveProcessKernel(bgr[1], j, i, minSize, maxSize);
bgr[2].at<uchar>(j, i) = adaptiveProcessKernel(bgr[2], j, i, minSize, maxSize);
}
}
cv::merge(bgr, dst);
return dst;
}