图像处理:傅里叶变换

2023-05-16

0 引言

在之前的博客 图像增强傅里叶变换(OpenCV)中都有用到过傅里叶变换,但一直都不是特别理解,现系统地学习一下。先来看一个视频 傅里叶级数与傅立叶变换,我们了解到任何周期函数都可以表示为不同频率的正弦函数和/或余弦函数之和,其中每个正弦函数和/或余弦函数都乘以不同的系数。如何找到是哪些频率组成的该周期函数?可以看一下这篇文章 从傅里叶变换进阶到小波变换。学习傅里叶还是要踏踏实实弄清楚公式和概念,没有捷径,接下来我们来推导公式。

1 傅里叶级数

周期为T的 连续变量t的 周期函数f(t),可表示为乘以适当系数的 正弦函数和余弦函数之和。 这个和就是 傅里叶级数,其形式为

式中,C n 是傅里叶级数

从上式可知, 若要将一个周期信号展开为傅里叶级数形式,实际上就是确定级数,接下来我们讨论如何求出cn

1.1 三角函数正交性

三角函数是周期函数,其在-π到π的积分必定为0,即

由三角函数的积化和差公式,可以继续推导出下列公式

因为三角函数在-π到π内的积分为0,因此当m≠n时上面三个式子必定为0,因此可以得出以下结论, 频率不同的三角函数相乘在一个周期内(-π到π)的积分必定为0

假设一函数f(t)由一个直流分量和若干正余弦函数组成

在上式两边同时乘以sin⁡(kωt),并对它们在一个周期内进行积分,可得

化简得

因此,可得 bn,同理也可得 an

1.2 欧拉公式与傅里叶级数

根据 欧拉公式

当θ=nωt和θ=-nωt时,

将这两项代入傅里叶级数

当n=0时,代入上一小节得到的a0

当n=1,2,3,...时,代入an,bn

当n=-1,-2,-3,...时,代入an,bn

可以看出, 对于任意的n,所有Cn的表达式都是一样的,傅里叶级数最终可以写为:

得证。

2 傅里叶变换 2.1 连续傅里叶变换

傅立叶级数是针对周期函数的,而 傅里叶变换针对非周期函数一个非周期函数可以看做周期无限大的函数。当T趋于无穷大时,频率间隔 ω=2π/T趋于无穷小; Δω=(n+1)ω-nω=ω=2π/T,因此 Δω也趋于0, 1/T=Δω/2π;ΣΔω可以写成积分的形式 ∫dω。我们以 nω为变量,当 ω不等于0时, nω为离散值,,但当 ω趋于无穷小时, nω就变成连续的量 ,令 nω=W。

我们将这个式子中标红的部分称作 函数f(t)的傅里叶变换,记作F(w),即

而原始函数f(t)可以写为

我们称之为 傅里叶反变换

二维连续函数f(x,y)的傅里叶正变换为

相应的傅里叶逆变换公式为

2.2 离散傅里叶变换

实际的信号往往是离散且有限的,在这种受限下要用到 离散傅里叶变换(Discrete Fourier Transform简称DFT)。首先,假设采集了N个信号点,其时间为 t 0 , t 1 , ... , t N-1 ,对应的信号值为 f(t 0 ), f(t 1 ), ... , f(t N-1 ) 。信号连续的时候是积分,现在数据离散了用累加,于是

我们发现,原信号有N个数据点,DFT变换后的信号却变成连续的了,我们将之称为 离散时间傅里叶变换(DISCRETE TIME FOURIER TRANSFORM,简称DTFT)。 DTFT有两个缺点,第一, ω∈(−∞,+∞)且连续, 需要进行无数次计算,计算机无法计算;第二,在进行计算的时候,我们 需要已知 t 0 , t 1 , ... , t N-1 , 和 f(t 0 ), f(t 1 ), ... , f(t N-1 ) ,但是FFT函数只需要已知 f(t 0 ), f(t 1 ), ... , f(t N-1 ) 就可以进行。

我们可以采用相对时间n=0,1,...,N-1来代替真实采样时间 t 0 , t 1 , ... , t N-1 , 可以得到

此时我们发现 F(ω)变成了以 2π为周期的函数,即

我们只需要计算 ω∈(0,2π)区间的 F(ω),就可以得到 ω∈(−∞,+∞)区间的 F(ω)了。也就是说,通过使用相对采样时间 n=0,1,...N−1代替真实采样时间 t 0 , t 1 , ... , t N-1 ,我们将 F(ω)的范围从 (−∞,+∞)缩小到了 (0,2π)。再将 (0,2π)离散化为N个点,这样计算机就可以计算了,取 ω=2πk/N, k=0,1,...N−1,得 离散傅里叶变换DFT

二维离散函数f(x,y)的傅里叶正变换的公式如下:

其中,u=0,1,2,...,M-1;v=0,1,2,...N-1。

相应的 傅里叶逆变换的公式如下:

其中,x=0,1,2,...,M-1;y=0,1,2,...N-1。

一维信号是一个序列,傅里叶变换将其分解成若干个一维的简单函数之和。二维信号可以说是一个图像, 二维傅里叶变换 将图像分解成若干个复平面波之和。通过上面的公式,我们可以计算出,每个平面波在图像重的成分是多少。从公式也可以看出,二维傅里叶变换就是将图像与每个不同频率的不同方向的复平面波做内积(先再求和),也就是一个求在基上投影的过程。 一维的正弦波可以通过三个参数确定,频率ω,幅度A和相位φ。因此在频域中,一维坐标表示频率,每个坐标对应的函数值F(ω)是一个复数,它的模|F(w)|就是幅度A,幅角∠F(w)就是相位。而二维正弦平面波需要四个参数,其中三个和一维一样( 频率ω ,幅度A 和相位φ ),令一个是 方向n。如下图所示,两个平面波仅在方向参数上不同:

如何存储频率ω ,幅度A,相位φ和方向n这些参数呢?和一维一样, 幅度和 相位可以用一个 复数表示,复数的模是幅度,幅角是相位 。向量有方向和长度,可以用来表示方向和频率。一个向量n=(u,v),向量的模√u2+v2代表这个平面波的频率,方向是平面波的方向,在该点的值F(u,v)表示幅度和相位。包含所有(u,v)点的矩阵是K空间,如下图所示

上图中,频谱图的中心为原点,即u=0,v=0,中间区域为低频,频率低周期大,条纹间隔宽,从中间向外,频率增大,平面波周期减小,条纹间隔小。图像区域灰度越高表示该频率平面波在图像中成分越多,由于低频表示图像灰度平稳区域,高频表示细节和边缘,所以图像主要是低频,频谱图中间灰度较高。在不同象限的点所代表的平面波方向不同。链接中有很多 图像的二维傅里叶变换频谱图,可以验证下自己弄懂了没。

3 应用

二维离散傅里叶变换(Two-Dimensional Discrete Fourier Transform)是一种数字变换方法,一般应用于 将图像从 空间域转至 频域,在 图像增强图像去噪图像边缘检测图像特征提取图像压缩等等应用中都起着极其重要的作用。

3.1 频域滤波

图像实质上是二维矩阵。将空间域(二维灰度数表)的图像转换到频域(频率数表)能够更直观地观察和处理图像,也更有利于进行频域滤波等操作。在博客 图像增强中介绍了不少常用的低通滤波器,也在博客 傅里叶变换中介绍过OpenCV中傅里叶变换的写法。接下来的这个示例和之前的写法有些不同。

示例 频域滤波

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

#include <opencv2/opencv.hpp>

using namespace cv;

using namespace std;

int main {

clock_t start = clock ;

Mat src = imread( "E:/C++projects/CH11/CH11/5.png" , 0);

imshow( "src" , src);

// 填充到傅里叶变换最佳尺寸 (gpu下加速明显)

int h = getOptimalDFTSize(src.rows);

int w = getOptimalDFTSize(src.cols);

Mat padded;

copyMakeBorder(src, padded, 0, h - src.rows, 0, w - src.cols, BORDER_CONSTANT, Scalar::all(0));

Mat pMat = Mat(padded.size, CV_32FC1);

// 中心化 (在时域做中心化,傅里叶变换后的频谱图低频在中心)

for ( int i = 0; i < padded.rows; i++)

{

for ( int j = 0; j < padded.cols; j++)

{

pMat.at< float >(i, j) = pow (-1, i + j) * padded.at<uchar>(i, j);

}

}

// 傅里叶变换

Mat planes[] = { pMat, Mat::zeros(padded.size, CV_32F) };

Mat complexImg;

merge(planes, 2, complexImg);

dft(complexImg, complexImg, DFT_COMPLEX_OUTPUT);

// 显示频谱图

split(complexImg, planes);

Mat magMat;

magnitude(planes[0], planes[1], magMat);

magMat += 1;

log (magMat, magMat);

normalize(magMat, magMat, 0, 255, NORM_MINMAX);

magMat.convertTo(magMat, CV_8UC1);

// 低通滤波

//Mat mask(Size(w, h), CV_32FC2, Scalar(0, 0));

//circle(mask, Point(w / 2, h / 2), 50, Scalar(255, 255), -1);

//complexImg = complexImg.mul(mask);

//高通滤波

Mat mask(Size(w, h), CV_32FC2, Scalar(255, 255));

circle(mask, Point(w / 2, h / 2), 50, Scalar(0, 0), -1);

complexImg = complexImg.mul(mask);

// 傅里叶反变换

Mat dst, tmp;

idft(complexImg, tmp, DFT_REAL_OUTPUT);

// 去中心化

for ( int i = 0; i < padded.rows; i++)

{

for ( int j = 0; j < padded.cols; j++)

{

pMat.at< float >(i, j) = pow (-1, i + j) * tmp.at< float >(i, j);

}

}

dst = pMat({ 0,0,src.cols ,src.rows }).clone;

normalize(dst, dst, 0, 1, NORM_MINMAX);

dst.convertTo(dst, CV_8U, 255);

imshow( "dst" , dst);

clock_t end = clock ;

cout << "spend time:" << end - start << "ms" << endl;

waitKey(0);

return 0;

}

不知道有没有人发现,是中心化的方法不一样。之前是在频域做的中心化,这次是在时域做中心化→傅里叶变换→滤波→傅里叶逆变换→去中心化。这是傅里叶变换的平移性质,在第4节会详细讲解下。

3.2 加速滤波计算

用大小为m×n元素的核对大小为M×N的图像进行滤波时,需要的运算次数为MNmn(乘法和加法)。如果核是可分离的,那么运算次数可减少为MN(m+n)。在频率域中执行等效滤波所需要的运算次数仅为2MNlog2MN,前面的系数2表示我们要计算一次正FFT和一次反FFT。

为说明频率域滤波相对于空间滤波的计算优势,我们分别考虑大小为M×M的方形图像与m×m的核。采用不可分离的核所需的运算次数为M 2 m 2 ,采用可分离的核所需的运算次数为2M 2 m,而采用FFT对这种图像滤波所需的运算次数为2M 2 log 2 M 2 ,定义FFT方法的计算优势为

两种情况下,当C(m)>1时,FFT方法的计算优势更大(根据计算次数);而当C(m)≤1时,空间滤波的优势更大。下图显示了中等大小图像(M=2048)的Cn(m)与m的曲线关系。对于7×7或更大的核,FFT具有计算优势。这一优势随着m的增大而迅速增大,例如m=101时计算优势超过200,而m=201时计算优势接近1000.下面说明这一优势的含义。如果用FFT对大小为2048×2048的一组图像进行滤波需要1分钟,那么用大小为201×201元素的不可分离核对同一组图像滤波要17小时。这一差异非常明显,因此清楚地表明了使用FFT进行频率域处理的重要性。

3.3 倾斜文本校正

对于分行的文本,其频率谱上一定会有一定的特征,当图像旋转时,其频谱也会同步旋转,因此找出这个特征的倾角,就可以将图像旋转校正回去。这是 二维傅里叶变换的旋转性质,傅里叶变换对

使用极坐标

可得到如下变换对

它指出,若f(x,y)旋转 θ 0 角度,则F(u,v)也旋转相同的角度。反之,若F(u,v)旋转某个角度,f(x,y)也旋转相同的角度。

示例 倾斜文本校正

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

#include <opencv2/opencv.hpp>

using namespace cv;

using namespace std;

double point2Line(Point2f pointP, Point2f pointA, Point2f pointB)

{

//求直线方程

double A = 0, B = 0, C = 0;

A = pointA.y - pointB.y;

B = pointB.x - pointA.x;

C = pointA.x * pointB.y - pointA.y * pointB.x;

//代入点到直线距离公式

double distance = 0;

double tmp1 = abs (A * pointP.x + B * pointP.y + C);

double tmp2 = (( float )sqrtf(A * A + B * B));

distance = tmp1 / tmp2;

return distance;

}

int main {

vector<string> filenames;

glob( "./" , filenames);

for ( int n = 0; n < filenames.size; n++) {

string filename = filenames[n];

Mat src = imread(filename, 0);

// 填充到傅里叶变换的最佳尺寸

int h = getOptimalDFTSize(src.rows);

int w = getOptimalDFTSize(src.cols);

Mat padded;

copyMakeBorder(src, padded, 0, h - src.rows, 0, w - src.cols, BORDER_CONSTANT, Scalar::all(0));

// 傅里叶变换

Mat planes[] = { Mat_< float >(padded), Mat::zeros(padded.size, CV_32F) };

Mat complexImg;

merge(planes, 2, complexImg);

dft(complexImg, complexImg, DFT_COMPLEX_INPUT | DFT_COMPLEX_OUTPUT);

// 求幅值

split(complexImg, planes);

Mat magMat;

magnitude(planes[0], planes[1], magMat);

magMat += 1;

log (magMat, magMat);

normalize(magMat, magMat, 0, 255, NORM_MINMAX);

magMat.convertTo(magMat, CV_8UC1);

// 把零频移到中心

Mat magImg = magMat.clone;

int cx = magImg.cols / 2;

int cy = magImg.rows / 2;

Mat q1 = magImg({ 0, 0, cx, cy });

Mat q2 = magImg({ 0, cy, cx, cy });

Mat q3 = magImg({ cx, 0, cx, cy });

Mat q4 = magImg({ cx, cy, cx, cy });

Mat temp;

q1.copyTo(temp);

q4.copyTo(q1);

temp.copyTo(q4);

q2.copyTo(temp);

q3.copyTo(q2);

temp.copyTo(q3);

// 霍夫直线检测有角度的斜线

Mat binImg;

threshold(magImg, binImg, 150, 255, THRESH_BINARY);

Mat markImg;

cvtColor(binImg, markImg, COLOR_GRAY2BGR);

vector<Vec4i> lines;

Vec4i l;

HoughLinesP(binImg, lines, 1, CV_PI / 180.0, 30, 200, 50);

Point2f p = Point2f(magImg.cols / 2.0, magImg.rows / 2.0);

for ( int i = 0; i < lines.size; i++)

{

if ( abs (lines[i][1] - lines[i][3]) > 15) {

line(markImg, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 255, 0), 1, 8, 0);

l = lines[i];

}

}

float theta = atan ((l[1] - l[3]) * 1.0 / (l[0] - l[2]) * src.cols / src.rows) * 180 / CV_PI;

float angle = theta <= 0 ? theta + 90 : theta - 90;

// 放射变换

Point2f center = Point2f(src.cols / 2.0, src.rows / 2.0);

Mat rotMat = getRotationMatrix2D(center, angle, 1.0);

Mat dst = Mat::ones(src.size, CV_8UC1);

warpAffine(src, dst, rotMat, src.size, 1, 0, Scalar(255, 255, 255));

imshow( "src" , src);

imshow( "markImg" , markImg);

imshow( "dst" , dst);

waitKey(0);

}

return 0;

}

4 Q&A Q: 为什么要中心化?如何中心化?

直接对数字图像进行二维DFT变换得到的频谱图是高频在中间,低频在四角。为了把能量(在低频)集中起来便于使用滤波器,可以利用 二维DFT的平移性质对频谱进行中心化。频谱图比较亮的地方是低频,图像的能量一般都是集中在低频部分。中心化不是必须的,主要是为了方便理解和滤波。

根据 二维傅里叶的平移性质,用<=>表示函数和其傅里叶变换的对应性

第一个公式表明,将f(x,y)与一个指数项相乘就相当于把其变换后的频域中心移动到新的位置。第二个公式表明将F(u,v)与一个指数项相乘就相当于把其变换后的空域中心移到新的位置,同时可以看出对f(x,y)的平移不会影响其傅里叶变换的幅值。将u0=M/2和v0=N/2代入第一个公式,指数部分就变为

代入上面的公式

也就是说,对数字图像的每个像素点的取值直接乘以(-1)^(x+y),x和y是像素坐标。这之后再做傅里叶变换,最后即为中心化后的傅里叶变换。和在频域移动M/2和N/2一样的效果。

Q: 为什么用图像二维傅里叶变换的相位谱进行反变换,能够大致得到原图的形状,而幅度谱则不行呢?

k空间中储存的是一个复数,其幅度代表平面波的波动的大小,相位代表平面波的相位也就是偏离原点的多少。从k空间回复图像的时候,是将每个复平面乘上对应的复系数,相加而成。可以分为两步:(1)乘上波动大小(幅度)(2)移动相应的距离(相位)

示例 谱和相角对图像信息的贡献

只用相角重建男孩图像,就是令|F(u,v)|=1,可以看出,图像丢失了灰度信息,但有形状特征。只使用谱重建,这意味着指数项为1,也就是令相角为0,此时结果中值包含灰度信息,没有形状信息。最后两张图显示了相位在确定图像空间特征内容方面的优势。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

...

Mat planes[] = { Mat_< float >(padded), Mat::zeros(padded.size, CV_32F) };

Mat complexImg;

merge(planes, 2, complexImg);

dft(complexImg, complexImg, DFT_COMPLEX_OUTPUT);

split(complexImg, planes);

Mat magMat;

magnitude(planes[0], planes[1], magMat);

// 相角重建

//divide(planes[0], magMat, planes[0]);

//divide(planes[1], magMat, planes[1]);

//谱重建

planes[0] = magMat;

planes[1] = Mat::zeros(padded.size, CV_32F);

merge(planes, 2, complexImg);

Mat dst, tmp;

idft(complexImg, tmp, DFT_REAL_OUTPUT);

...

Q: 傅里叶变换为什么要填充0?

A: (1)提升运算性能;(2)时域补零相当于频域插值,补零操作增加了频域的插值点数,让频域曲线看起来更加光滑,也就是增加了FFT频率分辨率。从傅里叶变换公式可以看出,频域的点数和时域的点数是一样的,时域补零后,采样点增加。详见快速傅里叶变换(FFT)中为什么要“补零”?

Q: 什么是频率(谱)泄漏?

频率泄漏是指傅里叶变换后的频谱中出现了本不该有的频率分量。原来的信号的序列我们认为是无限长的,但我们要分析某个信号的频谱的时候只能对它有限长度的序列进行分析,相当于时域上对它进行了加窗,类似于盒式函数乘上f(t),在频率域中这一相乘意味着原变换与一个sinc函数的卷积,进而导致由sinc函数的高频分量产生所谓的频率泄漏。归根结底,频率泄漏的原因就是加窗导致的序列长度有限。

频率泄漏会使得图像块效应。虽然频率泄漏无法完全消除,但让取样后的函数乘以另一个两端平滑地过渡到0的函数,可明显降低频率泄漏。这个想法是为了抑制“盒式函数”的急剧过渡。

参考

1. 冈萨雷斯《数字图像处理(第四版)》Chapter4(所有图片可在链接中下载)

2. 傅里叶变换推导详解

3. 傅里叶级数与傅里叶变换

4. 从傅里叶变换进阶到小波变换

5. 形象理解二维傅里叶变换

6. 二维傅里叶变换是怎么进行的?

7. 快速傅里叶变换(FFT)中为什么要“补零”?

转载: https://www.sohu.com/a/650204973_121124363

图像处理:傅里叶变换

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图像处理:傅里叶变换 的相关文章

随机推荐

  • Oracle安装问题INS-30131解决方法

    Win 8下安装Oracle 11 2 0 4遇到了错误INS 30131 Google搜索发现多说都说是共享文件夹问题 xff0c 按方法试验无效 于是想删除临时文件再重新安装一次 xff0c 发现oraremexecservice目录无
  • 去掉微信浏览器里的放大缩小按钮

    lt meta http equiv 61 34 Content Type 34 content 61 34 text html charset 61 utf 8 34 gt lt meta name 61 34 viewport 34 c
  • 清除SSH秘钥的命令

    重新安装了openmediavault之后在连接就是这样 xff0c 具体的原因是因为主机保存了以前的秘钥 PS C Users qs gt ssh root 64 10 11 12 2 64 64 64 64 64 64 64 64 64
  • HR-XML(可扩展人力资源标准)简介

    HR XML xff08 可扩展人力资源标准 xff09 简介 Flyspace flyspace 64 x263 net 2003 年 12 月 12 日 标准出处 xff1a http www hr xml org 标准简介 xff1a
  • 解决System进程占用80端口的问题

    1 IIS占用80端口 用如下方法可以解决System进程占用80端口的问题 xff1a 打开RegEdit 找到HKEY LOCAL MACHINE SYSTEM CurrentControlSet Services HTTP 找到一个D
  • Win 7, Server 2008 R2最大线程数限制

    最近在做压力测试时发现Win 7 和 Server 2008 R2 系统内线程数设为1500则无法创建线程池 xff0c 深入分析发现32位和64位程序存在很大性能差异 最大线程数 xff1a 32bit xff1a 1450 64bit
  • 算法|找出数组的最大公约数

    力扣第255场周赛题目 刷题链接 https leetcode cn com problems find greatest common divisor of array 题目描述 给你一个整数数组 nums xff0c 返回数组中最大数和
  • 结构体对齐规则

    结构体对齐规则 xff1a 1 第一个成员在于结构体变量偏移量为0的地址处 2 其他成员变量要对齐到某个数字 xff08 对齐数 xff09 的整数倍的地址处 对齐数 61 编译器默认的一个对齐数 与 该成员大小的 较小值 3 结构体总大小
  • Snapper转换器的捕捉类型

    原文发布时间 xff1a 2014 09 24 作者 xff1a Tenniwdy 在数据处理中Snapper转换器的作用是很强大的 xff0c 它的各类捕捉类型能针对不同的需求对数据进行处理 在FME Desktop 2014版本中新增了
  • STM32 4x4矩阵键盘初始化及实现多位输入

    目的 xff1a 实现矩阵键盘的多位数据输入 这里以两位数据为例 引脚初始化PC0 PC7 void Key Config GPIO InitTypeDef GPIO InitStructure RCC APB2PeriphClockCmd
  • CSP 202206 题解:归一化处理,寻宝大冒险,角色授权,光线追踪,PS无限版

    试题内容请前往CCF官网查看 xff1a CCF CSP计算机软件能力认证考试 http 118 190 20 162 home page 阅读本题解前 xff0c 您应当了解下列知识 xff1a 线段树 教程C 43 43 标准库 xff
  • 在 VirtualBox 中构建 Debian11 虚拟电脑

    文章目录 前言一 准备工作和Debian简介二 新建虚拟电脑三 安装 Debian11四 Debian11系统环境配置配置光盘软件镜像源配置国内镜像软件源控制台鼠标支持 安装虚拟机增强功能SSH 接入国际化和本地化配置网卡 结语 前言 介绍
  • 【华为机试真题 Python】 放苹果

    目录 题目描述 输入 输出 示例 参考代码 题目描述 把m个同样的苹果放在n个同样的盘子里 允许有的盘子空着不放 问共有多少种不同的分法 注意 如果有7个苹果和3个盘子 5 1 1 和 1 5 1 被视为是同一种分法 数据范围 0 m 10
  • keil5 显示 No target connected

    keil5 显示 No target connected 第一 xff0c 确认上电是否正常 xff0c 板子上有电源指示灯 xff1b 就是那个红色的指示灯 第二 xff1a 长按核心板上的复位键不要松开 找到Debug xff0c 确认
  • Debian系统安装中文包

    相对于Ubuntu系统 xff0c debian系统性对来说较为原始 xff0c 不能像Ubuntu一样一键设定为中文 xff0c 这样就必须自行设定 xff1a 1 安装aptitude xff1a sudo apt span class
  • 解决Linux(Ubuntu)系统下复制粘贴文件权限不够的问题

    首先是ctrl 43 alt 43 t 打开一个终端 运行命令 sudo nautilus 就可以打开一个具有管理员权限的文件管理器 xff0c 然后就可以在不切换到管理员的条件下拷贝文件
  • 解决开机出现“CLIENT MAC ADDR”的问题

    开机自检后 xff0c 系统会出现网卡配置的提示 xff0c 此时按Shift 43 F10组合键可进入配置页面 xff0c 如果不按该组合键 xff0c 几秒后则跳入下一页面 xff0c 这里会停留一段时间 xff0c 一般是一二十秒的样
  • iOS之性能优化·提高App的编译速度

    一 前言 经过多年的开发和迭代 xff0c 我相信很多的 iOS 项目代码已经达到几十万行甚至上百万行的规模 xff0c 所使用的 Pod 库的数量可以达到几十个甚至上百个 xff0c App Store 安装包也变得越来越大 xff0c
  • iOS之性能优化·优化App界面的渲染与流畅度

    一 界面渲染流程 渲染流程分析 计算机中的显示过程通常是通过 CPU GPU 显示器协同工作来将图片显示到屏幕上 xff0c 如下图所示 xff1a 苹果为了解决图片撕裂的问题使用了 VSync 43 双缓冲区的形式 xff0c 就是显示器
  • 图像处理:傅里叶变换

    0 引言 在之前的博客 图像增强 xff0c 傅里叶变换 xff08 OpenCV 中都有用到过傅里叶变换 xff0c 但一直都不是特别理解 xff0c 现系统地学习一下 先来看一个视频 傅里叶级数与傅立叶变换 xff0c 我们了解到任何周