├── .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 | ![](https://ws1.sinaimg.cn/large/6177e8b1gy1fevonc859gg208w05017k.gif) 10 | 11 | 其实实现的原理很简单,就是对两张图片每个像素点按一定的比例进行混合。通过以下的公式来对每个像素点进行融合。 12 | 13 | $$ M(x,y) = (1-\alpha)I(x,y) + \alpha J(x,y)$$ 14 | 15 | 其中$$\alpha$$代表了图片J所占比重。但是,如果对两张图片进行融合的话会出现一个问题,就是五官的位置并没有对齐,会出现奇怪的效果,如下图参考1中所展示的图片的问题。会发现效果并不是很好,只是两张图片单纯的叠加。 16 | 17 | ![](https://ws1.sinaimg.cn/large/6177e8b1gy1fexljkov27j20qq0buk7w.jpg) 18 | 19 | 这次实验的主要内容,就是介绍如何进行比较和谐的一种融合效果,已经将多张不同比重融合的图片所组成的一个人脸变换过程。 20 | 21 | ## 实现 22 | 23 | ### 实验环境 24 | 25 | Windows 10、Visual Studio 2015、CImg图像处理库 26 | 27 | ### 实验数据 28 | 29 | ![](https://ws1.sinaimg.cn/large/6177e8b1gy1fexn2sh0hdj20ys0mu7wh.jpg) 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 | ![](https://ws1.sinaimg.cn/large/6177e8b1gy1fexnir9ud1j20w80lc1kx.jpg) 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 | ![](https://ws1.sinaimg.cn/large/6177e8b1gy1fez20cah7hj20ty0je1kx.jpg) 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 | ![](https://ws1.sinaimg.cn/large/6177e8b1gy1fez32vqseuj20vg0atq40.jpg) 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~ --------------------------------------------------------------------------------