├── .gitignore
├── FourierTransform
├── README.md
├── myDFT2.m
├── myFFT.m
├── myFFT2.m
├── myGHPF.m
├── myGLPF.m
├── myIDFT2.m
├── myIFFT2.m
└── ~$057057.docx
├── README.md
├── colorTransfer
├── colorTransfer.sln
└── colorTransfer
│ ├── CImg.h
│ ├── ReadMe.txt
│ ├── colorTransfer.cpp
│ ├── colorTransfer.vcxproj
│ ├── colorTransfer.vcxproj.filters
│ ├── stdafx.cpp
│ ├── stdafx.h
│ └── targetver.h
├── faceMorphing
├── README.md
├── faceMorphing.sln
└── faceMorphing
│ ├── CImg.h
│ ├── ReadMe.txt
│ ├── faceMorphing.cpp
│ ├── faceMorphing.vcxproj
│ ├── faceMorphing.vcxproj.filters
│ ├── img
│ ├── .gitignore
│ ├── .gitignore~
│ ├── 1.jpg
│ ├── 1.txt
│ ├── 2.jpg
│ └── 2.txt
│ ├── stdafx.cpp
│ ├── stdafx.h
│ └── targetver.h
├── histEqn
├── histEqn.sln
└── histEqn
│ ├── CImg.h
│ ├── ReadMe.txt
│ ├── histEqn.cpp
│ ├── histEqn.h
│ ├── histEqn.vcxproj
│ ├── histEqn.vcxproj.filters
│ ├── main.cpp
│ ├── stdafx.cpp
│ ├── stdafx.h
│ └── targetver.h
├── hough
├── hough.sln
└── hough
│ ├── CImg.h
│ ├── ReadMe.txt
│ ├── hough.cpp
│ ├── hough.h
│ ├── hough.vcxproj
│ ├── hough.vcxproj.filters
│ ├── main.cpp
│ ├── stdafx.cpp
│ ├── stdafx.h
│ └── targetver.h
├── imageEnhancement
├── README.md
├── histEqualization.m
├── imageHist.m
├── laplacianFiltering.m
├── logTransform.m
├── powerlawTransform.m
├── spatialFiltering.m
├── spatialFiltering_ignore.m
├── spatialFiltering_zeros.m
└── unsharpFiltering.m
├── imageWarpping
├── imageWarpping.sln
└── imageWarpping
│ ├── CImg.h
│ ├── ReadMe.txt
│ ├── hough.cpp
│ ├── hough.h
│ ├── imageWapping.h
│ ├── imageWarpping.cpp
│ ├── imageWarpping.vcxproj
│ ├── imageWarpping.vcxproj.filters
│ ├── main.cpp
│ ├── stdafx.cpp
│ ├── stdafx.h
│ └── targetver.h
├── noiseReduction
├── README.md
├── addMotionBlur.m
├── addSinNoise.m
├── computePSNR.m
├── getSpacial.m
├── getSpectrum.m
├── notchFiltering.m
├── rescale.m
├── script.m
├── script2.m
├── sine.m
├── wienerFiltering.m
└── ~$057057_lab4.docx
└── zoom_and_shrink
├── README.md
├── bilinear_interpolation
├── resizeImage_bilinear.m
└── test.m
└── pixel_replication
├── resizeImage_replication.m
├── resizeImage_replication.m~
├── test.m
└── test.m~
/.gitignore:
--------------------------------------------------------------------------------
1 | *.jpg
2 | *.png
3 | *.bmp
4 | *.jpeg
5 | *.tif
6 | *.log
7 | *.tlog
8 | *.obj
9 | *.idb
10 | *.pdb
11 | *.pch
12 | *.exe
13 | *.lik
14 | *.lastbuildstate
15 | Debug
16 | x64
17 |
18 | .DS_Store
19 | Thumbs.db
20 | .gitignore~
21 | .vs
22 |
--------------------------------------------------------------------------------
/FourierTransform/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 题目 : http://www.imageprocessingplace.com/DIP-3E/dip3e_student_projects.htm#03-01
4 |
5 | 图片:http://www.imageprocessingplace.com/root_files_V3/image_databases.htm
6 |
7 | 实现内容:
8 |
9 | * Two-Dimensional Fast Fourier Transform
10 | * Fourier Spectrum and Average Value
11 | * Lowpass Filtering
12 | * Highpass Filtering
--------------------------------------------------------------------------------
/FourierTransform/myDFT2.m:
--------------------------------------------------------------------------------
1 | function [ F ] = myDFT2( f )
2 | %MYDFT2 Summary of this function goes here
3 | % Detailed explanation goes here
4 | [P,Q] = size(f);
5 | x = 0 : P-1;
6 | y = 0 : Q-1;
7 | [Y,X]=meshgrid(y,x);
8 |
9 | F = single(ones(P, Q));
10 | for u = 1 : P
11 | for v = 1 : Q
12 | F(u,v) = sum(sum(f .* exp(-1j*2*pi*(u/P*X + v/Q*Y))));
13 | end
14 | end
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/FourierTransform/myFFT.m:
--------------------------------------------------------------------------------
1 |
2 | function [ y ] = myFFT(x,W)
3 | N = length(x);
4 | s = log2(N);
5 |
6 | offset=1;
7 | x=bitrevorder(x);
8 | %in place
9 | for stage = 1:s
10 | for index=0:(2^stage):(N-1)
11 | for n=0:offset-1
12 | pos=n+index+1;
13 | pow=(2^(s-stage))*n+1;
14 | x1 = x(pos);
15 | x2 = x(pos+offset)*W(pow);
16 | x(pos) = x1 + x2;
17 | x(pos+offset)=x1-x2;
18 | end
19 | end
20 | offset = 2*offset;
21 | end
22 | y=x;
23 | end
--------------------------------------------------------------------------------
/FourierTransform/myFFT2.m:
--------------------------------------------------------------------------------
1 | function [ F ] = myFFT2( f )
2 | %MYFFT2 Summary of this function goes here
3 | % Detailed explanation goes here
4 | % each column of FFT
5 | g = single(ones(size(f)));
6 | F = single(ones(size(f)));
7 |
8 | N = size(f,1);
9 | s1 = log2(N);
10 | if (s1 ~= nextpow2(N))
11 | error('The rows of image must be the pow of 2');
12 | end
13 |
14 | M = size(f,2);
15 | s2 = log2(M);
16 | if (s2 ~= nextpow2(M))
17 | error('The colmuns of image must be the pow of 2');
18 | end
19 | K = 0:max(M,N)/2-1;
20 | % K from 0 ~ N/2-1, but the index is from 1 ~ N/2
21 | W = exp((-1j*2*pi/N)*K);
22 | for u = 1 : size(f,1)
23 | g(u,:) = myFFT(f(u,:),W);
24 | end
25 | for v = 1 : size(f,2)
26 | F(:,v) = myFFT(g(:,v),W);
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/FourierTransform/myGHPF.m:
--------------------------------------------------------------------------------
1 | function [ output ] = myGHPF( D0, M, N )
2 | %MYGHPF Summary of this function goes here
3 | % Detailed explanation goes here
4 | Hlp = myGLPF(D0, M, N);
5 | output = 1 - Hlp;
6 | end
7 |
8 |
--------------------------------------------------------------------------------
/FourierTransform/myGLPF.m:
--------------------------------------------------------------------------------
1 | function [ output ] = myGLPF( D0, M, N )
2 | %MYGLPF Summary of this function goes here
3 | % D0: cut off frequency in GLPF, type single
4 | % M, N: size of the filter(M x N), type int
5 | % output: a 2-D GLPF, type single
6 | % the center of GLPF is in the central
7 | % H(u,v) = exp(-D(u,v)^2/2D0^2)
8 |
9 | d = 2*D0^2;
10 | x = [floor((M-1)/2) :-1: 0, 1 : ceil((M-1)/2)];
11 | y = [floor((N-1)/2) :-1: 0, 1 : ceil((N-1)/2)];
12 | [Y,X] = meshgrid(y,x);
13 | S = X.^2 + Y.^2;
14 | output = single(exp(-S/d));
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/FourierTransform/myIDFT2.m:
--------------------------------------------------------------------------------
1 | function [ f ] = myIDFT2( F )
2 | %MYIDFT Summary of this function goes here
3 | % Detailed explanation goes here
4 |
5 | [P,Q]=size(F);
6 | u = 0:P-1;
7 | v = 0:Q-1;
8 | [V,U] = meshgrid(v,u);
9 | f = single(ones(P,Q));
10 |
11 | %for x = 1 : P
12 | % for y = 1 : Q
13 | % f(x,y) = sum(sum(F .* exp(1j*2*pi*(x/P*U + y/Q*V))));
14 | % end
15 | %end
16 |
17 | UV = U*V;
18 | w1 = mod(UV/P,P);
19 | w2 = mod(UV/Q,Q)';
20 | f = exp(-1j*2*pi*w1) * F * exp(-1j*2*pi*w2);
21 |
22 | f = f/(P*Q);
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/FourierTransform/myIFFT2.m:
--------------------------------------------------------------------------------
1 | function [ f ] = myIFFT2( F )
2 |
3 | f = conj(myFFT2(conj(F)))/(size(F,1)*size(F,2));
4 | end
--------------------------------------------------------------------------------
/FourierTransform/~$057057.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/FourierTransform/~$057057.docx
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Image Processing
2 |
3 | ## Report
4 |
5 | 1. 图像放大缩小(zoom_and_shrink) [Blog:最近邻算法与双线性内插](https://blog.kinpzz.com/2016/09/29/bilinear-interpolation/)
6 | * 最近邻内插
7 | * 双线性内插法
8 | 2. 图像增强(imageEnhancement) [Google Doc](https://docs.google.com/document/d/1wVBv9ghId2ANxUc5hqtmB38u4lTpsxWLZSW6xHSRjco/edit?usp=sharing)
9 | * log transform
10 | * hist qualization
11 | * unsharp filtering
12 | * laplacian filtering
13 | * spatial filtering 有无 padding情况
14 | 3. 傅里叶变换(FourierTransform) [Google Doc](https://docs.google.com/document/d/12U-6B-6k9plXSunznBRK8EkQviV1OIzaDTyD-SSiE0E/edit?usp=sharing)
15 | 4. 频域去噪声(noiseReduction) [Google Doc](https://docs.google.com/document/d/1wHtsmbDBtixlAnCS6zQBtabKEAy6lMegM6rId5s1sL8/edit?usp=sharing)
16 | * notch filtering
17 | * winner filtering
18 |
19 | # Computer Vision and Pattern Recognition
20 |
21 | ## Report
22 | 1. 直方图均衡化 (histogram equalization) : [Google Doc : histEqn](https://docs.google.com/document/d/1nUUfZkj2MxzmywB-vdZZ2fKp5QcJbpeiCVaub7NF5to/edit?usp=sharing)
23 |
24 | 2. 色彩转换(color Transfer) : [Google Doc : colorTransfer](https://docs.google.com/document/d/1Xs7vRzzSAfQ1KLfTLFG-r_psOtJA7YBveIwz06riKks/edit?usp=sharing)
25 |
26 | 3. A4纸边缘提取(hough transeform) : [Google Doc : Hough](https://docs.google.com/document/d/1NPqYcTj0R_17mvCNdp_45wVBWBnI8wGopN5VT67Fm6w/edit?usp=sharing)
27 |
28 | 4. A4纸边缘矫正(imageWarpping): [Google Doc :image Warping](https://docs.google.com/document/d/1ePcSfO367CHRnqIBHSSxy-4vhhbfRTe4RRxYOTrMnfU/edit?usp=sharing)
29 |
30 | 5. 人脸融合(faceMorphing): [Blog: faceMorphing](https://blog.kinpzz.com/2017/04/25/face-morphing/)
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "colorTransfer", "colorTransfer\colorTransfer.vcxproj", "{82125058-FB90-49E4-9D02-B88657DD2A6E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Debug|x64.ActiveCfg = Debug|x64
17 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Debug|x64.Build.0 = Debug|x64
18 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Debug|x86.ActiveCfg = Debug|Win32
19 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Debug|x86.Build.0 = Debug|Win32
20 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Release|x64.ActiveCfg = Release|x64
21 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Release|x64.Build.0 = Release|x64
22 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Release|x86.ActiveCfg = Release|Win32
23 | {82125058-FB90-49E4-9D02-B88657DD2A6E}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | 控制台应用程序:colorTransfer 项目概述
3 | ========================================================================
4 |
5 | 应用程序向导已为您创建了此 colorTransfer 应用程序。
6 |
7 | 本文件概要介绍组成 colorTransfer 应用程序的每个文件的内容。
8 |
9 |
10 | colorTransfer.vcxproj
11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
12 |
13 | colorTransfer.vcxproj.filters
14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
15 |
16 | colorTransfer.cpp
17 | 这是主应用程序源文件。
18 |
19 | /////////////////////////////////////////////////////////////////////////////
20 | 其他标准文件:
21 |
22 | StdAfx.h, StdAfx.cpp
23 | 这些文件用于生成名为 colorTransfer.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 | 其他注释:
27 |
28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
29 |
30 | /////////////////////////////////////////////////////////////////////////////
31 |
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/colorTransfer.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/colorTransfer/colorTransfer/colorTransfer.cpp
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/colorTransfer.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {82125058-FB90-49E4-9D02-B88657DD2A6E}
23 | Win32Proj
24 | colorTransfer
25 | 8.1
26 |
27 |
28 |
29 | Application
30 | true
31 | v140
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v140
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v140
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v140
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 |
84 |
85 |
86 | Use
87 | Level3
88 | Disabled
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Use
100 | Level3
101 | Disabled
102 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
103 | true
104 |
105 |
106 | Console
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 | Use
114 | MaxSpeed
115 | true
116 | true
117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 |
120 |
121 | Console
122 | true
123 | true
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | Use
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 |
137 |
138 | Console
139 | true
140 | true
141 | true
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | Create
156 | Create
157 | Create
158 | Create
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/colorTransfer.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/stdafx.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/colorTransfer/colorTransfer/stdafx.cpp
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/colorTransfer/colorTransfer/stdafx.h
--------------------------------------------------------------------------------
/colorTransfer/colorTransfer/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/colorTransfer/colorTransfer/targetver.h
--------------------------------------------------------------------------------
/faceMorphing/README.md:
--------------------------------------------------------------------------------
1 | # Face Morphing 面部合成
2 |
3 | ## 导语
4 |
5 | ### 效果
6 |
7 | 下面是一段面部合成的过程,演示了从一张脸过渡到另一张脸的过程。
8 |
9 | 
10 |
11 | 其实实现的原理很简单,就是对两张图片每个像素点按一定的比例进行混合。通过以下的公式来对每个像素点进行融合。
12 |
13 | $$ M(x,y) = (1-\alpha)I(x,y) + \alpha J(x,y)$$
14 |
15 | 其中$$\alpha$$代表了图片J所占比重。但是,如果对两张图片进行融合的话会出现一个问题,就是五官的位置并没有对齐,会出现奇怪的效果,如下图参考1中所展示的图片的问题。会发现效果并不是很好,只是两张图片单纯的叠加。
16 |
17 | 
18 |
19 | 这次实验的主要内容,就是介绍如何进行比较和谐的一种融合效果,已经将多张不同比重融合的图片所组成的一个人脸变换过程。
20 |
21 | ## 实现
22 |
23 | ### 实验环境
24 |
25 | Windows 10、Visual Studio 2015、CImg图像处理库
26 |
27 | ### 实验数据
28 |
29 | 
30 |
31 | rate = 0.6时的效果:
32 |
33 |
34 |
35 | ### 主要步骤
36 |
37 | 1. 构建人脸特征点
38 | 2. 进行Delaunay三角剖分
39 | 3. 将每个Delaunay三角形对映射到同一个三角形区域
40 | 4. 对每个映射三角形区域进行morphing
41 |
42 | ### 详细步骤
43 |
44 | ##### 1. 构建人脸特征点
45 |
46 | 
47 |
48 | 这个实验的重点不是实现人脸特征点的识别,所以这里就采用人工进行采集特征点。也可以采用Dlib库来进行特征点提取,但是这个库需要用到opencv,这里使用的库是CImg,所以没有采用。
49 |
50 | ```c++
51 | struct point {
52 | int x;
53 | int y;
54 | point(int _x, int _y) : x(_x), y(_y) {}
55 | };
56 | /*
57 | * get dection points to vector manually
58 | * this function support to reuse the records we have record in fliename .txt
59 | * if you want to detect the points by yourself just remove the txt file
60 | * record method from outer loop in inner loop
61 | * in this example 24 points each picture
62 | */
63 | CImg getDetectionPoints(vector& points, const CImg& src, const string filename) {
64 | // 1.jpg to 1.txt which record the points
65 | string points_file(filename);
66 | points_file.replace(points_file.end() - 3, points_file.end(), "txt");
67 | CImg dect_img = src;
68 | int color[] = { 255, 0, 0 };
69 |
70 | // try to read detection points from file
71 | ifstream input(points_file);
72 | ofstream output;
73 | if (input.fail()) { // if no exist points
74 | output.open(points_file);
75 | CImgDisplay disp(dect_img, filename.c_str());
76 |
77 | while (!disp.is_closed()) {
78 | disp.wait();
79 | if (disp.button() & 1 && disp.mouse_y() >= 0) {
80 | point* p = new point(disp.mouse_x(), disp.mouse_y());
81 | points.push_back(p);
82 | // draw circle
83 | dect_img.draw_circle(p->x, p->y, dect_img._width / 100, color);
84 | dect_img.display(disp);
85 | // write file
86 | output << p->x << "," << p->y << endl;
87 | }
88 | }
89 | output.close();
90 | }
91 | else {
92 | string line;
93 | while (getline(input, line)) {
94 | // point format : x,y
95 | int pos = line.find(',');
96 | if (pos != string::npos) {
97 | // skip ","
98 | string x_str = line.substr(0, pos);
99 | string y_str = line.substr(pos + 1, string::npos);
100 | point* p = new point(std::stoi(x_str), std::stoi(y_str));
101 | points.push_back(p);
102 | // draw circle
103 | dect_img.draw_circle(p->x, p->y, dect_img._width / 100, color);
104 | }
105 | }
106 | //dect_img.display();
107 | }
108 | input.close();
109 | return dect_img;
110 | }
111 | ```
112 |
113 | 这里首先读取与文件 名相同的`txt`文件来读取上一次侦测的记录,若之前对这张图片没有进行过特征点的手动记录,则跳出窗口来对特征点进行手动的侦测,然后存入`txt`文件中以便下次再读取。然后把读取到的侦测点存储在`vector`容器中。
114 |
115 | 除了手动检测的这几个点,还给每张图片加入了8个点,分别是4个角点和每条片的中点。
116 |
117 | ```c++
118 | // add four corners and four middle points
119 | points_A.push_back(new point(0, 0));
120 | points_A.push_back(new point(0, img_A._height));
121 | points_A.push_back(new point(img_A._width, 0));
122 | points_A.push_back(new point(img_A._width, img_A._height));
123 | points_A.push_back(new point(0, img_A._height/2));
124 | points_A.push_back(new point(img_A._width/2, 0));
125 | points_A.push_back(new point(img_A._width, img_A._height/2));
126 | points_A.push_back(new point(img_A._width/2, img_A._height));
127 |
128 | points_B.push_back(new point(0, 0));
129 | points_B.push_back(new point(0, img_B._height));
130 | points_B.push_back(new point(img_B._width, 0));
131 | points_B.push_back(new point(img_B._width, img_B._height));
132 | points_B.push_back(new point(0, img_B._height/2));
133 | points_B.push_back(new point(img_B._width/2, 0));
134 | points_B.push_back(new point(img_B._width, img_B._height / 2));
135 | points_B.push_back(new point(img_B._width/2, img_B._height));
136 | ```
137 |
138 |
139 |
140 | ##### 2. 进行Delaunay三角剖分
141 |
142 | 
143 |
144 | Delaunay 三角形剖分是一种最常用的三角剖分算法,具体可以参考5和百度百科。其中有一个定义
145 |
146 | > 假设V是二维实数域上的有限点集,边e是由点集中的点作为端点构成的封闭线段, E为e的集合。那么该点集V的一个三角剖分T=(V,E)是一个平面图G
147 | >
148 | > 假设T为V的任一三角剖分,则T是V的一个Delaunay三角剖分,当前仅当T中的每个三角形的外接圆的内部不包含V中任何的点。
149 |
150 | 常用的Delaunay三角形的算法,有翻边算法、逐点插入算法、分割合并算法、Bowyer-Watson算法等。
151 |
152 | 这里考虑到特征检测的点比较少,就直接采用上述关于外接圆的这个定义进行暴力验证,时间复杂度达`O(n^4)`
153 |
154 | ```c++
155 | struct triangle {
156 | point a;
157 | point b;
158 | point c;
159 | int index[3];
160 | triangle(point _a, point _b, point _c, int a_index, int b_index, int c_index)
161 | : a(_a), b(_b), c(_c) {
162 | index[0] = a_index;
163 | index[1] = b_index;
164 | index[2] = c_index;
165 | }
166 | triangle(point _a, point _b, point _c) : a(_a), b(_b), c(_c) {}
167 |
168 | bool isInTriangle(const point& p);
169 | };
170 | // get Delaunay triangles by traverse
171 | void getDelaunayTriangles(vector& triangles, const vector& points) {
172 | int size = points.size();
173 | if (size < 3) return;
174 |
175 | for (int i = 0; i < size - 2; i++) {
176 | for (int j = i + 1; j < size - 1; j++) {
177 | for (int k = j + 1; k < size; k++) {
178 | point* A = points[i];
179 | point* B = points[j];
180 | point* C = points[k];
181 | triangle* tri = new triangle(*A, *B, *C, i, j, k);
182 |
183 | bool no_exist = true;
184 | for (int m = 0; m < size; m++)
185 | {
186 | point* P = points[m];
187 | if (m == i || m == j || m == k) continue;
188 | double k1 = (double)(A->y - B->y) / (A->x - B->x);
189 | double k2 = (double)(A->y - C->y) / (A->x - C->x);
190 | if (isPointInCircle(P, tri) || abs(k1-k2) < 0.1) // abs to avoid to closer points
191 | {
192 | no_exist = false;
193 | break;
194 | }
195 | }
196 | if (no_exist)
197 | {
198 | triangles.push_back(tri);
199 | }
200 | }
201 | }
202 | }
203 |
204 | }
205 | ```
206 |
207 | 其实也就是验证每个三角形,看其外接圆内是否包含其他的点,若包含则不要这个三角形,若不包含则要。这里每个点的也同时记录下了其序号,只要对其中一张图片运算Delaunay三角剖分,再另一张图片中只需要根据所剖分出来的三角形的序号进行三角形的构建即可,因为两张图片的点位置是相对应的。
208 |
209 | ```c++
210 | // get couterpart delaunay triangles of B from A
211 | for (int i = 0; i < triangles_A.size(); i++) {
212 | triangles_B.push_back(new triangle(*points_B.at(triangles_A[i]->index[0]),
213 | *points_B.at(triangles_A[i]->index[1]),
214 | *points_B.at(triangles_A[i]->index[2]),
215 | triangles_A[i]->index[0],
216 | triangles_A[i]->index[1],
217 | triangles_A[i]->index[2]));
218 | }
219 | ```
220 |
221 |
222 |
223 | 其中还涉及到了如何验证一个三角形的外接圆是否包含某个点。这里使用了三角形外心的公式来进行计算,直接根据三角形的三个点推出外心坐标,再计算该点与外心的距离是否小于等于半径,如果满足则在外接圆内或上有点。具体公式可以看参考3维基百科中所给的公式。
224 |
225 | ```c++
226 | // get distance between point A and B
227 | double getDistance(point A, point B) {
228 | double dis = (A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y);
229 | return sqrt(dis);
230 | }
231 | // to judge is point p in the circumcircle of tri
232 | // formular find in wikipedia Circumscribed circle
233 | bool isPointInCircle(point* P, triangle* tri) {
234 | point origin(0, 0);
235 | double a_x = tri->a.x;
236 | double b_x = tri->b.x;
237 | double c_x = tri->c.x;
238 | double a_y = tri->a.y;
239 | double b_y = tri->b.y;
240 | double c_y = tri->c.y;
241 | double D = 2 * (a_x*(b_y-c_y) + b_x*(c_y-a_y) + c_x*(a_y-b_y));
242 | double x = ((a_x*a_x + a_y*a_y)*(b_y - c_y) + (b_x*b_x + b_y*b_y)*(c_y - a_y) + (c_x*c_x + c_y*c_y)*(a_y - b_y)) / D;
243 | double y = ((a_x*a_x + a_y*a_y)*(c_x - b_x) + (b_x*b_x + b_y*b_y)*(a_x - c_x) + (c_x*c_x + c_y*c_y)*(b_x - a_x)) / D;
244 | point center((int)x, (int)y);
245 | double radius = getDistance(center, tri->a);
246 |
247 | return (getDistance(*P, center) <= radius);
248 | }
249 | ```
250 |
251 |
252 |
253 | ##### 3.将每个Delaunay三角形对映射到同一个三角形区域
254 |
255 | 上一步结束之后,我们便得到了一些相对应的Delaunay三角形对。接下来要做的就是在每个三角形对之间,求一个的过渡的三角形,然后将三角形对在这个过渡三角形上进行融合。这里过渡三角形的大小是根据两张图片的比例来进行加权的。这样子有一个缺点,就是如果两张图片大小不同,其不同比例的融合的图片大小也会不一样。
256 |
257 | ```c++
258 | // transition between source A and B
259 | triangle* getTransitionTriangle(const triangle* A, const triangle* B, double rate) {
260 | int ax = (int)(rate*(A->a.x) + (1 - rate)*(B->a.x));
261 | int ay = (int)(rate*(A->a.y) + (1 - rate)*(B->a.y));
262 | int bx = (int)(rate*(A->b.x) + (1 - rate)*(B->b.x));
263 | int by = (int)(rate*(A->b.y) + (1 - rate)*(B->b.y));
264 | int cx = (int)(rate*(A->c.x) + (1 - rate)*(B->c.x));
265 | int cy = (int)(rate*(A->c.y) + (1 - rate)*(B->c.y));
266 | return new triangle(point(ax, ay), point(bx, by), point(cx, cy));
267 | }
268 | ```
269 |
270 | 函数`getTransTriangle2Triangle`是根据源三角形到目标三角形来求其变换矩阵的。根据公式$HA=D$,两边右乘以A的逆矩阵即可以得到变换矩阵H。
271 |
272 | ```c++
273 | void getTransTriangle2Triangle(double(*H)[3], const triangle* src, const triangle* dst) {
274 |
275 | // transform src to dst
276 | int u0 = src->a.x;
277 | int v0 = src->a.y;
278 | int u1 = src->b.x;
279 | int v1 = src->b.y;
280 | int u2 = src->c.x;
281 | int v2 = src->c.y;
282 |
283 | int x0 = dst->a.x;
284 | int y0 = dst->a.y;
285 | int x1 = dst->b.x;
286 | int y1 = dst->b.y;
287 | int x2 = dst->c.x;
288 | int y2 = dst->c.y;
289 |
290 | // |A|
291 | int detA;
292 | detA = u0*v1 + u1*v2 + u2*v0 - u2*v1 - u0*v2 - u1*v0;
293 | // inv(A) * detA
294 | int A11, A12, A13, A21, A22, A23, A31, A32, A33;
295 | A11 = v1 - v2;
296 | A21 = -(v0 - v2);
297 | A31 = v0 - v1;
298 | A12 = -(u1 - u2);
299 | A22 = u0 - u2;
300 | A32 = -(u0 - u1);
301 | A13 = u1*v2 - u2*v1;
302 | A23 = -(u0*v2 - u2*v0);
303 | A33 = u0*v1 - u1*v0;
304 |
305 | H[0][0] = (double)(x0*A11 + x1*A21 + x2*A31) / detA;
306 | H[1][0] = (double)(y0*A11 + y1*A21 + y2*A31) / detA;
307 | H[2][0] = (double)(A11 + A21 + A31) / detA;
308 | H[0][1] = (double)(x0*A12 + x1*A22 + x2*A32) / detA;
309 | H[1][1] = (double)(y0*A12 + y1*A22 + y2*A32) / detA;
310 | H[2][1] = (double)(A12 + A22 + A32) / detA;
311 | H[0][2] = (double)(x0*A13 + x1*A23 + x2*A33) / detA;
312 | H[1][2] = (double)(y0*A13 + y1*A23 + y2*A33) / detA;
313 | H[2][2] = (double)(A13 + A23 + A33) / detA;
314 | }
315 | ```
316 |
317 | 需要将求过渡三角形变换到两张图对应的Delaunay的变换矩阵两个,然后将过度三角形的坐标转换成在两张图片中对应的坐标。这样子做法的一个好处就是过渡三角形上不会有没有映射到的点出现。
318 |
319 |
320 |
321 | ##### 4.对每个映射三角形区域进行morphing
322 |
323 | 对每个三角形对求变换到两个Delaunay三角形的变换矩阵,然后将对每个点进行转换和融合(morph), 这里涉及到了一个遍历三角形的问题,原先是想求出三角形的最小外接矩形这样子就可以直接遍历这个矩形中的点,再判断这个点是否在三角形内了,但是求这个矩形是遇到了一些困难,于是就改成了直接对遍历全部的点,判断是否在这个三角形内。当图片大的时候,这样子其实效率是很低的。
324 |
325 | 这里涉及到了判断一个点是否在三角形内的方法。这里采用的是向量叉积符号的方法,具体可以看参考4。如果三角形的逆时针边的向量的与点P的叉积都是正的,则可以判断P在三角形内,但是由于无法判断我们三角形拿出来的边是顺时针还是逆时针,我就改成了判断三个叉积的符号是否相同,如果相同则可以判断点在三角形内。
326 |
327 | 
328 |
329 | ```c++
330 | int cross3(const point &a, const point &b, const point &p) {
331 | return (b.x - a.x)*(p.y - a.y) - (b.y - a.y)*(p.x - a.x);
332 | }
333 | bool triangle::isInTriangle(const point& p) {
334 |
335 | if (cross3(a, b, p) >= 0 && cross3(b, c, p) >= 0 && cross3(c, a, p) >= 0)
336 | return true;
337 | else if (cross3(a, b, p) <= 0 && cross3(b, c, p) <= 0 && cross3(c, a, p) <= 0)
338 | return true;
339 | else
340 | return false;
341 | }
342 | ```
343 |
344 | 在求完过渡三角形的每个点在两张图片上对应的点之后(使用变换矩阵求出坐标之后再使用双线性内插),就可以根据公式 $$M(x,y) = (1-\alpha)I(x,y) + \alpha J(x,y)$$来进行morphing了。
345 |
346 | ```c++
347 | // morph Triangles
348 | CImg morphTriangle(double rate, const vector& triangles_A, const vector& triangles_B,
349 | const CImg& img_A, const CImg& img_B) {
350 | int width = (rate * img_A._width + (1 - rate) * img_B._width);
351 | int height = (rate * img_A._height + (1 - rate) * img_B._height);
352 | CImg result(width, height, 1, 3);
353 |
354 | for (int i = 0; i < triangles_A.size(); i++) {
355 | triangle* trans_tri = getTransitionTriangle(triangles_A[i], triangles_B[i], rate);
356 | double H1[3][3], H2[3][3];
357 | getTransTriangle2Triangle(H1, trans_tri, triangles_A[i]);
358 | getTransTriangle2Triangle(H2, trans_tri, triangles_B[i]);
359 | cimg_forXY(result, x, y) {
360 | if (trans_tri->isInTriangle(point(x, y))) {
361 |
362 | float tx_a = x*H1[0][0] + y*H1[0][1] + H1[0][2];
363 | float ty_a = x*H1[1][0] + y*H1[1][1] + H1[1][2];
364 | float pixel_a[3] = { 0 };
365 | cimg_forC(img_A, c) {
366 | pixel_a[c] = img_A.linear_atXY(tx_a, ty_a, 0, c);
367 | }
368 |
369 | float tx_b = x*H2[0][0] + y*H2[0][1] + H2[0][2];
370 | float ty_b = x*H2[1][0] + y*H2[1][1] + H2[1][2];
371 | float pixel_b[3] = { 0 };
372 | cimg_forC(img_B, c) {
373 | pixel_b[c] = img_B.linear_atXY(tx_b, ty_b, 0, c);
374 | }
375 |
376 | // morph
377 | cimg_forC(result, c) {
378 | result(x, y, 0, c) = rate*pixel_a[c] + (1 - rate)*pixel_b[c];
379 | }
380 | }
381 |
382 | }
383 | }
384 |
385 | return result;
386 | }
387 | ```
388 |
389 |
390 |
391 | main 函数
392 |
393 | ```c++
394 | int main() {
395 |
396 | // --- step 1 : read img ---
397 |
398 | string filename_A = "img/1.jpg";
399 | string filename_B = "img/2.jpg";
400 | CImg img_A(filename_A.c_str());
401 | CImg img_B(filename_B.c_str());
402 |
403 | // --- step 2 : get dection points ---
404 | vector points_A, points_B;
405 |
406 | // add four corners and four middle points
407 | points_A.push_back(new point(0, 0));
408 | points_A.push_back(new point(0, img_A._height));
409 | points_A.push_back(new point(img_A._width, 0));
410 | points_A.push_back(new point(img_A._width, img_A._height));
411 | points_A.push_back(new point(0, img_A._height/2));
412 | points_A.push_back(new point(img_A._width/2, 0));
413 | points_A.push_back(new point(img_A._width, img_A._height/2));
414 | points_A.push_back(new point(img_A._width/2, img_A._height));
415 |
416 | points_B.push_back(new point(0, 0));
417 | points_B.push_back(new point(0, img_B._height));
418 | points_B.push_back(new point(img_B._width, 0));
419 | points_B.push_back(new point(img_B._width, img_B._height));
420 | points_B.push_back(new point(0, img_B._height/2));
421 | points_B.push_back(new point(img_B._width/2, 0));
422 | points_B.push_back(new point(img_B._width, img_B._height / 2));
423 | points_B.push_back(new point(img_B._width/2, img_B._height));
424 |
425 | getDetectionPoints(points_A, img_A, filename_A);
426 | getDetectionPoints(points_B, img_B, filename_B);
427 |
428 | if (points_A.size() != points_B.size()) {
429 | throw ("the decetion points size are no the same");
430 | }
431 | // --- step 3 : get Delaunay triangles ---
432 | vector triangles_A, triangles_B;
433 | getDelaunayTriangles(triangles_A, points_A);
434 |
435 | // get couterpart delaunay triangles of B from A
436 | for (int i = 0; i < triangles_A.size(); i++) {
437 | triangles_B.push_back(new triangle(*points_B.at(triangles_A[i]->index[0]),
438 | *points_B.at(triangles_A[i]->index[1]),
439 | *points_B.at(triangles_A[i]->index[2]),
440 | triangles_A[i]->index[0],
441 | triangles_A[i]->index[1],
442 | triangles_A[i]->index[2]));
443 | }
444 | drawTriangles(triangles_A, img_A);
445 | drawTriangles(triangles_B, img_B);
446 |
447 | // --- step 4: morph ---
448 | double rate = 0;
449 | for (int i = 0; i <= 10; i++) {
450 | CImg frame = morphTriangle(rate, triangles_A, triangles_B, img_A, img_B);
451 | rate += 0.1;
452 | string filename = "img/frame/.jpg";
453 | if (i < 10) {
454 | filename.insert(10, "0");
455 | filename.insert(11, std::to_string(i));
456 | }
457 | else {
458 | filename.insert(10, std::to_string(i));
459 | }
460 |
461 | frame.save(filename.c_str());
462 | cout << "saving frame " << i << endl;
463 | }
464 | return 0;
465 | }
466 | ```
467 |
468 |
469 |
470 | ### 总结
471 |
472 | rate = 0.6时候的效果
473 |
474 |
475 |
476 | 这次做的模型还是一个比较基础的模型,在侦测点不多的情况下速度平平,如果要做成工业级的产品,还有诸多需要改进的地方。比如Delaunay三角剖分的算法、遍历三角形的算法、人脸特征点的快速侦测。其实做完之后发现原理很简单,无非就是一个变换公式。主要做的功夫都是要使得”对应“的点能够对应着进行转换,才能达到一个比较好的效果。
477 |
478 | ## 参考
479 |
480 | 1. [手把手:使用OpenCV进行面部合成— C++ / Python](http://mp.weixin.qq.com/s?__biz=MjM5MTQzNzU2NA==&mid=2651641340&idx=1&sn=29e39cb6113120fe73b3c397f1c9d555)
481 | 2. [基于opencv+Dlib的面部合成(Face Morph)](http://blog.csdn.net/wangxing233/article/details/51549880)
482 | 3. [Wikipedia : Circumscribed circle](https://en.wikipedia.org/wiki/Circumscribed_circle)
483 | 4. [向量叉积和应用:判断点是否在三角形内部](http://www.yalewoo.com/in_triangle_test.html)
484 | 5. [Delaunay三角剖分算法](http://www.cnblogs.com/zhiyishou/p/4430017.html)
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "faceMorphing", "faceMorphing\faceMorphing.vcxproj", "{858B6486-4263-46D0-9E12-D8F99E494C84}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Debug|x64.ActiveCfg = Debug|x64
17 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Debug|x64.Build.0 = Debug|x64
18 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Debug|x86.ActiveCfg = Debug|Win32
19 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Debug|x86.Build.0 = Debug|Win32
20 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Release|x64.ActiveCfg = Release|x64
21 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Release|x64.Build.0 = Release|x64
22 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Release|x86.ActiveCfg = Release|Win32
23 | {858B6486-4263-46D0-9E12-D8F99E494C84}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | 控制台应用程序:faceMorphing 项目概述
3 | ========================================================================
4 |
5 | 应用程序向导已为您创建了此 faceMorphing 应用程序。
6 |
7 | 本文件概要介绍组成 faceMorphing 应用程序的每个文件的内容。
8 |
9 |
10 | faceMorphing.vcxproj
11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
12 |
13 | faceMorphing.vcxproj.filters
14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
15 |
16 | faceMorphing.cpp
17 | 这是主应用程序源文件。
18 |
19 | /////////////////////////////////////////////////////////////////////////////
20 | 其他标准文件:
21 |
22 | StdAfx.h, StdAfx.cpp
23 | 这些文件用于生成名为 faceMorphing.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 | 其他注释:
27 |
28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
29 |
30 | /////////////////////////////////////////////////////////////////////////////
31 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/faceMorphing.cpp:
--------------------------------------------------------------------------------
1 | /* author : Yan Pengxiang 14331327
2 | * kinpzzz(at)gmail
3 | * 2017.4
4 | */
5 |
6 | #include "stdafx.h"
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "CImg.h"
12 | using std::vector;
13 | using std::string;
14 | using std::cout;
15 | using std::cin;
16 | using std::endl;
17 | using std::ifstream;
18 | using std::ofstream;
19 | using std::getline;
20 | using namespace cimg_library;
21 |
22 | struct point {
23 | int x;
24 | int y;
25 | point(int _x, int _y) : x(_x), y(_y) {}
26 | };
27 |
28 | struct triangle {
29 | point a;
30 | point b;
31 | point c;
32 | int index[3];
33 | triangle(point _a, point _b, point _c, int a_index, int b_index, int c_index)
34 | : a(_a), b(_b), c(_c) {
35 | index[0] = a_index;
36 | index[1] = b_index;
37 | index[2] = c_index;
38 | }
39 | triangle(point _a, point _b, point _c) : a(_a), b(_b), c(_c) {}
40 |
41 | bool isInTriangle(const point& p);
42 | };
43 |
44 | CImg getDetectionPoints(vector& points, const CImg& src, string filename);
45 | double getDistance(point A, point B);
46 | bool isPointInCircle(point* P, triangle* tri);
47 | void getDelaunayTriangles(vector& triangles, const vector& points);
48 | void drawTriangles(const vector& triangles, const CImg& src);
49 | triangle* getTransitionTriangle(const triangle* A, const triangle* B, double rate);
50 | void getTransTriangle2Triangle(double(*H)[3], const triangle* src, const triangle* dst);
51 | int cross3(const point &a, const point &b, const point &p);
52 | CImg morphTriangle(double rate, const vector& triangles_A, const vector& triangles_B,
53 | const CImg& img_A, const CImg& img_B);
54 |
55 | int main() {
56 |
57 | // --- step 1 : read img ---
58 |
59 | string filename_A = "img/1.jpg";
60 | string filename_B = "img/2.jpg";
61 | CImg img_A(filename_A.c_str());
62 | CImg img_B(filename_B.c_str());
63 |
64 | // --- step 2 : get dection points ---
65 | vector points_A, points_B;
66 |
67 | // add four corners and four middle points
68 | points_A.push_back(new point(0, 0));
69 | points_A.push_back(new point(0, img_A._height));
70 | points_A.push_back(new point(img_A._width, 0));
71 | points_A.push_back(new point(img_A._width, img_A._height));
72 | points_A.push_back(new point(0, img_A._height/2));
73 | points_A.push_back(new point(img_A._width/2, 0));
74 | points_A.push_back(new point(img_A._width, img_A._height/2));
75 | points_A.push_back(new point(img_A._width/2, img_A._height));
76 |
77 | points_B.push_back(new point(0, 0));
78 | points_B.push_back(new point(0, img_B._height));
79 | points_B.push_back(new point(img_B._width, 0));
80 | points_B.push_back(new point(img_B._width, img_B._height));
81 | points_B.push_back(new point(0, img_B._height/2));
82 | points_B.push_back(new point(img_B._width/2, 0));
83 | points_B.push_back(new point(img_B._width, img_B._height / 2));
84 | points_B.push_back(new point(img_B._width/2, img_B._height));
85 |
86 | getDetectionPoints(points_A, img_A, filename_A);
87 | getDetectionPoints(points_B, img_B, filename_B);
88 |
89 | if (points_A.size() != points_B.size()) {
90 | throw ("the decetion points size are no the same");
91 | }
92 | // --- step 3 : get Delaunay triangles ---
93 | vector triangles_A, triangles_B;
94 | getDelaunayTriangles(triangles_A, points_A);
95 |
96 | // get couterpart delaunay triangles of B from A
97 | for (int i = 0; i < triangles_A.size(); i++) {
98 | triangles_B.push_back(new triangle(*points_B.at(triangles_A[i]->index[0]),
99 | *points_B.at(triangles_A[i]->index[1]),
100 | *points_B.at(triangles_A[i]->index[2]),
101 | triangles_A[i]->index[0],
102 | triangles_A[i]->index[1],
103 | triangles_A[i]->index[2]));
104 | }
105 | drawTriangles(triangles_A, img_A);
106 | drawTriangles(triangles_B, img_B);
107 |
108 | // --- step 4: morph ---
109 | double rate = 0;
110 | for (int i = 0; i <= 10; i++) {
111 | CImg frame = morphTriangle(rate, triangles_A, triangles_B, img_A, img_B);
112 | rate += 0.1;
113 | string filename = "img/frame/.jpg";
114 | if (i < 10) {
115 | filename.insert(10, "0");
116 | filename.insert(11, std::to_string(i));
117 | }
118 | else {
119 | filename.insert(10, std::to_string(i));
120 | }
121 |
122 | frame.save(filename.c_str());
123 | cout << "saving frame " << i << endl;
124 | }
125 | return 0;
126 | }
127 |
128 |
129 | /*
130 | * get dection points to vector manually
131 | * this function support to reuse the records we have record in fliename .txt
132 | * if you want to detect the points by yourself just remove the txt file
133 | * record method from outer loop in inner loop
134 | * in this example 24 points each picture
135 | */
136 | CImg getDetectionPoints(vector& points, const CImg& src, const string filename) {
137 | // 1.jpg to 1.txt which record the points
138 | string points_file(filename);
139 | points_file.replace(points_file.end() - 3, points_file.end(), "txt");
140 | CImg dect_img = src;
141 | int color[] = { 255, 0, 0 };
142 |
143 | // try to read detection points from file
144 | ifstream input(points_file);
145 | ofstream output;
146 | if (input.fail()) { // if no exist points
147 | output.open(points_file);
148 | CImgDisplay disp(dect_img, filename.c_str());
149 |
150 | while (!disp.is_closed()) {
151 | disp.wait();
152 | if (disp.button() & 1 && disp.mouse_y() >= 0) {
153 | point* p = new point(disp.mouse_x(), disp.mouse_y());
154 | points.push_back(p);
155 | // draw circle
156 | dect_img.draw_circle(p->x, p->y, dect_img._width / 100, color);
157 | dect_img.display(disp);
158 | // write file
159 | output << p->x << "," << p->y << endl;
160 | }
161 | }
162 | output.close();
163 | }
164 | else {
165 | string line;
166 | while (getline(input, line)) {
167 | // point format : x,y
168 | int pos = line.find(',');
169 | if (pos != string::npos) {
170 | // skip ","
171 | string x_str = line.substr(0, pos);
172 | string y_str = line.substr(pos + 1, string::npos);
173 | point* p = new point(std::stoi(x_str), std::stoi(y_str));
174 | points.push_back(p);
175 | // draw circle
176 | dect_img.draw_circle(p->x, p->y, dect_img._width / 100, color);
177 | }
178 | }
179 | //dect_img.display();
180 | }
181 | input.close();
182 | return dect_img;
183 | }
184 |
185 | double getDistance(point A, point B) {
186 | double dis = (A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y);
187 | return sqrt(dis);
188 | }
189 | // to judge is point p in the circumcircle of tri
190 | // formular find in wikipedia Circumscribed circle
191 | bool isPointInCircle(point* P, triangle* tri) {
192 | point origin(0, 0);
193 | double a_x = tri->a.x;
194 | double b_x = tri->b.x;
195 | double c_x = tri->c.x;
196 | double a_y = tri->a.y;
197 | double b_y = tri->b.y;
198 | double c_y = tri->c.y;
199 | double D = 2 * (a_x*(b_y-c_y) + b_x*(c_y-a_y) + c_x*(a_y-b_y));
200 | double x = ((a_x*a_x + a_y*a_y)*(b_y - c_y) + (b_x*b_x + b_y*b_y)*(c_y - a_y) + (c_x*c_x + c_y*c_y)*(a_y - b_y)) / D;
201 | double y = ((a_x*a_x + a_y*a_y)*(c_x - b_x) + (b_x*b_x + b_y*b_y)*(a_x - c_x) + (c_x*c_x + c_y*c_y)*(b_x - a_x)) / D;
202 | point center((int)x, (int)y);
203 | double radius = getDistance(center, tri->a);
204 |
205 | return (getDistance(*P, center) <= radius);
206 | }
207 | void getDelaunayTriangles(vector& triangles, const vector& points) {
208 | int size = points.size();
209 | if (size < 3) return;
210 |
211 | for (int i = 0; i < size - 2; i++) {
212 | for (int j = i + 1; j < size - 1; j++) {
213 | for (int k = j + 1; k < size; k++) {
214 | point* A = points[i];
215 | point* B = points[j];
216 | point* C = points[k];
217 | triangle* tri = new triangle(*A, *B, *C, i, j, k);
218 |
219 | bool no_exist = true;
220 | for (int m = 0; m < size; m++)
221 | {
222 | point* P = points[m];
223 | if (m == i || m == j || m == k) continue;
224 | double k1 = (double)(A->y - B->y) / (A->x - B->x);
225 | double k2 = (double)(A->y - C->y) / (A->x - C->x);
226 | if (isPointInCircle(P, tri) || abs(k1-k2) < 0.1)
227 | {
228 | no_exist = false;
229 | break;
230 | }
231 | }
232 | if (no_exist)
233 | {
234 | triangles.push_back(tri);
235 | }
236 | }
237 | }
238 | }
239 |
240 | }
241 | // draw triangle lines
242 | void drawTriangles(const vector& triangles, const CImg& src) {
243 | CImg disp(src);
244 | int color[] = { 255, 0, 0 };
245 | for (int i = 0; i < triangles.size(); i++) {
246 | disp.draw_line(triangles[i]->a.x, triangles[i]->a.y,
247 | triangles[i]->b.x, triangles[i]->b.y, color);
248 | disp.draw_line(triangles[i]->a.x, triangles[i]->a.y,
249 | triangles[i]->c.x, triangles[i]->c.y, color);
250 | disp.draw_line(triangles[i]->b.x, triangles[i]->b.y,
251 | triangles[i]->c.x, triangles[i]->c.y, color);
252 | disp.draw_circle(triangles[i]->a.x, triangles[i]->a.y, disp._width / 100, color);
253 | disp.draw_circle(triangles[i]->b.x, triangles[i]->b.y, disp._width / 100, color);
254 | disp.draw_circle(triangles[i]->c.x, triangles[i]->c.y, disp._width / 100, color);
255 | }
256 | //disp.display();
257 | }
258 |
259 | // transition between source A and B
260 | triangle* getTransitionTriangle(const triangle* A, const triangle* B, double rate) {
261 | int ax = (int)(rate*(A->a.x) + (1 - rate)*(B->a.x));
262 | int ay = (int)(rate*(A->a.y) + (1 - rate)*(B->a.y));
263 | int bx = (int)(rate*(A->b.x) + (1 - rate)*(B->b.x));
264 | int by = (int)(rate*(A->b.y) + (1 - rate)*(B->b.y));
265 | int cx = (int)(rate*(A->c.x) + (1 - rate)*(B->c.x));
266 | int cy = (int)(rate*(A->c.y) + (1 - rate)*(B->c.y));
267 | return new triangle(point(ax, ay), point(bx, by), point(cx, cy));
268 | }
269 | void getTransTriangle2Triangle(double(*H)[3], const triangle* src, const triangle* dst) {
270 |
271 | // transform src to dst
272 | int u0 = src->a.x;
273 | int v0 = src->a.y;
274 | int u1 = src->b.x;
275 | int v1 = src->b.y;
276 | int u2 = src->c.x;
277 | int v2 = src->c.y;
278 |
279 | int x0 = dst->a.x;
280 | int y0 = dst->a.y;
281 | int x1 = dst->b.x;
282 | int y1 = dst->b.y;
283 | int x2 = dst->c.x;
284 | int y2 = dst->c.y;
285 |
286 | // |A|
287 | int detA;
288 | detA = u0*v1 + u1*v2 + u2*v0 - u2*v1 - u0*v2 - u1*v0;
289 | // inv(A) * detA
290 | int A11, A12, A13, A21, A22, A23, A31, A32, A33;
291 | A11 = v1 - v2;
292 | A21 = -(v0 - v2);
293 | A31 = v0 - v1;
294 | A12 = -(u1 - u2);
295 | A22 = u0 - u2;
296 | A32 = -(u0 - u1);
297 | A13 = u1*v2 - u2*v1;
298 | A23 = -(u0*v2 - u2*v0);
299 | A33 = u0*v1 - u1*v0;
300 |
301 | H[0][0] = (double)(x0*A11 + x1*A21 + x2*A31) / detA;
302 | H[1][0] = (double)(y0*A11 + y1*A21 + y2*A31) / detA;
303 | H[2][0] = (double)(A11 + A21 + A31) / detA;
304 | H[0][1] = (double)(x0*A12 + x1*A22 + x2*A32) / detA;
305 | H[1][1] = (double)(y0*A12 + y1*A22 + y2*A32) / detA;
306 | H[2][1] = (double)(A12 + A22 + A32) / detA;
307 | H[0][2] = (double)(x0*A13 + x1*A23 + x2*A33) / detA;
308 | H[1][2] = (double)(y0*A13 + y1*A23 + y2*A33) / detA;
309 | H[2][2] = (double)(A13 + A23 + A33) / detA;
310 | }
311 |
312 | // url:http://www.yalewoo.com/in_triangle_test.html
313 | int cross3(const point &a, const point &b, const point &p) {
314 | return (b.x - a.x)*(p.y - a.y) - (b.y - a.y)*(p.x - a.x);
315 | }
316 | bool triangle::isInTriangle(const point& p) {
317 |
318 | if (cross3(a, b, p) >= 0 && cross3(b, c, p) >= 0 && cross3(c, a, p) >= 0)
319 | return true;
320 | else if (cross3(a, b, p) <= 0 && cross3(b, c, p) <= 0 && cross3(c, a, p) <= 0)
321 | return true;
322 | else
323 | return false;
324 | }
325 | // morph Triangles
326 | CImg morphTriangle(double rate, const vector& triangles_A, const vector& triangles_B,
327 | const CImg& img_A, const CImg& img_B) {
328 | int width = (rate * img_A._width + (1 - rate) * img_B._width);
329 | int height = (rate * img_A._height + (1 - rate) * img_B._height);
330 | CImg result(width, height, 1, 3);
331 |
332 | for (int i = 0; i < triangles_A.size(); i++) {
333 | triangle* trans_tri = getTransitionTriangle(triangles_A[i], triangles_B[i], rate);
334 | double H1[3][3], H2[3][3];
335 | getTransTriangle2Triangle(H1, trans_tri, triangles_A[i]);
336 | getTransTriangle2Triangle(H2, trans_tri, triangles_B[i]);
337 | cimg_forXY(result, x, y) {
338 | if (trans_tri->isInTriangle(point(x, y))) {
339 |
340 | float tx_a = x*H1[0][0] + y*H1[0][1] + H1[0][2];
341 | float ty_a = x*H1[1][0] + y*H1[1][1] + H1[1][2];
342 | float pixel_a[3] = { 0 };
343 | cimg_forC(img_A, c) {
344 | pixel_a[c] = img_A.linear_atXY(tx_a, ty_a, 0, c);
345 | }
346 |
347 | float tx_b = x*H2[0][0] + y*H2[0][1] + H2[0][2];
348 | float ty_b = x*H2[1][0] + y*H2[1][1] + H2[1][2];
349 | float pixel_b[3] = { 0 };
350 | cimg_forC(img_B, c) {
351 | pixel_b[c] = img_B.linear_atXY(tx_b, ty_b, 0, c);
352 | }
353 |
354 | // morph
355 | cimg_forC(result, c) {
356 | result(x, y, 0, c) = rate*pixel_a[c] + (1 - rate)*pixel_b[c];
357 | }
358 | }
359 |
360 | }
361 | }
362 |
363 | return result;
364 | }
365 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/faceMorphing.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {858B6486-4263-46D0-9E12-D8F99E494C84}
23 | Win32Proj
24 | faceMorphing
25 | 8.1
26 |
27 |
28 |
29 | Application
30 | true
31 | v140
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v140
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v140
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v140
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 |
84 |
85 |
86 | Use
87 | Level3
88 | Disabled
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Use
100 | Level3
101 | Disabled
102 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
103 | true
104 |
105 |
106 | Console
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 | Use
114 | MaxSpeed
115 | true
116 | true
117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 |
120 |
121 | Console
122 | true
123 | true
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | Use
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 |
137 |
138 | Console
139 | true
140 | true
141 | true
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | Create
156 | Create
157 | Create
158 | Create
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/faceMorphing.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/img/.gitignore:
--------------------------------------------------------------------------------
1 | !1.jpg
2 | !2.jpg
3 | frame/*.jpg
4 |
5 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/img/.gitignore~:
--------------------------------------------------------------------------------
1 | !1.jpg
2 | !2.jpg
3 |
4 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/img/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/faceMorphing/faceMorphing/img/1.jpg
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/img/1.txt:
--------------------------------------------------------------------------------
1 | 109,285
2 | 142,181
3 | 249,161
4 | 360,186
5 | 376,276
6 | 370,418
7 | 336,467
8 | 245,518
9 | 166,478
10 | 122,421
11 | 146,322
12 | 185,310
13 | 215,327
14 | 185,333
15 | 281,326
16 | 311,310
17 | 347,325
18 | 315,336
19 | 207,386
20 | 249,399
21 | 290,386
22 | 181,427
23 | 311,427
24 | 248,474
25 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/img/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/faceMorphing/faceMorphing/img/2.jpg
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/img/2.txt:
--------------------------------------------------------------------------------
1 | 73,160
2 | 87,89
3 | 163,71
4 | 233,89
5 | 247,164
6 | 244,256
7 | 233,287
8 | 162,340
9 | 91,291
10 | 78,256
11 | 92,181
12 | 115,168
13 | 138,180
14 | 115,186
15 | 182,180
16 | 204,170
17 | 224,181
18 | 202,188
19 | 135,236
20 | 164,242
21 | 187,234
22 | 128,271
23 | 198,271
24 | 163,295
25 |
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/stdafx.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/faceMorphing/faceMorphing/stdafx.cpp
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/faceMorphing/faceMorphing/stdafx.h
--------------------------------------------------------------------------------
/faceMorphing/faceMorphing/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/faceMorphing/faceMorphing/targetver.h
--------------------------------------------------------------------------------
/histEqn/histEqn.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "histEqn", "histEqn\histEqn.vcxproj", "{C9162399-3D07-42E1-8C6F-B2FECD60F442}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Debug|x64.ActiveCfg = Debug|x64
17 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Debug|x64.Build.0 = Debug|x64
18 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Debug|x86.ActiveCfg = Debug|Win32
19 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Debug|x86.Build.0 = Debug|Win32
20 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Release|x64.ActiveCfg = Release|x64
21 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Release|x64.Build.0 = Release|x64
22 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Release|x86.ActiveCfg = Release|Win32
23 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/histEqn/histEqn/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | 控制台应用程序:histEqn 项目概述
3 | ========================================================================
4 |
5 | 应用程序向导已为您创建了此 histEqn 应用程序。
6 |
7 | 本文件概要介绍组成 histEqn 应用程序的每个文件的内容。
8 |
9 |
10 | histEqn.vcxproj
11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
12 |
13 | histEqn.vcxproj.filters
14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
15 |
16 | histEqn.cpp
17 | 这是主应用程序源文件。
18 |
19 | /////////////////////////////////////////////////////////////////////////////
20 | 其他标准文件:
21 |
22 | StdAfx.h, StdAfx.cpp
23 | 这些文件用于生成名为 histEqn.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 | 其他注释:
27 |
28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
29 |
30 | /////////////////////////////////////////////////////////////////////////////
31 |
--------------------------------------------------------------------------------
/histEqn/histEqn/histEqn.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "histEqn.h"
3 |
4 | // get the histogram of the pixel values in a pthotos
5 | // pixel values range from 0 ~ 255
6 | vector histEqn::getImageHist(const CImg& img) {
7 | vector hist(256, 0);
8 | cimg_forXY(img, x, y) {
9 | hist.at(img(x, y))++;
10 | }
11 | return hist;
12 | }
13 |
14 | // perform histogram equalization
15 | // allow gray image and RGB image
16 | // RGB image will operate on y channel
17 | void histEqn::histEqualization(CImg& img) {
18 | if (img._spectrum == 1) {
19 | try {
20 | histEqualizationGray(img);
21 | }
22 | catch (const char* &e) {
23 | std::cout << e << std::endl;
24 | throw(e);
25 | }
26 | }
27 | else if (img._spectrum == 3) {
28 | try {
29 | histEqualizationRGB(img);
30 | }
31 | catch (const char* &e) {
32 | std::cout << e << std::endl;
33 | throw(e);
34 | }
35 | }
36 | else {
37 | throw("Error channel number");
38 | }
39 | }
40 |
41 | // operate RGB image
42 | void histEqn::histEqualizationRGB(CImg& img) {
43 | if (img._spectrum != 3) {
44 | throw("RGB Error channel number");
45 | }
46 |
47 | // rgb to yuv
48 | CImg img_yuv = img;
49 | int r, g, b;
50 | cimg_forXY(img_yuv,x,y){
51 | r = img(x, y, 0);
52 | g = img(x, y, 1);
53 | b = img(x, y, 2);
54 | img_yuv(x, y, 0) = 0.299*r + 0.587*g + 0.114*b;
55 | img_yuv(x, y, 1) = -0.169*r - 0.331*g + 0.5*b + 128;
56 | img_yuv(x, y, 2) = 0.5*r - 0.419*g - 0.081*b + 128;
57 | }
58 | // y is luminance
59 | CImg y_channel = img_yuv.get_channel(0);
60 | try {
61 | histEqualizationGray(y_channel);
62 | }
63 | catch (const char* &e) {
64 | std::cout << e << std::endl;
65 | throw(e);
66 | }
67 |
68 | // yuv to rgb
69 | int y, u, v;
70 | cimg_forXY(img_yuv, i, j) {
71 | y = y_channel(i, j);
72 | u = img_yuv(i, j, 1);
73 | v = img_yuv(i, j, 2);
74 | img(i, j, 0) = y + 1.13983 * (v - 128);
75 | img(i, j, 1) = y - 0.39465 * (u - 128) - 0.58060 * (v - 128);
76 | img(i, j, 2) = y + 2.03211 * (u - 128);
77 | }
78 | }
79 | // operate gray image
80 | void histEqn::histEqualizationGray(CImg& img) {
81 |
82 | if (img._spectrum != 1) {
83 | throw("Gray Error channel number");
84 | }
85 |
86 | vector hist, mapping;
87 | hist = getImageHist(img);
88 | int pixel_num = img._height * img._width;
89 | double cummulate_sum = 0;
90 | int value_mapped;
91 | // cdf
92 | for (auto i = hist.begin() ; i != hist.end(); i++) {
93 | cummulate_sum += *i;
94 | value_mapped = round(255*cummulate_sum/pixel_num);
95 | mapping.push_back(value_mapped);
96 | }
97 | // mapping
98 | cimg_forXY(img, x, y) {
99 | img(x,y) = mapping.at(img(x,y));
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/histEqn/histEqn/histEqn.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | using std::vector;
3 | using namespace cimg_library;
4 | #ifndef HISTEQN
5 | #define HISTEQN
6 | // singleton using inside static
7 | class histEqn {
8 | public:
9 | static histEqn& getInstance() {
10 | static histEqn instance;
11 | return instance;
12 | }
13 | vector getImageHist(const CImg &);
14 | void histEqualization(CImg&);
15 | void histEqualizationRGB(CImg&);
16 | void histEqualizationGray(CImg&);
17 | private:
18 | histEqn() {}
19 | };
20 | #endif
--------------------------------------------------------------------------------
/histEqn/histEqn/histEqn.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {C9162399-3D07-42E1-8C6F-B2FECD60F442}
23 | Win32Proj
24 | histEqn
25 | 8.1
26 |
27 |
28 |
29 | Application
30 | true
31 | v140
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v140
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v140
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v140
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 |
84 |
85 |
86 | Use
87 | Level3
88 | Disabled
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Use
100 | Level3
101 | Disabled
102 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
103 | true
104 |
105 |
106 | Console
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 | Use
114 | MaxSpeed
115 | true
116 | true
117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 |
120 |
121 | Console
122 | true
123 | true
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | Use
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 |
137 |
138 | Console
139 | true
140 | true
141 | true
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | Create
158 | Create
159 | Create
160 | Create
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/histEqn/histEqn/histEqn.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/histEqn/histEqn/main.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "histEqn.h"
3 |
4 | int main() {
5 | std::vector list = { "img/RGB_test1.jpg",
6 | "img/RGB_test2.jpg",
7 | "img/RGB_test3.jpg",
8 | "img/RGB_test4.jpg",
9 | "img/RGB_test5.jpg",
10 | "img/gray_test1.tif",
11 | "img/gray_test2.tif",
12 | "img/gray_test3.tif",
13 | "img/gray_test4.tif",
14 | "img/gray_test5.tif"};
15 | histEqn histEqnC = histEqn::getInstance();
16 | for (auto i : list) {
17 | char* filename = i;
18 | CImg test(filename);
19 | test.display();
20 | try {
21 | histEqnC.histEqualization(test);
22 | }
23 | catch (const char* &e) {
24 | std::cout << e << std::endl;
25 | }
26 | test.display();
27 | }
28 | return 0;
29 | }
30 |
--------------------------------------------------------------------------------
/histEqn/histEqn/stdafx.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/histEqn/histEqn/stdafx.cpp
--------------------------------------------------------------------------------
/histEqn/histEqn/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/histEqn/histEqn/stdafx.h
--------------------------------------------------------------------------------
/histEqn/histEqn/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/histEqn/histEqn/targetver.h
--------------------------------------------------------------------------------
/hough/hough.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hough", "hough\hough.vcxproj", "{677C4498-36CF-4C6F-AD03-01E52DAEF528}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Debug|x64.ActiveCfg = Debug|x64
17 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Debug|x64.Build.0 = Debug|x64
18 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Debug|x86.ActiveCfg = Debug|Win32
19 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Debug|x86.Build.0 = Debug|Win32
20 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Release|x64.ActiveCfg = Release|x64
21 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Release|x64.Build.0 = Release|x64
22 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Release|x86.ActiveCfg = Release|Win32
23 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/hough/hough/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | 控制台应用程序:hough 项目概述
3 | ========================================================================
4 |
5 | 应用程序向导已为您创建了此 hough 应用程序。
6 |
7 | 本文件概要介绍组成 hough 应用程序的每个文件的内容。
8 |
9 |
10 | hough.vcxproj
11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
12 |
13 | hough.vcxproj.filters
14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
15 |
16 | hough.cpp
17 | 这是主应用程序源文件。
18 |
19 | /////////////////////////////////////////////////////////////////////////////
20 | 其他标准文件:
21 |
22 | StdAfx.h, StdAfx.cpp
23 | 这些文件用于生成名为 hough.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 | 其他注释:
27 |
28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
29 |
30 | /////////////////////////////////////////////////////////////////////////////
31 |
--------------------------------------------------------------------------------
/hough/hough/hough.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/hough/hough/hough.cpp
--------------------------------------------------------------------------------
/hough/hough/hough.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdafx.h"
3 |
4 | using namespace cimg_library;
5 | using std::vector;
6 | #ifndef HOUGH_H
7 | #define HOUGH_H
8 |
9 | struct line {
10 | double _k, _b;
11 | line(double k, double b) : _k(k), _b(b) {}
12 | };
13 | struct point {
14 | int _x, _y;
15 | int _value;
16 | point(int x, int y, int v) : _x(x), _y(y), _value(v) {}
17 | };
18 |
19 | const double PI = 3.14159265358979323846;
20 |
21 | class hough {
22 | public:
23 | hough(CImg source) : _img(source) , _sigma(3), _hough_threshold(700), _hough_diff(300), _gradient_threshold(50){}
24 | void set_blur_sigma(double);
25 | void set_threshold(char, int);
26 | CImg get_rgb2gray();
27 | CImg get_gradient();
28 | CImg get_hough_space();
29 | vector get_peaks();
30 | vector get_lines();
31 | vector get_intersection();
32 | CImg get_draw_lines();
33 | double get_distance(int, int);
34 | bool check_line_valie(int, int);
35 | private:
36 | CImg _img;
37 | CImg _result;
38 | CImg _hough_img;
39 | vector _peaks;
40 | vector _lines;
41 | vector _intersection;
42 |
43 | double _sigma;
44 | int _hough_threshold;
45 | int _hough_diff;
46 | int _gradient_threshold;
47 | };
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/hough/hough/hough.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {677C4498-36CF-4C6F-AD03-01E52DAEF528}
23 | Win32Proj
24 | hough
25 | 8.1
26 |
27 |
28 |
29 | Application
30 | true
31 | v140
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v140
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v140
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v140
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 |
84 |
85 |
86 | Use
87 | Level3
88 | Disabled
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Use
100 | Level3
101 | Disabled
102 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
103 | true
104 |
105 |
106 | Console
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 | Use
114 | MaxSpeed
115 | true
116 | true
117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 |
120 |
121 | Console
122 | true
123 | true
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | Use
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 |
137 |
138 | Console
139 | true
140 | true
141 | true
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | Create
157 | Create
158 | Create
159 | Create
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/hough/hough/hough.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/hough/hough/main.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "hough.h"
3 | #include
4 | using std::string;
5 | int main() {
6 | vector filename = { "Dataset/test1.jpg","Dataset/test2.jpg" };
7 | int test_para[2][4] = { 3, 900, 500, 70,
8 | 2, 650, 250, 45 };
9 | for (int i = 0; i < filename.size(); i++) {
10 | CImg file(filename[i].c_str());
11 | hough hough_runner(file);
12 | hough_runner.set_blur_sigma(test_para[i][0]);
13 | hough_runner.set_threshold('h', test_para[i][1]);
14 | hough_runner.set_threshold('d', test_para[i][2]);
15 | hough_runner.set_threshold('g', test_para[i][3]);
16 | hough_runner.get_rgb2gray().display();
17 | hough_runner.get_gradient().display();
18 | hough_runner.get_hough_space().display();
19 | hough_runner.get_draw_lines().display();
20 | }
21 | return 0;
22 | }
23 |
--------------------------------------------------------------------------------
/hough/hough/stdafx.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/hough/hough/stdafx.cpp
--------------------------------------------------------------------------------
/hough/hough/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/hough/hough/stdafx.h
--------------------------------------------------------------------------------
/hough/hough/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/hough/hough/targetver.h
--------------------------------------------------------------------------------
/imageEnhancement/README.md:
--------------------------------------------------------------------------------
1 | 题目:http://www.imageprocessingplace.com/DIP-3E/dip3e_student_projects.htm#03-01
2 |
3 | 图片:http://www.imageprocessingplace.com/DIP-3E/dip3e_book_images_downloads.htm
4 |
5 | 主要内容:
6 |
7 | * Image Enhancement Using Intensity Transformations
8 | * Histogram Equalization
9 | * Spatial Filtering, Enhancement Using the Laplacian, Unsharp Masking
--------------------------------------------------------------------------------
/imageEnhancement/histEqualization.m:
--------------------------------------------------------------------------------
1 | function [ output, T ] = histEqualization( input )
2 | %perform histogram equalization
3 | % output enhanced photo uint8 [0,255]
4 | % input photo uint8 [0,255]
5 | row = size(input,1);
6 | col = size(input,2);
7 | T = uint8(zeros(1,256));
8 | output = uint8(zeros(row,col));
9 |
10 | pr = imageHist(input)./(col*row);
11 | % 255*cdf(r)
12 | for i = 1: 256
13 | T(1,i) = round(255 * sum(pr(1,1:i)));
14 | end
15 | % mapping
16 | for i = 1:row
17 | for j = 1:col
18 | output(i,j) = T(1,input(i,j)+1);
19 | end
20 | end
21 | end
--------------------------------------------------------------------------------
/imageEnhancement/imageHist.m:
--------------------------------------------------------------------------------
1 | function [ output ] = imageHist( input )
2 | % get the hisogram of a photo
3 | % input uint8 [0~255]
4 | output = single(zeros(1,256));
5 | for i = 1 : size(input,1)
6 | for j = 1 : size(input,2)
7 | output(1,input(i,j)+1) = output(1,input(i,j)+1) + 1;
8 | end
9 | end
10 | end
11 |
12 |
--------------------------------------------------------------------------------
/imageEnhancement/laplacianFiltering.m:
--------------------------------------------------------------------------------
1 | function [ output, scaledLaplacian ] = laplacianFiltering( input, w, scale )
2 | % laplacian fitering
3 | % output 2d grayscale single 0~1
4 | % input 2d grayscale single 0~1
5 | % w laplacian mask 2d
6 | scaledLaplacian = scale .* spatialFiltering(input,w);
7 | output = input + scaledLaplacian;
8 | %output = (output - ones(size(output))*min(min(output)))/max(max(output));
9 | end
10 |
--------------------------------------------------------------------------------
/imageEnhancement/logTransform.m:
--------------------------------------------------------------------------------
1 | function [ output ] = logTransform( input )
2 | % intensity transform by log function
3 | % s = clog(1+r) c = log(2) map s into [0,1]
4 | % input & output [0,1] single
5 | output = 1/log(2)*log(1+input);
6 | end
7 |
8 |
--------------------------------------------------------------------------------
/imageEnhancement/powerlawTransform.m:
--------------------------------------------------------------------------------
1 | function [ output ] = powerlawTransform( input, r )
2 | % power law transform
3 | % g = cf^r, c = 1
4 | % input & output [0,1] single
5 | output = input.^r;
6 | end
7 |
8 |
--------------------------------------------------------------------------------
/imageEnhancement/spatialFiltering.m:
--------------------------------------------------------------------------------
1 | function [ output ] = spatialFiltering( input, w )
2 | %sptial filtering
3 | % input grayscale image single 0~1
4 | % w:mask 2d mask single
5 | % output grayscale image single 0~1
6 | extra_row = (size(w,1)-1)/2;
7 | extra_col = (size(w,2)-1)/2;
8 | % mirror
9 | input = [repmat(input(:,1),1,extra_col),input];
10 | input = [input,repmat(input(:,size(input,2)),1,extra_col)];
11 | input = [repmat(input(1,:),extra_row,1);input];
12 | input = [input;repmat(input(size(input,1),:),extra_row,1)];
13 |
14 | output = single(zeros(size(input)));
15 |
16 | for i = extra_row+1:size(input, 1)-extra_row
17 | for j = extra_col+1:size(input,2)-extra_col
18 | for m = 1 : size(w,1)
19 | for n = 1 : size(w,2)
20 | output(i,j) = output(i,j) + w(m,n)*input(...
21 | (size(w,1)+1)/2-m+i, (size(w,2)+1)/2-n+j);
22 | end
23 | end
24 | end
25 | end
26 | row = size(output,1);
27 | col = size(output,2);
28 | output = output(extra_row+1:row-extra_row, extra_col+1:col-extra_row);
29 | end
30 |
31 |
--------------------------------------------------------------------------------
/imageEnhancement/spatialFiltering_ignore.m:
--------------------------------------------------------------------------------
1 | function [ output ] = spatialFiltering_zeros( input, w )
2 | %sptial filtering using ignore edges methods
3 | % input grayscale image single 0~1
4 | % w:mask 2d mask single
5 | % output grayscale image single 0~1
6 | extra_row = (size(w,1)-1)/2;
7 | extra_col = (size(w,2)-1)/2;
8 | output = input;
9 |
10 | for i = extra_row+1:size(input, 1)-extra_row
11 | for j = extra_col+1:size(input,2)-extra_col
12 | output(i,j) = 0;
13 | for m = 1 : size(w,1)
14 | for n = 1 : size(w,2)
15 | output(i,j) = output(i,j) + w(m,n)*input(...
16 | (size(w,1)+1)/2-m+i, (size(w,2)+1)/2-n+j);
17 | end
18 | end
19 | end
20 | end
21 | end
22 |
23 |
--------------------------------------------------------------------------------
/imageEnhancement/spatialFiltering_zeros.m:
--------------------------------------------------------------------------------
1 | function [ output ] = spatialFiltering_zeros( input, w )
2 | %sptial filtering using add zeors methods
3 | % input grayscale image single 0~1
4 | % w:mask 2d mask single
5 | % output grayscale image single 0~1
6 | extra_row = (size(w,1)-1)/2;
7 | extra_col = (size(w,2)-1)/2;
8 | % zeros
9 | input = [zeros(extra_row,size(input,2));input];
10 | input = [input;zeros(extra_row,size(input,2))];
11 | input = [zeros(size(input,1),extra_col),input];
12 | input = [input,zeros(size(input,1),extra_col)];
13 |
14 | output = single(zeros(size(input)));
15 |
16 | for i = extra_row+1:size(input, 1)-extra_row
17 | for j = extra_col+1:size(input,2)-extra_col
18 | for m = 1 : size(w,1)
19 | for n = 1 : size(w,2)
20 | output(i,j) = output(i,j) + w(m,n)*input(...
21 | (size(w,1)+1)/2-m+i, (size(w,2)+1)/2-n+j);
22 | end
23 | end
24 | end
25 | end
26 | row = size(output,1);
27 | col = size(output,2);
28 | output = output(extra_row+1:row-extra_row, extra_col+1:col-extra_row);
29 | end
30 |
31 |
--------------------------------------------------------------------------------
/imageEnhancement/unsharpFiltering.m:
--------------------------------------------------------------------------------
1 | function [ output, scaledUnsharp, blurredInput] = unsharpFiltering( input, boxMask, scale)
2 | % unsharp filtering
3 | % boxMask box(average) mask
4 | % blurredInput input after applying box mask type single
5 | % scaledUnsharp c*g_mask
6 | blurredInput = spatialFiltering(input,boxMask);
7 | scaledUnsharp = scale .* (input - blurredInput);
8 | output = input + scaledUnsharp;
9 | end
10 |
11 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imageWrapping", "imageWrapping\imageWrapping.vcxproj", "{13EFF0BB-8BE5-481F-9722-11F6DB9F946A}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Debug|x64.ActiveCfg = Debug|x64
17 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Debug|x64.Build.0 = Debug|x64
18 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Debug|x86.ActiveCfg = Debug|Win32
19 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Debug|x86.Build.0 = Debug|Win32
20 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Release|x64.ActiveCfg = Release|x64
21 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Release|x64.Build.0 = Release|x64
22 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Release|x86.ActiveCfg = Release|Win32
23 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | 控制台应用程序:imageWrapping 项目概述
3 | ========================================================================
4 |
5 | 应用程序向导已为您创建了此 imageWrapping 应用程序。
6 |
7 | 本文件概要介绍组成 imageWrapping 应用程序的每个文件的内容。
8 |
9 |
10 | imageWrapping.vcxproj
11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
12 |
13 | imageWrapping.vcxproj.filters
14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
15 |
16 | imageWrapping.cpp
17 | 这是主应用程序源文件。
18 |
19 | /////////////////////////////////////////////////////////////////////////////
20 | 其他标准文件:
21 |
22 | StdAfx.h, StdAfx.cpp
23 | 这些文件用于生成名为 imageWrapping.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 | 其他注释:
27 |
28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
29 |
30 | /////////////////////////////////////////////////////////////////////////////
31 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/hough.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/imageWarpping/imageWarpping/hough.cpp
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/hough.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdafx.h"
3 |
4 | using namespace cimg_library;
5 | using std::vector;
6 | #ifndef HOUGH_H
7 | #define HOUGH_H
8 |
9 | struct line {
10 | double _k, _b;
11 | line(double k, double b) : _k(k), _b(b) {}
12 | };
13 | struct point {
14 | int _x, _y;
15 | int _value;
16 | point(int x, int y, int v) : _x(x), _y(y), _value(v) {}
17 | };
18 |
19 | const double PI = 3.14159265358979323846;
20 |
21 | class hough {
22 | public:
23 | hough(CImg source) : _img(source) , _sigma(2), _hough_threshold(500), _hough_diff(200), _gradient_threshold(30){}
24 | void set_blur_sigma(double);
25 | void set_threshold(char, int);
26 | CImg get_rgb2gray();
27 | CImg get_gradient();
28 | CImg get_hough_space();
29 | vector get_peaks();
30 | vector get_lines();
31 | vector get_intersection();
32 | CImg get_draw_lines();
33 | double get_distance(int, int);
34 | double get_distance(point, point);
35 | bool check_line_valie(int, int);
36 | private:
37 | CImg _img;
38 | CImg _result;
39 | CImg _hough_img;
40 | vector _peaks;
41 | vector _lines;
42 | vector _intersection;
43 |
44 | double _sigma;
45 | int _hough_threshold;
46 | int _hough_diff;
47 | int _gradient_threshold;
48 | };
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/imageWapping.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdafx.h"
3 | #include "hough.h"
4 | using std::vector;
5 | using namespace cimg_library;
6 | #ifndef IMAGEWRAPPING_H
7 | #define IMAGEWRAPPING_H
8 | CImg reverse_wrapping(const CImg, vector);
9 | #endif
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/imageWarpping.cpp:
--------------------------------------------------------------------------------
1 | // imageWrapping.cpp : ��������̨Ӧ�ó��������ڵ㡣
2 | //
3 |
4 | #include "stdafx.h"
5 | #include "imageWarpping.h"
6 |
7 | using namespace cimg_library;
8 | CImg reverse_wrapping(const CImg source, vector vertex) {
9 | double x[4], y[4];
10 | for (int i = 0; i < 4; i++) {
11 | x[i] = vertex.at(i)._x;
12 | y[i] = vertex.at(i)._y;
13 | }
14 | double dx3 = x[0] - x[1] + x[2] - x[3];
15 | double dy3 = y[0] - y[1] + y[2] - y[3];
16 | double H[3][3];
17 | if (dx3 == 0.0f && dy3 == 0.0f) {
18 | H[0][0] = x[1] - x[0];
19 | H[0][1] = y[1] - y[0];
20 | H[0][2] = 0;
21 | H[1][0] = x[2] - x[1];
22 | H[1][1] = y[2] - y[1];
23 | H[1][2] = 0;
24 | H[2][0] = x[0];
25 | H[2][1] = y[0];
26 | H[2][2] = 1;
27 | } else {
28 | double dx1 = x[1] - x[2];
29 | double dx2 = x[3] - x[2];
30 | double dy1 = y[1] - y[2];
31 | double dy2 = y[3] - y[2];
32 | double denominator = dx1 * dy2 - dx2 * dy1;
33 | double a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
34 | double a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
35 | H[0][0] = x[1] - x[0] + a13 * x[1];
36 | H[0][1] = y[1] - y[0] + a13 * y[1];
37 | H[0][2] = a13;
38 | H[1][0] = x[3] - x[0] + a23 * x[3];
39 | H[1][1] = y[3] - y[0] + a23 * y[3];
40 | H[1][2] = a23;
41 | H[2][0] = x[0];
42 | H[2][1] = y[0];
43 | H[2][2] = 1;
44 | }
45 | CImg target(794, 1123, 1, 3);
46 | cimg_forXY(target, x, y) {
47 | double _x = (double)x / target._width;
48 | double _y = (double)y / target._height;
49 | double denominator = H[0][2] * _x + H[1][2] * _y + H[2][2];
50 | double tx = (H[0][0] * _x + H[1][0] * _y + H[2][0]) / denominator;
51 | double ty = (H[0][1] * _x + H[1][1] * _y + H[2][1]) / denominator;
52 | cimg_forC(target, c) {
53 | target(x, y, 0, c) = source.linear_atXY(tx, ty, 0, c);
54 | }
55 | }
56 | return target;
57 | }
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/imageWarpping.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {13EFF0BB-8BE5-481F-9722-11F6DB9F946A}
23 | Win32Proj
24 | imageWrapping
25 | 8.1
26 |
27 |
28 |
29 | Application
30 | true
31 | v140
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v140
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v140
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v140
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 |
84 |
85 |
86 | Use
87 | Level3
88 | Disabled
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Use
100 | Level3
101 | Disabled
102 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
103 | true
104 |
105 |
106 | Console
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 | Use
114 | MaxSpeed
115 | true
116 | true
117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 |
120 |
121 | Console
122 | true
123 | true
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | Use
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 |
137 |
138 | Console
139 | true
140 | true
141 | true
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | Create
160 | Create
161 | Create
162 | Create
163 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/imageWarpping.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/main.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "hough.h"
3 | #include "imageWrapping.h"
4 |
5 | #include
6 | using std::string;
7 | int main() {
8 | vector filename = { "Dataset/test1.jpg","Dataset/test2.jpg" };
9 | int test_para[][4] = { 2, 500, 200, 30,
10 | 3, 500, 250, 40 };
11 | for (int i = 0; i < filename.size(); i++) {
12 | CImg file(filename[i].c_str());
13 | hough hough_runner(file);
14 |
15 | hough_runner.set_blur_sigma(test_para[i][0]);
16 | hough_runner.set_threshold('h', test_para[i][1]);
17 | hough_runner.set_threshold('d', test_para[i][2]);
18 | hough_runner.set_threshold('g', test_para[i][3]);
19 |
20 | /*
21 | hough_runner.get_rgb2gray().display();
22 | hough_runner.get_gradient().display();
23 | hough_runner.get_hough_space().display();
24 | */
25 | CImg img = hough_runner.get_draw_lines();
26 | img.display();
27 | reverse_wrapping(img, hough_runner.get_intersection()).display();
28 |
29 | }
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/stdafx.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/imageWarpping/imageWarpping/stdafx.cpp
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/imageWarpping/imageWarpping/stdafx.h
--------------------------------------------------------------------------------
/imageWarpping/imageWarpping/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/imageWarpping/imageWarpping/targetver.h
--------------------------------------------------------------------------------
/noiseReduction/README.md:
--------------------------------------------------------------------------------
1 | 题目:http://www.imageprocessingplace.com/DIP-3E/dip3e_student_projects.htm#05-03
2 |
3 | 图片:http://www.imageprocessingplace.com/root_files_V3/image_databases.htm
4 |
5 | 主要内容:
6 |
7 | * Periodic noise reduction using a notch filter
8 | * Parametric Wiener filter
9 |
10 |
--------------------------------------------------------------------------------
/noiseReduction/addMotionBlur.m:
--------------------------------------------------------------------------------
1 | function [ output_f, H ] = addMotionBlur( input_f, T, a, b )
2 | %ADDMOTIONBLUR add motion blur
3 | % input_f & output_f 2-D image in frequency domain(centered), type single
4 | % H : motion blur degradation function in frequency domain, type single
5 | % T, a, b : H(u,v) =
6 | % (T/pi*(u*a+v*b))*sin(pi*(u*a+v*b))*exp(-1j*pi*(u*a+v*b))
7 | M = size(input_f,1)/2;
8 | N = size(input_f,2)/2;
9 | [U,V]=meshgrid(floor(-M+1):1:floor(M),floor(-N+1):1:floor(N));
10 | UV = pi.*(a.*U+b.*V);
11 | H = (T./UV).*sin(UV).*exp(-1j.*UV);
12 | [n,m] = find(isnan(H));
13 | for i = 1:length(n)
14 | H(n(i),m(i))=T;
15 | end
16 | output_f = single(H.*input_f);
17 | end
18 |
19 |
--------------------------------------------------------------------------------
/noiseReduction/addSinNoise.m:
--------------------------------------------------------------------------------
1 | function [ output_s ] = addSinNoise( input_s, A, u0, v0 )
2 | %addSinNoise add sin noise to input image
3 | % intut_s & output_s : 2-D image in spatial
4 | % u0, v0, A : noise = n(x,y) = A*sin(2*pi*(u0*x/M+v0*y/N))
5 | % A : the magnitude of noise
6 | % M : width of image (cols y)
7 | % N : height of image (rows x)
8 | M = size(input_s,1);
9 | N = size(input_s,2);
10 | x = 0:M-1;
11 | y = 0:N-1;
12 | [X,Y]=meshgrid(x,y);
13 | Noise = A*sin(2*pi*((u0/M).*X+(v0/N).*Y));
14 |
15 | output_s = single(input_s + Noise);
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/noiseReduction/computePSNR.m:
--------------------------------------------------------------------------------
1 | function [ psnr ] = computePSNR( input1_s,input2_s )
2 | %COMPUTEPSNR compute psnr
3 | % psnr(dB): Peak Signal-to-Noise Ratio between original and restored image
4 | % psnr between input1_s and input2_s
5 | % peak in gray picture is 255
6 | % higher psnr means higer quality
7 | if size(input1_s) ~= size(input2_s)
8 | error('two input must be equal size');
9 | end
10 | M = size(input1_s,1);
11 | N = size(input1_s,2);
12 | square_err = (input1_s-input2_s).^2;
13 | psnr = 10*log10((M*N*255*255)/sum(square_err(:)));
14 | end
15 |
16 |
--------------------------------------------------------------------------------
/noiseReduction/getSpacial.m:
--------------------------------------------------------------------------------
1 | function [ f ] = getSpacial( F )
2 | %GETSPACIAL Summary of this function goes here
3 | % Detailed explanation goes here
4 |
5 | %IDFT
6 | g = real(ifft2(F));
7 | %shift back
8 | P = size(F,1);
9 | Q = size(F,2);
10 | x = 0 : P-1;
11 | y = 0 : Q-1;
12 | [Y,X]=meshgrid(y,x);
13 | cshift = (ones(P, Q)*(-1)) .^(X+Y);
14 | g = g .* cshift;
15 | %cut
16 | f = g(1:size(F,1)/2,1:size(F,2)/2);
17 |
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/noiseReduction/getSpectrum.m:
--------------------------------------------------------------------------------
1 | function [ F] = getSpectrum( f )
2 | %GETSPECTRUM get spectrum in frequency domain move DC to center
3 | [P,Q]=size(f);
4 | %step1: padding
5 | g=[f;zeros(P,Q)];
6 | g=[g zeros(2*P,Q)];
7 | [P,Q]=size(g);
8 | %step2: shift
9 | x = 0 : P-1;
10 | y = 0 : Q-1;
11 | [Y,X]=meshgrid(y,x);
12 | cshift = (ones(P, Q)*(-1)) .^(X+Y);
13 | g2 = g .* cshift;
14 | %DTF
15 | F = fft2(g2);
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/noiseReduction/notchFiltering.m:
--------------------------------------------------------------------------------
1 | function [ output_f, Notch] = notchFiltering( input_f, D0, u0, v0)
2 | %NOTCHFILTERING filtering the input image in notch filter
3 | % intput_f & output_f : 2-D image in frequency domain(centered)
4 | % , type single range 0~1
5 | % Notch: notch reject filter in frequency domain(two-circle version)
6 | % D0, u0, v0: H(u,v) = 0 if D1(u,v) <= D0 or D2(u,v) <= D0
7 | % H(u,v) = 1 otherwise
8 | % D1(u,v) = sqrt((u-M/2-u0)^2 + (v-N/2-v0)^2)
9 | % D2(u,v) = sqrt((u-M/2+u0)^2 + (v-N/2+v0)^2)
10 | % M : width of image (cols y)
11 | % N : height of image (rows x)
12 | M = size(input_f,1);
13 | N = size(input_f,2);
14 | u = 0:M-1;
15 | v = 0:N-1;
16 | [U,V] = meshgrid(u,v);
17 | % symmetric in frequency domain
18 | % U-M/2,V-N/2 to move DC to orgin point
19 | D1 = (sqrt((U-M/2-u0).^2 + (V-N/2-v0).^2));
20 | D2 = (sqrt((U-M/2+u0).^2 + (V-N/2+v0).^2));
21 | Notch = and(D1 > D0, D2 > D0);
22 | output_f = single(input_f .* Notch);
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/noiseReduction/rescale.m:
--------------------------------------------------------------------------------
1 | function [ output ] = rescale( input )
2 | mx = max(input(:));
3 | mn = min(input(:));
4 | output = (input-mn)/(mx-mn);
5 | end
--------------------------------------------------------------------------------
/noiseReduction/script.m:
--------------------------------------------------------------------------------
1 | clear;
2 | f = imread('images/Fig0526a.tif', 'tif');
3 | f = im2single(f); % im2single map into 0~1
4 | g = addSinNoise(f,1,250,100);
5 | %G = getSpectrum(g);
6 | G = fft2(g);
7 | G = fftshift(G);
8 | imshow(rescale(log(1+abs(G))));
9 | F = fft2(f);
10 | F = fftshift(F);
11 | % why is double times?
12 | [G_f, Notch] = notchFiltering(G,10,250,100);
13 | f_s = ifft2(ifftshift(G_f));
14 |
15 | imwrite(im2uint8(g),'images/Fig0526b.tif','tif');
16 | imwrite(im2uint8(rescale(log(1+abs(F)))),'images/Fig0526c.tif','tif');
17 | imwrite(im2uint8(rescale(log(1+abs(G)))),'images/Fig0526d.tif','tif');
18 | imwrite(im2uint8(rescale(log(1+abs(G_f)))),'images/Fig0526e.tif','tif');
19 | imwrite(im2uint8(Notch),'images/Fig0526f.tif','tif');
20 | imwrite(im2uint8(f_s),'images/Fig0526g.tif','tif');
21 | psnr = computePSNR(f,f_s)
22 | T_f = getSpectrum(f_s);
23 | %imshow(rescale(log(1+abs(T_f))));
24 |
--------------------------------------------------------------------------------
/noiseReduction/script2.m:
--------------------------------------------------------------------------------
1 | clear;
2 | f = im2single(imread('images/Fig0526a.tif','tif'));
3 | F = fft2(f);
4 | F = fftshift(F);
5 | [G,H] = addMotionBlur(F,1,0.1,0.1);
6 | % not real part too big error
7 | g = ifft2(ifftshift(G));
8 | %gn = addSinNoise(g,10^-2,250,100);
9 | %gn = imnoise(g,'gaussian',0,10^-2);
10 | gn = g;
11 | Gn = fft2(gn);
12 | Gn = fftshift(Gn);
13 |
14 | G1 = wienerFiltering(Gn,H,10^-10);
15 | g1 = real(ifft2(ifftshift(G1)));
16 | psnr1 = computePSNR(g1,f);
17 |
18 | G2 = wienerFiltering(Gn,H,10^-23);
19 | g2 = real(ifft2(ifftshift(G2)));
20 | psnr2 = computePSNR(g2,f);
21 |
22 | G3 = wienerFiltering(Gn,H,0);
23 | g3 = real(ifft2(ifftshift(G3)));
24 | psnr3 = computePSNR(g3,f);
25 |
26 | imwrite(im2uint8(real(g)),'images/Fig0526-2b.tif','tif');
27 | imwrite(im2uint8(real(gn)),'images/Fig0526-2bn.tif','tif');
28 | imwrite(im2uint8(g1),'images/Fig0526-1.tif','tif');
29 | imwrite(im2uint8(g2),'images/Fig0526-2.tif','tif');
30 | imwrite(im2uint8(g3),'images/Fig0526-3.tif','tif');
31 | imwrite(im2uint8(rescale(log(1+abs(Gn)))),'images/gaussian.tif','tif');
--------------------------------------------------------------------------------
/noiseReduction/sine.m:
--------------------------------------------------------------------------------
1 | Amp = 1;
2 | freqHz = 12000;
3 | fsHz = 65536;
4 | dt = 1/fsHz;
5 | index = 1;
6 | sines = [];
7 | sampleNumber = [];
8 | for t = 0:dt:1-dt
9 | sines(index) = Amp * sin(2*pi*freqHz*t);
10 | sampleNumber(index) = index;
11 | index = index + 1;
12 | end
13 |
14 | % alternative to the above loop
15 | % sine = Amp*sin(2*pi*freq*(0:dt:1-dt));
16 |
17 | N = 65536;
18 | transform = fft(sines,N)/N;
19 | magTransform = abs(transform);
20 |
21 | faxis = linspace(-fsHz/2,fsHz/2,N);
22 | plot(faxis/1000,fftshift(magTransform));
23 | axis([-40 40 0 0.6])
24 | xlabel('Frequency (KHz)')
--------------------------------------------------------------------------------
/noiseReduction/wienerFiltering.m:
--------------------------------------------------------------------------------
1 | function [ output_f ] = wienerFiltering( input_f,H,K )
2 | %wienerFiltering: filtering by winner filter
3 | % input_f & output_f 2-D image in frequency domain(centered), type single
4 | % H : motion blur degradation function in frequency domain, type single
5 | % K : winner filter parameter
6 | % W : winner filter
7 | H_a = (H).^2;
8 | W = (1./H).*(H_a./(H_a+K));
9 | output_f = single(W.*input_f);
10 | end
11 |
12 |
--------------------------------------------------------------------------------
/noiseReduction/~$057057_lab4.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/noiseReduction/~$057057_lab4.docx
--------------------------------------------------------------------------------
/zoom_and_shrink/README.md:
--------------------------------------------------------------------------------
1 | 題目:
2 |
3 | http://www.imageprocessingplace.com/DIP-3E/dip3e_student_projects.htm
4 |
5 | 圖片:
6 |
7 | http://www.imageprocessingplace.com/DIP-3E/dip3e_book_images_downloads.htm
8 |
9 |
10 |
11 | ##### Proj 02-03 像素複製方法(最近鄰內插法)
12 |
13 | 代碼放在pixel_replication文件夾中,所使用到的圖片放在images文件夾中,直接運行test.m文件可以得到三張圖片。其中originalImage為原圖片,resizedImage為縮小后的圖片,recovered為縮小后又放大的圖片。
14 |
15 | 函數在pixel_replication.m中實現
16 |
17 | ##### Proj 02-04 雙線性內插法
18 |
19 | 代碼放在bilinear_interpolation文件夾中,所使用到的圖片放在images文件夾中,直接運行test.m文件可以得到三張圖片。其中originalImage為原圖片,resizedImage為縮小后的圖片,recovered為縮小后又放大的圖片。
20 |
21 | 函數在bilinear_interpolation.m中實現
--------------------------------------------------------------------------------
/zoom_and_shrink/bilinear_interpolation/resizeImage_bilinear.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/zoom_and_shrink/bilinear_interpolation/resizeImage_bilinear.m
--------------------------------------------------------------------------------
/zoom_and_shrink/bilinear_interpolation/test.m:
--------------------------------------------------------------------------------
1 | % read the original image
2 | originalImage = imread('../images/Fig0220(a).tif');
3 | figure(1)
4 | imshow(originalImage)
5 | title('original image')
6 |
7 | resizedImage = resizeImage_bilinear(originalImage, 1/12.5);
8 | figure(2)
9 | imshow(resizedImage)
10 | title('resized image')
11 |
12 | recovered = resizeImage_bilinear(resizedImage, 12.5);
13 | figure(3)
14 | imshow(recovered)
15 | title('recovered image')
--------------------------------------------------------------------------------
/zoom_and_shrink/pixel_replication/resizeImage_replication.m:
--------------------------------------------------------------------------------
1 | function [resizedImage] = resizeImage_replication(originalImage,scaleFactor)
2 | % Zooming and Shrinking Images by Pixel Replication
3 | if scaleFactor <= 0
4 | error('Error. ScaleFactor must positive')
5 | end
6 | % size of original image
7 | [row, col] = size(originalImage);
8 | resizedImage = [];
9 | for i = 1 : (row*scaleFactor)
10 | for j= 1 : (col*scaleFactor)
11 | x = round(i/scaleFactor);
12 | y = round(j/scaleFactor);
13 | if x == 0
14 | x = 1;
15 | end
16 | if y == 0
17 | y = 1;
18 | end
19 | resizedImage(i,j)=originalImage(x,y);
20 | end
21 | end
22 | % matlab's function imshow support double and uint8,
23 | % while double range is 0~1 so we change it to uint whose range is 0~255
24 | resizedImage = uint8(resizedImage);
25 | end
26 |
27 |
--------------------------------------------------------------------------------
/zoom_and_shrink/pixel_replication/resizeImage_replication.m~:
--------------------------------------------------------------------------------
1 | function [resizedImage] = resizeImage_replication(originalImage,scaleFactor)
2 | % Zooming and Shrinking Images by Pixel Replication
3 | if scaleFactor <= 0
4 | error('Error. ScaleFactor must positive')
5 | end
6 | % size of original image
7 | [row, col] = size(originalImage);
8 | resizedImage = zeros(row, col);
9 | for i = 1 : (row*scaleFactor)
10 | for j= 1 : (col*scaleFactor)
11 | resizedImage(i,j)=originalImage(i/scaleFactor), j/scaleFactor));
12 | end
13 | end
14 |
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/zoom_and_shrink/pixel_replication/test.m:
--------------------------------------------------------------------------------
1 | % read the original image
2 | originalImage = imread('../images/Fig0220(a).tif');
3 | figure(1)
4 | imshow(originalImage)
5 | title('original image')
6 |
7 | resizedImage = resizeImage_replication(originalImage, 1/10);
8 | figure(2)
9 | imshow(resizedImage)
10 | title('resized image')
11 |
12 | recovered = resizeImage_replication(resizedImage, 10);
13 | figure(3)
14 | imshow(recovered)
15 | title('recovered image')
--------------------------------------------------------------------------------
/zoom_and_shrink/pixel_replication/test.m~:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kinpzz/computerVision/b0cbbeadc955e64d07787f7b1b946365b4347f68/zoom_and_shrink/pixel_replication/test.m~
--------------------------------------------------------------------------------