欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++ Opencv——图像预处理——滤波

程序员文章站 2022-07-13 08:53:47
...
#include <opencv2/opencv.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

/*

边缘突出
	用高通——拉普拉斯
	锐化处理

去噪点
	用低通——均值、中值


偏色问题解决
	用白平衡进行处理

【空域与频域之间是有一定关系。均值滤波器是一种低通滤波;拉普拉斯算子滤波(边缘检测)是一种高通滤波】
*/

class Blur_Class
{
public:	
	/*
	双边滤波——保留纹理的滤波
	三通道图,返回三通道图
	Shuangbian_Bialteral_Filter(src, src);
	*/
	void Shuangbian_Bialteral_Filter(Mat src, Mat dst, int R = 10, double sigmaC = 20, double sigmaS = 20);

	/*
	高分差滤波——类似锐化增加噪声点
	三通道图,返回三通道图
	HighPass(src, dst);
	*/
	void HighPass(Mat src, Mat dst, int r = 3, int k = 3);

	/*
	LOG变换——使整体图片亮度均衡(强度大)
	三通道图,返回三通道图
	log_Filter(src, src);
	*/
	void log_Filter(Mat src, Mat dst);

	/*
	均衡化——一定程度上亮度均衡,增强边缘强度
	输入单通道、三通道
	junheng_equalizeHist(src, src);
	*/
	void junheng_equalizeHist(Mat src, Mat dst);

	/*
	中值滤波——可以去除多个零散密集的噪声点
	输入单通道、三通道图
	zhongzhi_Median_Filter(src, src);
	*/
	void zhongzhi_Median_Filter(Mat src, Mat dst, int k = 10);

	/*
	膨胀腐蚀——默认膨胀
	输入单通道、三通道
	PF_Filter(src, dst);
	*/
	void PF_Filter(Mat src, Mat dst, bool flag = true, int k = 1);

	/*
	自己定义卷积核
	0	-1	0
	-1	5	-1
	0	-1	0
	filter(dst2, dst2)
	*/
	void filter(Mat src, Mat dst, Mat kerne = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0));


public:
	/* RGB分离 */
	void RGB_Split(Mat src, Mat  r = Mat(), Mat g = Mat(), Mat b = Mat(), Mat R = Mat(), Mat G = Mat(), Mat B = Mat());

	/*白平衡*/
	void baipingheng(Mat src, Mat dst);

public:
	/*
	lab
	*/
	void RGB2LAB(Mat& rgb, Mat& Lab);

	/*
	偏色检验
	*/
	float colorCheck(const Mat& imgLab);


};








/*——————————————————————————————————————————————————————————————*/

/*
双边滤波——保留纹理的滤波
三通道图,返回三通道图
Shuangbian_Bialteral_Filter(src, src);
*/
void Blur_Class::Shuangbian_Bialteral_Filter(Mat src, Mat dst, int R, double sigmaC, double sigmaS)
{
	Mat dst_;
	bilateralFilter(src, dst_, R, sigmaC, sigmaS);
	dst_.copyTo(dst);
}

/*
高反差滤波——类似锐化增加噪声点——叠加边缘后的效果图 = 原图 + r*(原图-滤波)
三通道图,返回三通道图
HighPass(src, dst);
*/
void Blur_Class::HighPass(Mat src, Mat dst, int r, int k)
{
	Mat temp;
	int n = 2 * k + 1;
	Size ksize = Size(n, n);
	GaussianBlur(src, temp, ksize, 1.6, 1.6);
	Mat diff = src + r*(src - temp); //高反差保留算法
	diff.copyTo(dst);
}

/*
LOG变换——使整体图片亮度均衡(强度大)
三通道图,返回三通道图
log_Filter(src, src);
*/
void Blur_Class::log_Filter(Mat src, Mat dst)
{
	Mat imageLog(src.size(), CV_32FC3);
	for (int i = 0; i < src.rows; i++)
	{
		for (int j = 0; j < src.cols; j++)
		{
			imageLog.at<Vec3f>(i, j)[0] = log(1 + src.at<Vec3b>(i, j)[0]);
			imageLog.at<Vec3f>(i, j)[1] = log(1 + src.at<Vec3b>(i, j)[1]);
			imageLog.at<Vec3f>(i, j)[2] = log(1 + src.at<Vec3b>(i, j)[2]);
		}
	}
	//归一化到0~255  
	normalize(imageLog, imageLog, 0, 255, CV_MINMAX);
	//转换成8bit图像显示  
	convertScaleAbs(imageLog, imageLog);
	imageLog.copyTo(dst);
}

/*
均衡化——一定程度上亮度均衡,增强边缘强度
输入单通道、三通道
junheng_equalizeHist(src, src);
*/
void Blur_Class::junheng_equalizeHist(Mat src, Mat dst)
{
	if (src.channels() == 3)
	{
		dst.create(src.size(), src.type());
		Mat imageRGB[3];
		split(src, imageRGB);
		for (int i = 0; i < 3; i++)
		{
			equalizeHist(imageRGB[i], imageRGB[i]);
		}
		merge(imageRGB, 3, dst);
	}
	else if (src.channels() == 1)
	{
		dst.create(src.size(), src.type());
		equalizeHist(src, dst);
	}
}

/*
中值滤波——可以去除多个零散密集的噪声点
输入单通道、三通道图
zhongzhi_Median_Filter(src, src);
*/
void Blur_Class::zhongzhi_Median_Filter(Mat src, Mat dst, int k)
{
	int n = 2 * k + 1;
	dst.create(src.size(), src.type());
	medianBlur(src, dst, n);
}

/*
膨胀腐蚀——默认膨胀
输入单通道、三通道
PF_Filter(src, dst);
*/
void Blur_Class::PF_Filter(Mat src, Mat dst, bool flag, int k)
{
	int n = 2 * k + 1;
	Size Ksize = Size(k, k);
	Mat element = getStructuringElement(MORPH_RECT, Ksize);
	if (flag == true)
	{
		// 进行膨胀操作
		dilate(src, dst, element);
	}
	else
	{
		// 进行腐蚀操作
		erode(src, dst, element);
	}
}

/*
自己定义卷积核
0	-1	0
-1	5	-1
0	-1	0
filter(dst2, dst2)
*/
void Blur_Class::filter(Mat src, Mat dst, Mat kerne)
{
	//Mat kerne = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);                       // 生成一个掩模核 大小为 3x3 , 通过<<  输入到矩阵Mat_<char> 中,然后隐式转换成Mat类型
	dst.create(src.size(), src.type());
	filter2D(src, dst, CV_8UC3, kerne);

}

/*
RGB
分离成r、g、b
合并成R、G、B
*/
void Blur_Class::RGB_Split(Mat src, Mat r, Mat g, Mat b, Mat R, Mat G, Mat B)
{
	Mat imageRGB[3];
	split(src, imageRGB);
	r.create(src.size(), src.type());
	g.create(src.size(), src.type());
	b.create(src.size(), src.type());
	b = imageRGB[0];
	g = imageRGB[1];
	r = imageRGB[2];
		
	Mat black = Mat::zeros(Size(src.cols, src.rows), CV_8UC1);

	vector<Mat> channels_r;
	channels_r.push_back(black);
	channels_r.push_back(black);
	channels_r.push_back(r);		
	merge(channels_r, R);

	vector<Mat> channels_g;
	channels_g.push_back(black);
	channels_g.push_back(g);
	channels_g.push_back(black);
	merge(channels_g, G);

	vector<Mat> channels_b;
	channels_b.push_back(b);
	channels_b.push_back(black);
	channels_b.push_back(black);
	merge(channels_b, B);
}

/*
白平衡
*/
void Blur_Class::baipingheng(Mat src, Mat dst)
{
	vector<Mat> imageRGB;
	split(src, imageRGB);

	//求原始图像的RGB分量的均值
	double R, G, B;
	B = mean(imageRGB[0])[0];
	G = mean(imageRGB[1])[0];
	R = mean(imageRGB[2])[0];

	//需要调整的RGB分量的增益
	double KR, KG, KB;
	KB = (R + G + B) / (3 * B);
	KG = (R + G + B) / (3 * G);
	KR = (R + G + B) / (3 * R);

	//调整RGB三个通道各自的值
	imageRGB[0] = imageRGB[0] * KB;
	imageRGB[1] = imageRGB[1] * KG;
	imageRGB[2] = imageRGB[2] * KR;

	//RGB三通道图像合并
	dst.create(src.size(), src.type());
	merge(imageRGB, dst);
	namedWindow("白平衡调整后", 0);
	imshow("白平衡调整后", dst);
	waitKey();

}



/*转换成lab*/
void Blur_Class::RGB2LAB(Mat& rgb, Mat& Lab)
{
	Mat XYZ(rgb.size(), rgb.type());
	Mat_<Vec3b>::iterator begainRGB = rgb.begin<Vec3b>();
	Mat_<Vec3b>::iterator endRGB = rgb.end<Vec3b>();
	Mat_<Vec3b>::iterator begainXYZ = XYZ.begin<Vec3b>();
	int shift = 22;
	for (; begainRGB != endRGB; begainRGB++, begainXYZ++)
	{
		(*begainXYZ)[0] = ((*begainRGB)[0] * 199049 + (*begainRGB)[1] * 394494 + (*begainRGB)[2] * 455033 + 524288) >> (shift - 2);
		(*begainXYZ)[1] = ((*begainRGB)[0] * 75675 + (*begainRGB)[1] * 749900 + (*begainRGB)[2] * 223002 + 524288) >> (shift - 2);
		(*begainXYZ)[2] = ((*begainRGB)[0] * 915161 + (*begainRGB)[1] * 114795 + (*begainRGB)[2] * 18621 + 524288) >> (shift - 2);
	}

	int LabTab[1024];
	for (int i = 0; i < 1024; i++)
	{
		if (i>9)
			LabTab[i] = (int)(pow((float)i / 1020, 1.0F / 3) * (1 << shift) + 0.5);
		else
			LabTab[i] = (int)((29 * 29.0 * i / (6 * 6 * 3 * 1020) + 4.0 / 29) * (1 << shift) + 0.5);
	}
	const int ScaleLC = (int)(16 * 2.55 * (1 << shift) + 0.5);
	const int ScaleLT = (int)(116 * 2.55 + 0.5);
	const int HalfShiftValue = 524288;
	begainXYZ = XYZ.begin<Vec3b>();
	Mat_<Vec3b>::iterator endXYZ = XYZ.end<Vec3b>();
	Lab.create(rgb.size(), rgb.type());
	Mat_<Vec3b>::iterator begainLab = Lab.begin<Vec3b>();
	for (; begainXYZ != endXYZ; begainXYZ++, begainLab++)
	{
		int X = LabTab[(*begainXYZ)[0]];
		int Y = LabTab[(*begainXYZ)[1]];
		int Z = LabTab[(*begainXYZ)[2]];
		int L = ((ScaleLT * Y - ScaleLC + HalfShiftValue) >> shift);
		int A = ((500 * (X - Y) + HalfShiftValue) >> shift) + 128;
		int B = ((200 * (Y - Z) + HalfShiftValue) >> shift) + 128;
		(*begainLab)[0] = L;
		(*begainLab)[1] = A;
		(*begainLab)[2] = B;
	}
}
/*偏色检测*/
float Blur_Class::colorCheck(const Mat& imgLab)
{
	Mat_<Vec3b>::const_iterator begainIt = imgLab.begin<Vec3b>();
	Mat_<Vec3b>::const_iterator endIt = imgLab.end<Vec3b>();
	float aSum = 0;
	float bSum = 0;
	for (; begainIt != endIt; begainIt++)
	{
		aSum += (*begainIt)[1];
		bSum += (*begainIt)[2];
	}
	int MN = imgLab.cols*imgLab.rows;
	double Da = aSum / MN - 128; // 必须归一化到[-128,,127]范围内    
	double Db = bSum / MN - 128;

	//平均色度
	double D = sqrt(Da*Da + Db*Db);

	begainIt = imgLab.begin<Vec3b>();
	double Ma = 0;
	double Mb = 0;
	for (; begainIt != endIt; begainIt++)
	{
		Ma += abs((*begainIt)[1] - 128 - Da);
		Mb += abs((*begainIt)[2] - 128 - Db);
	}
	Ma = Ma / MN;
	Mb = Mb / MN;
	//色度中心距
	double M = sqrt(Ma*Ma + Mb*Mb);
	//偏色因子
	float K = (float)(D / M);
	cout << "K=" << K << endl;
	return K;
}