[OpenCV4] 湖南大学数字图像处理实验5

实验5目录

实验内容

运行效果

项目源码

Headers

DigitalGraphicExp5.h

 midFilter.h

randomInt.h 

aveFilter.h 

 addSaltNoise.h

addGaussNoise.h

adaptiveFilter.h 

Sources

DigitalGraphicExp5.cpp

randomInt.cpp

midFilter.cpp

aveFilter.cpp

 addSaltNoise.cpp

addGaussNoise.cpp

 adaptiveFilter.cpp


实验内容

  1. 读入图像,给图像加上不同类别的噪声;
  2. 分别采用均值滤波器、中值滤波器、自适应中值滤波器去除图像噪声;
  3. 分析比较不同滤波器对不同噪声的去除效果。

运行效果

项目组织格式:

原图:

加了椒盐噪声之后的图像:

加了高斯噪声之后的图像:

盐噪声的均值滤波:

高斯噪声的均值滤波:

盐噪声的中值滤波:

高斯噪声的中值滤波:

盐噪声的自适应中值滤波:

高斯噪声的自适应中值滤波:

项目源码

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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值