图像处理之频率域应用案例(C++)

图像处理之频率域应用案例(C++)



前言

本文主要介绍几个比较典型的图像从空间域转换到频率域的案例。


一、原理

频率特征是图像的灰度变化特征。一个重要的经验结论:低频代表图像整体轮廓,高频代表了图像噪声,中频代表图像边缘、纹理等细节。因此,我们可以设计不同的滤波器对频率域图像进行滤波,从而实现我们想获得的频率特征。
注意:
1.在做傅里叶变换(FFT)时,通常只使用灰度图像数据,所以需要将彩色图像数据转换为灰度图像数据。同时灰度图像数据作为傅里叶变换复数单元的实数部分,虚数部分直接将值设置为0即可。
2.变换到频域后的数据,低频中心(直流分量)分散在uv坐标系图像的四个角落上,为了方便后续频域处理,通常需要将低频中心位置偏移到uv坐标系图像的中心,需要做一个位置变换处理,然后进行频域滤波,滤波完成再将低频中心重新偏移到四个角落上做IFFT变换。

二、代码实现

1.案例介绍

在复杂背景却又有一些纹理背景中,想要检测出缺陷(位于中心处),在空间域可能比较难以直接检测,可以转换到频率域,设计相应的滤波器,最后再转换到空间域进行后处理。
复杂背景的缺陷识别

2.代码实现

#include <iostream>
#include <opencv.hpp>
using namespace std;

class Filter
{
public:
	Filter(){ }
	virtual cv::Mat getFilter()=0;	//获得不同的滤波器矩阵
	virtual ~Filter() { }
};

class idealLowPassFilter :public Filter	//理想低通滤波器
{
	int h, w;
	double D0;
public:
	idealLowPassFilter(int H, int W, double d0) : h(H), w(W), D0(d0)
	{
		
	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for(int i=0;i<h;i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				if (D > D0 * D0)
					filter.at<float>(i, j) = 0;
				else
					filter.at<float>(i, j) = 1;
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};

class idealHighPassFilter :public Filter	//理想高通滤波器
{
	int h, w;
	double D0;
public:
	idealHighPassFilter(int H, int W, double d0) : h(H), w(W), D0(d0)
	{

	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				if (D > D0 * D0)
					filter.at<float>(i, j) = 1;
				else
					filter.at<float>(i, j) = 0;
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};

class GaussLowPassFilter :public Filter	//高斯低通滤波器
{
	int h, w;
	double D0;
public:
	GaussLowPassFilter(int H, int W, double d0) :h(H), w(W), D0(d0)
	{

	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				filter.at<float>(i, j) = exp(-1 * D / (2 * D0 * D0));
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};

class GaussHighPassFilter :public Filter	//高斯高通滤波器
{
	int h, w;
	double D0;
public:
	GaussHighPassFilter(int H, int W, double d0) :h(H), w(W), D0(d0)
	{

	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				filter.at<float>(i, j) = 1-exp(-1*D/(2*D0*D0));
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};



class ButterworthLowPassFilter :public Filter	//巴特沃斯低通滤波器
{
	int h, w;
	double D0;	//截止频率
	int n;		//阶数
public:
	ButterworthLowPassFilter(int H, int W, double d0, int N):h(H),w(W),D0(d0), n(N)
	{

	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				filter.at<float>(i, j) = 1/(pow(D / (D0 * D0),n)+1);
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};

class ButterworthHighPassFilter :public Filter	//巴特沃斯高通滤波器
{
	int h, w;
	double D0;	//截止频率
	int n;		//阶数
public:
	ButterworthHighPassFilter(int H, int W, double d0,int N) :h(H), w(W), D0(d0),n(N)
	{

	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				filter.at<float>(i, j) = 1 / (pow((D0 * D0)/D, n) + 1);
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};

//自定义滤波器
class myPassFilter :public Filter	//理想高通滤波器
{
	int h, w;
	double D0;
public:
	myPassFilter(int H, int W, double d0) : h(H), w(W), D0(d0)
	{

	}
	//h,w--为图像的长宽、D0为带通半径
	cv::Mat getFilter()
	{
		//1. 计算频谱中心
		int cx = w / 2;
		int cy = h / 2;

		//2. 构建滤波器
		cv::Mat filter(cv::Size(w, h), CV_32FC1);
		for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				double D = pow(i - cy, 2) + pow(j - cx, 2);
				if (D > D0 * D0)
					filter.at<float>(i, j) = 1;
				else
					filter.at<float>(i, j) = 0.5;
			}

		//3. 中心化
		cv::Mat temp = filter.clone();
		temp(cv::Rect(0, 0, cx, cy)).copyTo(filter(cv::Rect(cx, cy, cx, cy)));//左上到右下
		temp(cv::Rect(0, cy, cx, cy)).copyTo(filter(cv::Rect(cx, 0, cx, cy)));//左下到右上
		temp(cv::Rect(cx, 0, cx, cy)).copyTo(filter(cv::Rect(0, cy, cx, cy)));//右上到左下
		temp(cv::Rect(cx, cy, cx, cy)).copyTo(filter(cv::Rect(0, 0, cx, cy)));//右下到左上
		return filter;
	}
};

/*
* @param cv::Mat src	输入图片,单通道灰度图像
* @param cv::Mat dst	输出图片
* @brief 空间域转换到频率域,进行频率域的滤波,然后再返回空间域分析变化
*/
void Spatial2Frequency(const cv::Mat& src, cv::Mat& dst)
{
	//1. 获得dft的最优尺寸
	int h = cv::getOptimalDFTSize(src.rows);
	int w = cv::getOptimalDFTSize(src.cols);

	//2. 对图像进行填充
	cv::Mat padImg;
	cv::copyMakeBorder(src, padImg, 0, h - src.rows, 0, w - src.cols, cv::BORDER_CONSTANT, cv::Scalar(0));

	//3. 创建矩阵存储实数和虚数
	cv::Mat planes[] = { cv::Mat_<float>(padImg),cv::Mat::zeros(padImg.size(),CV_32FC1) };
	cv::Mat dftImg;
	cv::merge(planes, 2, dftImg);

	//4. 执行傅里叶变换,转换到频率域
	cv::dft(dftImg, dftImg);

	//5. 构建不同的滤波器
	double D0 = 10;	//带宽
	//要获得不同的滤波器,只需要修改此处的类即可。
	//Filter* filter = new idealLowPassFilter(h,w,D0);		//理想低通滤波器
	//Filter* filter = new idealHighPassFilter(h,w,D0);		//理想高通滤波器
	//Filter* filter = new GaussLowPassFilter(h, w, D0);			//高斯低通滤波器
	//Filter* filter = new GaussHighPassFilter(h, w, D0);		//高斯高通滤波器
	//Filter* filter = new ButterworthLowPassFilter(h, w, D0,1);		//巴特沃斯低通滤波器
	//Filter* filter = new ButterworthHighPassFilter(h, w, D0, 1);		//巴特沃斯高通滤波器
	Filter* filter = new myPassFilter(h, w, D0);				//自定义滤波器

	cv::Mat PassFilter=filter->getFilter().clone();

	//6. 将滤波器放到一个两通道的Mat矩阵中
	cv::Mat filterPlanes[] = { cv::Mat_<float>(PassFilter),cv::Mat::zeros(PassFilter.size(),CV_32FC1) };
	cv::merge(filterPlanes, 2,PassFilter);

	//7. 相应的频谱进行滤波
	cv::mulSpectrums(dftImg, PassFilter, dftImg,0);

	//8. 反变换回空间域
	cv::Mat spatial;
	std::vector<cv::Mat> channels;
	cv::idft(dftImg, dftImg,cv::DFT_SCALE);
	cv::split(dftImg, channels);
	cv::magnitude(channels[0], channels[1], spatial);

	//9. 归一化
	cv::normalize(spatial, spatial, 0, 255, cv::NORM_MINMAX, CV_8UC1);

	spatial(cv::Rect(0, 0, src.cols, src.rows)).copyTo(dst);
	//cv::imshow("dst", dst);

	//释放指针
	delete filter;
}


/*
* @param cv::Mat src	输入图片,单通道灰度图像
* @param cv::Mat dst	输出图片,三通道的结果图像
* @brief 后处理函数
*/
void postProcess(cv::Mat& src, cv::Mat& dst)
{
	//通过观察图片,发现缺陷一半白,一半黑,采用阈值处理,然后膨胀再采用与操作,提取相同区域
	cv::Mat light, dark;
	cv::threshold(src, dark, 10, 255, cv::THRESH_BINARY_INV);
	cv::threshold(src, light, 230, 255, cv::THRESH_BINARY);
	cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 7));
	cv::dilate(dark, dark, kernel);
	cv::dilate(light, light, kernel);
	cv::bitwise_and(light, dark, src);
	//cv::imshow("dst_1", src);

	//绘制轮廓
	std::vector<std::vector<cv::Point>> contours;
	std::vector<cv::Vec4i> hierarchy;
	cv::findContours(src, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
	for (int i = 0; i < contours.size(); i++)
	{
		cv::Rect rect = cv::boundingRect(contours[i]);
		cv::rectangle(dst, cv::Rect(rect.x, rect.y, 10, 10), cv::Scalar(0, 0, 255));
	}
}


int main()
{
	//读取图片
	string filepath = "F://work_study//algorithm_demo//hard_blob.bmp";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		std::cout << "imread error" << std::endl;
		return -1;
	}

	cv::Mat dst(src.size(), src.type());

	//空间域转换到频率域,设计滤波器进行处理,提取想要的特征
	Spatial2Frequency(src, dst);

	//可视化结果,将单通道灰度图转换为三通道彩色图像
	cv::cvtColor(src, src, cv::COLOR_GRAY2BGR);

	//后处理
	postProcess(dst, src);
	//显示图片
	imwrite("dst.bmp", dst);

	cv::waitKey(0);
	return 0;
}

3.结果展示

检测结果


总结

本文介绍了图像在频率域中的典型应用,并且对滤波器类进行了重构,方便后续读者根据自己的需要进行继承设计自己的滤波器,代码中已经实现了理想高/低通滤波器、高斯高/低通滤波器、巴特沃斯高/低通滤波器。
因为笔者水平有限,有错误欢迎指出,代码本人均在本地运行实验正确,大家放心使用。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
伪彩色算法是一种将灰度图像转换为彩色图像的方法,其中频率方法是一种使用频率滤波器来增强图像对比度的方法,可以用于伪彩色处理。以下是C++实现频率伪彩色算法的基本步骤: 1. 加载灰度图像 2. 对图像进行傅里叶变换 3. 设计一个频率滤波器,例如高斯滤波器、带通滤波器等 4. 将滤波器应用于傅里叶变换后的图像 5. 对处理后的图像进行反傅里叶变换得到彩色图像 下面是一份示例代码,演示了如何使用OpenCV库实现基于频率滤波器的伪彩色算法。 ```c++ #include <opencv2/opencv.hpp> #include <cmath> using namespace cv; using namespace std; int main(int argc, char** argv) { // Load grayscale image Mat gray = imread("lena.jpg", IMREAD_GRAYSCALE); // Get optimal DFT size int dftSize = getOptimalDFTSize(gray.rows); // Add zero padding to image Mat padded; copyMakeBorder(gray, padded, 0, dftSize - gray.rows, 0, dftSize - gray.cols, BORDER_CONSTANT, Scalar::all(0)); // Create complex matrix for DFT Mat complexI; padded.convertTo(complexI, CV_32FC1); Mat planes[] = { Mat_<float>(complexI), Mat::zeros(complexI.size(), CV_32FC1) }; Mat complexImg; merge(planes, 2, complexImg); // Perform DFT dft(complexImg, complexImg); // Create filter Mat filter = Mat::zeros(dftSize, dftSize, CV_32FC1); float cx = dftSize / 2; float cy = dftSize / 2; float radius = dftSize / 4; for (int i = 0; i < dftSize; i++) { for (int j = 0; j < dftSize; j++) { float distance = sqrt(pow(i - cx, 2) + pow(j - cy, 2)); if (distance <= radius) { filter.at<float>(i, j) = 1; } } } // Apply filter Mat planes2[] = { Mat::zeros(complexImg.size(), CV_32FC1), Mat::zeros(complexImg.size(), CV_32FC1) }; split(complexImg, planes2); multiply(planes2[0], filter, planes2[0]); multiply(planes2[1], filter, planes2[1]); merge(planes2, 2, complexImg); // Perform inverse DFT Mat invDFT; dft(complexImg, invDFT, DFT_INVERSE | DFT_REAL_OUTPUT); // Convert to 8-bit color image Mat result; invDFT.convertTo(result, CV_8UC1); // Apply color map Mat colorMap; applyColorMap(result, colorMap, COLORMAP_JET); // Display images imshow("Grayscale", gray); imshow("Result", result); imshow("Color Map", colorMap); waitKey(0); return 0; } ``` 在这个示例中,我们首先加载了一张灰度图像,然后对图像进行了傅里叶变换,并设计了一个频率滤波器。我们将滤波器应用于傅里叶变换后的图像,然后对处理后的图像进行反傅里叶变换得到彩色图像。最后,我们使用OpenCV库的applyColorMap函数将图像转换为伪彩色图像。 在实际使用中,您可能需要根据具体应用场景调整滤波器参数和颜色映射。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值