Application of Fourier Transform in Image Processing

Fundamental

Discrete Fourier transform (Discrete Fourier reansform, abbreviated as DFT) means that the Fourier transform presents a discrete form in both the time domain and the frequency domain. domain sampling. To put it simply, doing a Fourier transform on an image is to decompose it into sin and cos, that is, to convert the image from the spatial domain to the frequency domian. You can use Euler's formula for conversion, as shown in the figure:
insert image description here
the conversion result F(u,v) is a complex number, including real and imaginary parts: the
insert image description here
magnitude image contains almost all the geometric information we need, generally we only need to use Amplitude image. If you want to modify the original image through Fourier transform, you can modify the magnitude image first, and then inversely transform the magnitude image and phase image to obtain the result image.
insert image description here
But the dynamic range of the Fourier coefficients is too large to be displayed on the screen. For visualization using grayscale values, we can convert the magnitude plot on a linear scale to a logarithmic scale:
M1=log(1+M)

API of Fourier transform in opencv:

void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0); 

From the formula (1) can get:
insert image description here

Therefore, the inverse Fourier transform can also be performed using the dft() function.

Applications in image processing

Fourier transform has many functions in image processing. Because not only Fourier analysis involves many aspects of image processing, but Fourier's improved algorithms, such as discrete cosine transform, gabor and wavelet, also have important components in image processing. Fourier transform is applied in the following aspects:
insert image description here
The following is the implementation of the application of Fourier transform in the image rotation direction, which is divided into 4 steps:
(1) Perform DFT transformation on the original image to obtain the complex number F(u ,v);
(2) Synthesize the magnitude map from the real part and the imaginary part, and perform M1=log(1+M) conversion; (3
) Rearrange the 4 quadrants of the magnitude map so that the origin is at the center of the image, The high frequency is in the corner, and the amplitude is converted to [0, 255]
(4) Use the Hough transform to find the straight line, calculate the rotation angle, and rotate the image

The implementation code is as follows:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <ctime>
#include "math.h"

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    
    
	//以单通道(灰度)方式读取图像
	const char* filename = "../data/blue.jpg";
	Mat srcImg = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
	if (srcImg.empty())
		return -1;

	Point center(srcImg.cols / 2, srcImg.rows / 2);

	clock_t start = clock();
	//将图像扩展到最佳大小,以获得更快的处理速度
	//设置4个方向的边框宽度
	//如果 borderType==BORDER_CONSTANT, 用(0,0,0)填充
	Mat padded;
	int opWidth = getOptimalDFTSize(srcImg.rows);
	int opHeight = getOptimalDFTSize(srcImg.cols);
	copyMakeBorder(srcImg, padded, 0, opWidth - srcImg.rows, 0, opHeight - srcImg.cols, BORDER_CONSTANT, Scalar::all(0));

	Mat planes[] = {
    
     Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
	Mat comImg;
	//合并成一个双通道图像
	merge(planes, 2, comImg);

	//傅里叶变换
	dft(comImg, comImg);

	//计算幅值
	//复数形式:planes[0]=Re(DFT(I)), planes[1]=Im(DFT(I)), magnitude=sqrt(Re^2+Im^2)
	split(comImg, planes);
	magnitude(planes[0], planes[1], planes[0]);

	//转换到log的尺度下,从而能观察到图像(否则数据过界)
	//M2=log(1+M1)
	Mat magMat = planes[0];
	magMat += Scalar::all(1);
	log(magMat, magMat);

	//剪切和重分布幅度图象限

	//若有奇数行或奇数列,进行裁剪
	magMat = magMat(Rect(0, 0, magMat.cols & -2, magMat.rows & -2));

	//重新排布傅里叶图像的4个象限,使原点位于图像中心,高频在角落
	int cx = magMat.cols / 2;
	int cy = magMat.rows / 2;

	Mat q0(magMat, Rect(0, 0, cx, cy));
	Mat q1(magMat, Rect(0, cy, cx, cy));
	Mat q2(magMat, Rect(cx, cy, cx, cy));
	Mat q3(magMat, Rect(cx, 0, cx, cy));

	//交换象限
	Mat tmp;
	q0.copyTo(tmp);
	q2.copyTo(q0);
	tmp.copyTo(q2);

	q1.copyTo(tmp);
	q3.copyTo(q1);
	tmp.copyTo(q3);

	//将幅度标准化至 [0,1], 再转为[0,255]
	normalize(magMat, magMat, 0, 1, CV_MINMAX);
	Mat magImg(magMat.size(), CV_8UC1);
	magMat.convertTo(magImg, CV_8UC1, 255, 0);   // 像素值*255+0

	//以下部分是对频谱图像进行霍夫直线变换,找到角度值,利用该角度值对原图像进行旋转,多适用于文字图像

	//转为二值图像
	threshold(magImg, magImg, 150, 255, CV_THRESH_BINARY);

	//旋转原图
	//使用霍夫变换查找直线
	vector<Vec2f> lines;
	float pi180 = (float)CV_PI / 180;
	Mat linImg(magImg.size(), CV_8UC3);
	HoughLines(magImg, lines, 1, pi180, 500, 0, 0);
	int numLines = lines.size();
	for (int l = 0; l < numLines; l++)
	{
    
    
		float rho = lines[l][0], theta = lines[l][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		line(linImg, pt1, pt2, Scalar(255, 0, 0), 1, 8, 0);
	}

	//imwrite("imageText_line.jpg",linImg);
	if (lines.size() == 3) {
    
    
		cout << "found three angels:" << endl;
		cout << lines[0][1] * 180 / CV_PI << endl << lines[1][1] * 180 / CV_PI << endl << lines[2][1] * 180 / CV_PI << endl << endl;
	}

	//Find the proper angel from the three found angels
	float angel = 0;
	float piThresh = (float)CV_PI / 90;
	float pi2 = CV_PI / 2;
	for (int l = 0; l < numLines; l++)
	{
    
    
		float theta = lines[l][1];
		if (abs(theta) < piThresh || abs(theta - pi2) < piThresh)
			continue;
		else {
    
    
			angel = theta;
			break;
		}
	}

	//计算旋转角度
	//如果图像不是方的,旋转后可能会达不到预期效果
	angel = angel < pi2 ? angel : angel - CV_PI;
	if (angel != pi2) {
    
    
		float angelT = srcImg.rows * tan(angel) / srcImg.cols;
		angel = atan(angelT);
	}
	float angelD = angel * 180 / (float)CV_PI;
	cout << "the rotation angel to be applied:" << endl << angelD << endl << endl;

	clock_t end = clock();
	cout << "花费了" << (double)(end - start) / CLOCKS_PER_SEC << "秒" << endl;

	//旋转图像
	Mat rotMat = getRotationMatrix2D(center, angelD, 1.0);
	Mat dstImg = Mat::ones(srcImg.size(), CV_8UC3);
	warpAffine(srcImg, dstImg, rotMat, srcImg.size(), 1, 0, Scalar(0, 0, 0));

	return 0;
}

The implementation results are shown in the figure below:
insert image description here
This article only implements the application of Fourier transform in the image rotation direction, and will implement examples in several other fields in the future. For the use of related functions in the code, not much research has been done in the implementation of image rotation. If necessary, I will revise this blog post for introduction in the future.

Reference literature:
OpenCV tutorial
CSDN blog post_01
CSDN blog post_02
very detailed B station tutorial

Guess you like

Origin blog.csdn.net/weixin_38584764/article/details/128136123