Skip to content

Commit f0d4650

Browse files
committed
Add Computer-Image labs
1 parent 1122f52 commit f0d4650

28 files changed

+1158
-0
lines changed

计算机图像学/labs/README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<!-- style=flat/plastic/social, label force to change the title -->
2+
# <div align="center">2019 计算机图像学实验 </div>
3+
[![License](https://img.shields.io/badge/LICENSE-MIT-blue.svg)](LICENSE)
4+
[![Language](https://img.shields.io/badge/language-python3.6-orange.svg)](.)
5+
6+
>说明. 最开始我用的 cpp 实现了实验内容(代码在 `cpp`目录下),以及自己实现了 fft, 1d,2d。但是配置 windows上的 opencv 环境失败,代码只经过了静态语法检测,可能还有些地方有 bug。 后来我用的 python 重新实现了除 FFT 的所有算法,并将结果记录如下
7+
8+
## 使用
9+
### 环境
10+
- python3.6+
11+
- matplotlib
12+
- numpy
13+
- cv2
14+
15+
### 运行
16+
当前目录下的所有 python 代码按如下格式执行
17+
`python3 lab*.py <IMG_PATH>`
18+
19+
`python3 lab1.py images/lena.bmp`
20+
21+
22+
# 实验内容
23+
## 图像的点处理
24+
### 灰度的线性变换
25+
输入斜率,截距, 进行一维线性变换
26+
27+
### 灰度拉伸
28+
输入两个转折点(x1,y1),(x2,y2), 进行分段的线性变换
29+
```
30+
当 x<x1, f(x) = y1/x1*x
31+
当 x1<=x<=x2, f(x) = (y2-y1)(x-x1)/(x2-x1)+y1
32+
当 x>x2, f(x) = (255-y2)*(x-x2)/(255-x2)+y2
33+
```
34+
35+
### 灰度直方图
36+
输入图像,显示它的灰度直方图, 还可以输入恢复的上限,下限, 显示这个范围内的灰度直方图
37+
38+
### 直方图均衡
39+
扩大灰度范围,减少灰度之间的数量差值
40+
41+
42+
结果如下
43+
![](result/lab1-lena.png)
44+
45+
![](result/lab1-pout.png)
46+
47+
## 数字图像的平滑
48+
滤波,去除图像的噪声,均值滤波,中值滤波去除加性噪声;同态滤波去除乘性噪声
49+
50+
先给图像加上 3% 的椒盐噪声,然后分别使用 窗口大小为 3 的均值滤波器和中值滤波器进行滤波
51+
52+
53+
记图像大小 nxm, 窗口大小为 wxw
54+
我在实现滤波器时,移动窗口,每次只会更新移进的值,和移出的值。
55+
即 窗口先又移动,每移动一列,就将这列的数据考虑进来,而将移出的那一列剔除。这样在更新窗口的值时只需 O(w)
56+
57+
对于均值滤波,时间复杂 O(nmw)
58+
对于中值滤波,需要求出中值,则这需要 O(w^2) 的时间才能完成。可以利用 快速选择的算法,在O(lengthOfArray) 时间里找出排任意名次的数,这里找出中值, w\*w/2
59+
总时间复杂度 O(nmw^2)
60+
61+
结果如下
62+
![](result/lab2-lena.png)
63+
64+
65+
## 图像的边缘检测
66+
实验原理:
67+
68+
在灰度图像的情况下,所谓的边缘检测可以看成是基于图像像素灰度值在空间的不连续性对图像做出的一种分割。边缘可以用方向和幅度两个特性来描述。一般而言,沿边缘走向方向其幅度值变化较平缓,而沿垂直于边缘走向其幅度值变化较剧烈。
69+
70+
经典的边缘提取方法是考察图像的每个像素在某个邻域内灰度的变化,利用边缘邻近一阶或二阶方向导数变化规律,用简单的方法检测边缘。这种方法称为边缘检测局部算子
71+
法。
72+
73+
边缘检测算子一般有
74+
- Roberts 交叉算子
75+
- Sobel 模板卷积
76+
- Prewitt 同上
77+
- Laplace
78+
79+
我实现的时 Roberts, Prewitt, 结果如下
80+
![](result/lab3-lena.png)
81+
![](result/lab3-map.png)
82+
83+
## 傅里叶变换
84+
有时间可以专门写一篇介绍 Fourier 变换
85+
86+
实验要求
87+
-`images/rect*` 图像作二维Fourier , 显示频谱,然后作幅度变换,将低频移到中心点
88+
- Fourier 反变换 幅度,并显示
89+
- Fourier 反变换 相位,并显示
90+
91+
结果如下
92+
![](result/lab4-rect1.png)
93+
![](result/lab4-rect2.png)

计算机图像学/labs/cpp/dft.cpp

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#include "dft.h"
2+
3+
dft::dft()
4+
{
5+
}
6+
dft::~dft()
7+
{
8+
}
9+
10+
int computeLayer(int n2)
11+
{
12+
int m = 0;
13+
14+
while (n2 > 1) {
15+
n2 >>= 1;
16+
m += 1;
17+
}
18+
19+
return m;
20+
}
21+
22+
23+
void computeWeights(vector<comp>& weights, int n)
24+
{
25+
double fixed_factor = -2 * PI / n;
26+
weights.clear();
27+
int half = n / 2;
28+
29+
for (int i = 0; i < half; ++i) {
30+
double angle = i * fixed_factor;
31+
weights.push_back(comp{cos(angle), sin(angle)});
32+
}
33+
34+
for (int i = half; i < n; ++i) {
35+
weights.push_back(-weights[i - half]);
36+
}
37+
}
38+
39+
void computeInvertCode(vector<int> dst, int layer)
40+
{
41+
dst.clear();
42+
int n = 1 << layer;
43+
44+
for (int i = 0; i < n; ++i) {
45+
int index = 0, r = i;
46+
47+
for (int j = 0; j < layer; ++j) {
48+
index <<= 1;
49+
50+
if (r & 1) {
51+
index += 1;
52+
}
53+
54+
r >>= 1;
55+
}
56+
57+
dst.push_back(index);
58+
}
59+
}
60+
61+
bool dft::dft1d(vector<comp>& dst, vector<comp> const &src)
62+
{
63+
// fast fourier transform
64+
int n = src.size();
65+
66+
if (n == 0 || ~(n & (n - 1)))
67+
return false;
68+
69+
vector<comp> weights;
70+
computeWeights(weights, n);
71+
int layer = computeLayer(n);
72+
vector<int> invertCode;
73+
computeInvertCode(invertCode, src, layer);
74+
vector<comp> inData;
75+
76+
for (int i = 0; i < n; ++i)
77+
inData[i] = src[invertCode[i]];
78+
79+
dst = vecotr<comp>(comp{0, 0}, n);
80+
81+
// compute fast fourier transform
82+
for (int L = 1; L <= layer; L++) {
83+
int distance = 1 << (L - 1);
84+
int W = 1 << (layer - L);
85+
int B = n >> L;
86+
int N = n / B;
87+
int index;
88+
89+
for (int i = 0; i < B; i++) {
90+
int mid = i * N;
91+
92+
for (int j = 0; j < N / 2; j++) {
93+
index = j + mid;
94+
dst[index] = inData[index] + (Weights[j * W] * inData[index + distance]); // Fe + W*Fo
95+
}
96+
97+
for (int j = N / 2; j < N; j++) {
98+
index = j + mid;
99+
dst[index] = inData[index - distance] + (Weights[j * W] * inData[index]); // Fe - W*Fo
100+
}
101+
}
102+
103+
inData = dst;
104+
}
105+
106+
return true;
107+
}
108+
bool dft::idft1d(vector<comp>& dst, vector<comp> const &src)
109+
{
110+
//invert fast fourier transform
111+
int n = src.size();
112+
113+
if (n == 0 || ~(n & (n - 1)))
114+
return false;
115+
116+
vector<comp> weights;
117+
computeWeights(weights, n);
118+
int layer = computeLayer(n);
119+
vector<comp> inData(src);
120+
dst = vecotr<comp>(comp{0, 0}, n);
121+
122+
// compute invert fast fourier transform
123+
for (int L = 1; L <= layer; L++) {
124+
int distance = 1 << (L - 1);
125+
int W = 1 << (layer - L);
126+
int B = n >> L;
127+
int N = n / B;
128+
int index;
129+
130+
for (int i = 0; i < B; i++) {
131+
int mid = i * N;
132+
133+
for (int j = 0; j < N / 2; j++) {
134+
index = j + mid;
135+
dst[index] = (inData[index] + inData[index + distance]) / 2; // Fe + W*Fo
136+
}
137+
138+
for (int j = N / 2; j < N; j++) {
139+
index = j + mid;
140+
dst[index] = (inData[index] - inData[index + distance]) / 2; // Fe - W*Fo
141+
142+
if (abs(weights[j * W]))
143+
dst[index] = weights[j * W] * dst[index]; //(a+bi)/(c+di)
144+
}
145+
}
146+
147+
inData = dst;
148+
}
149+
150+
vecotr<int> invertCode;
151+
computeInvertCode(invertCode, src, layer);
152+
153+
for (int i = 0; i < n; ++i)
154+
dst[i] = inData[invertCode[i]];
155+
156+
return true;
157+
}
158+
159+
bool dft::_dft2d(vector<vector<comp>>& dst, vector<vector<comp>> const &src,bool isInvert)
160+
{
161+
auto fft=dft::dft1d;
162+
if(isInvert)
163+
fft = dft::idft1d;
164+
int row = src.size();
165+
if(row<1)
166+
return false;
167+
int col = src[0].size();
168+
if(col<1 || ~(row&(row-1)) || ~(col&(col-1)))
169+
return false;
170+
vector<vector<comp>> dftrow(vector<comp>(),row);
171+
for(int i=0;i<n;++i)
172+
fft(dftrow[i],src[i]);
173+
dst.clear();
174+
dst = vector<vector<comp>>(vector<comp>(comp(),col),row);
175+
for(int c=0;c<col;++c){
176+
vector<comp> inData,outData;
177+
for(int r=0;r<row;++r)
178+
inData.push_back(dftrow[r][c]);
179+
fft(outData,inData);
180+
for(int r=0;r<row;++r)
181+
dst[r][c] = outData[r];
182+
}
183+
return true;
184+
}
185+
}
186+
bool dft::dft2d(vector<vector<comp>>& dst, vector<vector<comp>> const &src)
187+
{
188+
return _dft2d(dst,src);
189+
}
190+
bool dft::idft2d(vector<vector<comp>>& dst, vector<vector<comp>> const &src)
191+
{
192+
return _dft2d(dst,src,true);
193+
}

计算机图像学/labs/cpp/dft.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef __my_dft__
2+
#define __my_dft__
3+
4+
5+
#include <complex>
6+
#include <vector>
7+
8+
#define MAX_MATRIX_SIZE 419304 // 2048*2048
9+
#define MAX_VECTOR_LENGTH 10000
10+
#define PI 3.1415926
11+
12+
using std::complex;
13+
using std::vector;
14+
typedef complex<double> comp ;
15+
16+
class dft
17+
{
18+
public:
19+
dft();
20+
~dft();
21+
bool dft1d(vector<comp>&, vector<comp> const &);
22+
bool dft2d(vector<comp>&, vector<comp> const &);
23+
bool idft1d(vector<comp>&, vector<comp> const &);
24+
bool dft::_dft2d(vector<vector<comp>>& dst, vector<vector<comp>> const &src,bool isInvert=false)
25+
bool dft::dft2d(vector<vector<comp>>& dst, vector<vector<comp>> const &src)
26+
bool dft::idft2d(vector<vector<comp>>& dst, vector<vector<comp>> const &src)
27+
};
28+
29+
#endif

0 commit comments

Comments
 (0)