├── ETF.cpp ├── ETF.h ├── FDOG.pro ├── FDOG.pro.user ├── FDOG.v11.suo ├── README.md ├── a.jpg ├── b.jpg ├── c.jpg ├── d.jpg ├── example.jpg ├── fdog.cpp ├── fdog.h ├── imatrix.h ├── main.cpp └── myvec.h /ETF.cpp: -------------------------------------------------------------------------------- 1 | #include "ETF.h" 2 | #include "imatrix.h" 3 | #include 4 | 5 | /** 6 | * @brief ETF::set // get flows from input image 7 | * @param image //输入图片矩阵 8 | */ 9 | void ETF::set(imatrix& image) 10 | { 11 | int i, j; 12 | double MAX_VAL = 1020.; 13 | double v[2]; 14 | 15 | max_grad = -1.; 16 | 17 | //sobel operator 18 | for (i = 1; i < Nr - 1; i++) { 19 | for (j = 1; j < Nc - 1; j++) { 20 | //////////////////////////////////////////////////////////////// 21 | p[i][j].tx = (image[i+1][j-1] + 2*(double)image[i+1][j] + image[i+1][j+1] 22 | - image[i-1][j-1] - 2*(double)image[i-1][j] - image[i-1][j+1]) / MAX_VAL; 23 | p[i][j].ty = (image[i-1][j+1] + 2*(double)image[i][j+1] + image[i+1][j+1] 24 | - image[i-1][j-1] - 2*(double)image[i][j-1] - image[i+1][j-1]) / MAX_VAL; 25 | ///////////////////////////////////////////// 26 | v[0] = p[i][j].tx; 27 | v[1] = p[i][j].ty; 28 | p[i][j].tx = -v[1]; 29 | p[i][j].ty = v[0]; 30 | ////////////////////////////////////////////// 31 | p[i][j].mag = sqrt(p[i][j].tx * p[i][j].tx + p[i][j].ty * p[i][j].ty); 32 | 33 | if (p[i][j].mag > max_grad) { 34 | max_grad = p[i][j].mag; 35 | } 36 | } 37 | } 38 | 39 | //处理边界 40 | for (i = 1; i <= Nr - 2; i++) { 41 | p[i][0].tx = p[i][1].tx; 42 | p[i][0].ty = p[i][1].ty; 43 | p[i][0].mag = p[i][1].mag; 44 | p[i][Nc - 1].tx = p[i][Nc - 2].tx; 45 | p[i][Nc - 1].ty = p[i][Nc - 2].ty; 46 | p[i][Nc - 1].mag = p[i][Nc - 2].mag; 47 | } 48 | 49 | for (j = 1; j <= Nc - 2; j++) { 50 | p[0][j].tx = p[1][j].tx; 51 | p[0][j].ty = p[1][j].ty; 52 | p[0][j].mag = p[1][j].mag; 53 | p[Nr - 1][j].tx = p[Nr - 2][j].tx; 54 | p[Nr - 1][j].ty = p[Nr - 2][j].ty; 55 | p[Nr - 1][j].mag = p[Nr - 2][j].mag; 56 | } 57 | 58 | //处理四个角 59 | p[0][0].tx = ( p[0][1].tx + p[1][0].tx ) / 2; 60 | p[0][0].ty = ( p[0][1].ty + p[1][0].ty ) / 2; 61 | p[0][0].mag = ( p[0][1].mag + p[1][0].mag ) / 2; 62 | p[0][Nc-1].tx = ( p[0][Nc-2].tx + p[1][Nc-1].tx ) / 2; 63 | p[0][Nc-1].ty = ( p[0][Nc-2].ty + p[1][Nc-1].ty ) / 2; 64 | p[0][Nc-1].mag = ( p[0][Nc-2].mag + p[1][Nc-1].mag ) / 2; 65 | p[Nr-1][0].tx = ( p[Nr-1][1].tx + p[Nr-2][0].tx ) / 2; 66 | p[Nr-1][0].ty = ( p[Nr-1][1].ty + p[Nr-2][0].ty ) / 2; 67 | p[Nr-1][0].mag = ( p[Nr-1][1].mag + p[Nr-2][0].mag ) / 2; 68 | p[Nr - 1][Nc - 1].tx = ( p[Nr - 1][Nc - 2].tx + p[Nr - 2][Nc - 1].tx ) / 2; 69 | p[Nr - 1][Nc - 1].ty = ( p[Nr - 1][Nc - 2].ty + p[Nr - 2][Nc - 1].ty ) / 2; 70 | p[Nr - 1][Nc - 1].mag = ( p[Nr - 1][Nc - 2].mag + p[Nr - 2][Nc - 1].mag ) / 2; 71 | 72 | normalize(); 73 | 74 | } 75 | 76 | /** 77 | * @brief ETF::set2 //transform input image to flow map ,then further get flow from magnitude map of previous flow 78 | * @param image 79 | */ 80 | void ETF::set2(imatrix& image) 81 | { 82 | int i, j; 83 | double MAX_VAL = 1020.; 84 | double v[2]; 85 | 86 | max_grad = -1.; 87 | 88 | imatrix tmp(Nr, Nc); 89 | 90 | //transform input image to gradients map 91 | for (i = 1; i < Nr - 1; i++) { 92 | for (j = 1; j < Nc - 1; j++) { 93 | //////////////////////////////////////////////////////////////// 94 | p[i][j].tx = (image[i+1][j-1] + 2*(double)image[i+1][j] + image[i+1][j+1] 95 | - image[i-1][j-1] - 2*(double)image[i-1][j] - image[i-1][j+1]) / MAX_VAL; 96 | p[i][j].ty = (image[i-1][j+1] + 2*(double)image[i][j+1] + image[i+1][j+1] 97 | - image[i-1][j-1] - 2*(double)image[i][j-1] - image[i+1][j-1]) / MAX_VAL; 98 | ///////////////////////////////////////////// 99 | v[0] = p[i][j].tx; 100 | v[1] = p[i][j].ty; 101 | ////////////////////////////////////////////// 102 | tmp[i][j] = sqrt(p[i][j].tx * p[i][j].tx + p[i][j].ty * p[i][j].ty); 103 | 104 | if (tmp[i][j] > max_grad) { 105 | max_grad = tmp[i][j]; 106 | } 107 | } 108 | } 109 | 110 | for (i = 1; i <= Nr - 2; i++) { 111 | tmp[i][0] = tmp[i][1]; 112 | tmp[i][Nc - 1] = tmp[i][Nc - 2]; 113 | } 114 | 115 | for (j = 1; j <= Nc - 2; j++) { 116 | tmp[0][j] = tmp[1][j]; 117 | tmp[Nr - 1][j] = tmp[Nr - 2][j]; 118 | } 119 | 120 | tmp[0][0] = ( tmp[0][1] + tmp[1][0] ) / 2; 121 | tmp[0][Nc-1] = ( tmp[0][Nc-2] + tmp[1][Nc-1] ) / 2; 122 | tmp[Nr-1][0] = ( tmp[Nr-1][1] + tmp[Nr-2][0] ) / 2; 123 | tmp[Nr - 1][Nc - 1] = ( tmp[Nr - 1][Nc - 2] + tmp[Nr - 2][Nc - 1] ) / 2; 124 | 125 | imatrix gmag(Nr, Nc); 126 | 127 | // normalize the magnitude 128 | for (i = 0; i < Nr; i++) { 129 | for (j = 0; j < Nc; j++) { 130 | tmp[i][j] /= max_grad; 131 | gmag[i][j] = round(tmp[i][j] * 255.0); 132 | } 133 | } 134 | 135 | // get gradients from gradient map 136 | for (i = 1; i < Nr - 1; i++) { 137 | for (j = 1; j < Nc - 1; j++) { 138 | //////////////////////////////////////////////////////////////// 139 | p[i][j].tx = (gmag[i+1][j-1] + 2*(double)gmag[i+1][j] + gmag[i+1][j+1] 140 | - gmag[i-1][j-1] - 2*(double)gmag[i-1][j] - gmag[i-1][j+1]) / MAX_VAL; 141 | p[i][j].ty = (gmag[i-1][j+1] + 2*(double)gmag[i][j+1] + gmag[i+1][j+1] 142 | - gmag[i-1][j-1] - 2*(double)gmag[i][j-1] - gmag[i+1][j-1]) / MAX_VAL; 143 | ///////////////////////////////////////////// 144 | v[0] = p[i][j].tx; 145 | v[1] = p[i][j].ty; 146 | p[i][j].tx = -v[1]; 147 | p[i][j].ty = v[0]; 148 | ////////////////////////////////////////////// 149 | p[i][j].mag = sqrt(p[i][j].tx * p[i][j].tx + p[i][j].ty * p[i][j].ty); 150 | 151 | if (p[i][j].mag > max_grad) { 152 | max_grad = p[i][j].mag; 153 | } 154 | } 155 | } 156 | 157 | for (i = 1; i <= Nr - 2; i++) { 158 | p[i][0].tx = p[i][1].tx; 159 | p[i][0].ty = p[i][1].ty; 160 | p[i][0].mag = p[i][1].mag; 161 | p[i][Nc - 1].tx = p[i][Nc - 2].tx; 162 | p[i][Nc - 1].ty = p[i][Nc - 2].ty; 163 | p[i][Nc - 1].mag = p[i][Nc - 2].mag; 164 | } 165 | 166 | for (j = 1; j <= Nc - 2; j++) { 167 | p[0][j].tx = p[1][j].tx; 168 | p[0][j].ty = p[1][j].ty; 169 | p[0][j].mag = p[1][j].mag; 170 | p[Nr - 1][j].tx = p[Nr - 2][j].tx; 171 | p[Nr - 1][j].ty = p[Nr - 2][j].ty; 172 | p[Nr - 1][j].mag = p[Nr - 2][j].mag; 173 | } 174 | 175 | p[0][0].tx = ( p[0][1].tx + p[1][0].tx ) / 2; 176 | p[0][0].ty = ( p[0][1].ty + p[1][0].ty ) / 2; 177 | p[0][0].mag = ( p[0][1].mag + p[1][0].mag ) / 2; 178 | p[0][Nc-1].tx = ( p[0][Nc-2].tx + p[1][Nc-1].tx ) / 2; 179 | p[0][Nc-1].ty = ( p[0][Nc-2].ty + p[1][Nc-1].ty ) / 2; 180 | p[0][Nc-1].mag = ( p[0][Nc-2].mag + p[1][Nc-1].mag ) / 2; 181 | p[Nr-1][0].tx = ( p[Nr-1][1].tx + p[Nr-2][0].tx ) / 2; 182 | p[Nr-1][0].ty = ( p[Nr-1][1].ty + p[Nr-2][0].ty ) / 2; 183 | p[Nr-1][0].mag = ( p[Nr-1][1].mag + p[Nr-2][0].mag ) / 2; 184 | p[Nr - 1][Nc - 1].tx = ( p[Nr - 1][Nc - 2].tx + p[Nr - 2][Nc - 1].tx ) / 2; 185 | p[Nr - 1][Nc - 1].ty = ( p[Nr - 1][Nc - 2].ty + p[Nr - 2][Nc - 1].ty ) / 2; 186 | p[Nr - 1][Nc - 1].mag = ( p[Nr - 1][Nc - 2].mag + p[Nr - 2][Nc - 1].mag ) / 2; 187 | 188 | normalize(); 189 | } 190 | 191 | 192 | inline void make_unit(double& vx, double& vy) 193 | { 194 | double mag = sqrt( vx*vx + vy*vy ); 195 | if (mag != 0.0) { 196 | vx /= mag; 197 | vy /= mag; 198 | } 199 | } 200 | 201 | void ETF::normalize() 202 | { 203 | int i, j; 204 | 205 | for (i = 0; i < Nr; i++) { 206 | for (j = 0; j < Nc; j++) { 207 | make_unit(p[i][j].tx, p[i][j].ty); 208 | p[i][j].mag /= max_grad; 209 | } 210 | } 211 | } 212 | 213 | /** 214 | * @brief ETF::Smooth // The ETF construction filter, with acceleration 215 | * @param half_w // kernel大小的一半 216 | * @param M // 迭代次数 217 | */ 218 | 219 | void ETF::Smooth(int half_w, int M) 220 | { 221 | int i, j, k; 222 | int MAX_GRADIENT = -1; 223 | double weight; 224 | int s, t; 225 | int x, y; 226 | double mag_diff; 227 | 228 | int image_x = getRow(); 229 | int image_y = getCol(); 230 | 231 | ETF e2; 232 | 233 | e2.init(image_x, image_y); 234 | e2.copy(*this); 235 | 236 | double v[2], w[2], g[2]; 237 | double angle; 238 | double factor; 239 | 240 | //迭代M次,加速算法 241 | for (k = 0; k < M; k++) { 242 | //////////////////////// 243 | // horizontal 244 | for (j = 0; j < image_y; j++) { 245 | for (i = 0; i < image_x; i++) { 246 | g[0] = g[1] = 0.0; 247 | v[0] = p[i][j].tx; 248 | v[1] = p[i][j].ty; 249 | for (s = -half_w; s <= half_w; s++) { 250 | //////////////////////////////////////// 251 | x = i+s; y = j; //这里决定了水平还是竖直 252 | if (x > image_x-1) x = image_x-1; 253 | else if (x < 0) x = 0; 254 | if (y > image_y-1) y = image_y-1; 255 | else if (y < 0) y = 0; 256 | //////////////////////////////////////// 257 | mag_diff = p[x][y].mag - p[i][j].mag; 258 | ////////////////////////////////////////////////////// 259 | w[0] = p[x][y].tx; 260 | w[1] = p[x][y].ty; 261 | //////////////////////////////// 262 | factor = 1.0; //Fai(x,y) 263 | angle = v[0] * w[0] + v[1] * w[1]; 264 | if (angle < 0.0) { 265 | factor = -1.0; 266 | } 267 | weight = mag_diff + 1; //Wm(x,y),没有除以2 268 | ////////////////////////////////////////////////////// 269 | g[0] += weight * p[x][y].tx * factor; //没有乘以Wd(x,y) 270 | g[1] += weight * p[x][y].ty * factor; 271 | } 272 | make_unit(g[0], g[1]); 273 | e2[i][j].tx = g[0]; 274 | e2[i][j].ty = g[1]; 275 | } 276 | } 277 | this->copy(e2); 278 | ///////////////////////////////// 279 | // vertical 280 | for (j = 0; j < image_y; j++) { 281 | for (i = 0; i < image_x; i++) { 282 | g[0] = g[1] = 0.0; 283 | v[0] = p[i][j].tx; 284 | v[1] = p[i][j].ty; 285 | for (t = -half_w; t <= half_w; t++) { 286 | //////////////////////////////////////// 287 | x = i; y = j+t; //只有这里不同 288 | if (x > image_x-1) x = image_x-1; 289 | else if (x < 0) x = 0; 290 | if (y > image_y-1) y = image_y-1; 291 | else if (y < 0) y = 0; 292 | //////////////////////////////////////// 293 | mag_diff = p[x][y].mag - p[i][j].mag; 294 | ////////////////////////////////////////////////////// 295 | w[0] = p[x][y].tx; 296 | w[1] = p[x][y].ty; 297 | //////////////////////////////// 298 | factor = 1.0; 299 | /////////////////////////////// 300 | angle = v[0] * w[0] + v[1] * w[1]; 301 | if (angle < 0.0) factor = -1.0; 302 | ///////////////////////////////////////////////////////// 303 | weight = mag_diff + 1; 304 | ////////////////////////////////////////////////////// 305 | g[0] += weight * p[x][y].tx * factor; 306 | g[1] += weight * p[x][y].ty * factor; 307 | } 308 | make_unit(g[0], g[1]); 309 | e2[i][j].tx = g[0]; 310 | e2[i][j].ty = g[1]; 311 | } 312 | } 313 | this->copy(e2); 314 | } 315 | //////////////////////////////////////////// 316 | } 317 | -------------------------------------------------------------------------------- /ETF.h: -------------------------------------------------------------------------------- 1 | #ifndef _ETF_H_ 2 | #define _ETF_H_ 3 | 4 | #include "imatrix.h" 5 | #define round(x) ((int) ((x) + 0.5)) 6 | 7 | struct Vect { 8 | double tx, ty, mag; 9 | }; 10 | 11 | 12 | class ETF { 13 | private: 14 | int Nr, Nc; 15 | Vect** p; 16 | double max_grad; 17 | public: 18 | ETF() 19 | { 20 | Nr = 1, Nc = 1; 21 | p = new Vect*[Nr]; 22 | for(int i = 0; i < Nr; i++) 23 | p[i] = new Vect[Nc]; 24 | p[0][0].tx=1.0; p[0][0].ty=0.0; p[0][0].mag=1.0; 25 | max_grad = 1.0; 26 | }; 27 | ETF(int i, int j) 28 | { 29 | Nr = i, Nc = j; 30 | p = new Vect*[Nr]; 31 | for(i = 0; i < Nr; i++) 32 | p[i] = new Vect[Nc]; 33 | max_grad = 1.0; 34 | }; 35 | void delete_all() { 36 | for (int i = 0; i < Nr; i++) 37 | delete[] p[i]; 38 | delete[] p; 39 | } 40 | ~ETF() { delete_all(); } 41 | Vect* operator[](int i) { return p[i]; }; 42 | Vect& get( int i, int j ) const { return p[i][j]; } 43 | int getRow() const { return Nr; } 44 | int getCol() const { return Nc; } 45 | void init(int i, int j) 46 | { 47 | delete_all(); 48 | Nr = i, Nc = j; 49 | p = new Vect*[Nr]; 50 | for(i = 0; i < Nr; i++) 51 | p[i] = new Vect[Nc]; 52 | max_grad = 1.0; 53 | }; 54 | void copy(ETF& s) 55 | { 56 | for (int i = 0; i < Nr; i++) 57 | for (int j = 0; j < Nc; j++) { 58 | p[i][j].tx = s.p[i][j].tx; 59 | p[i][j].ty = s.p[i][j].ty; 60 | p[i][j].mag = s.p[i][j].mag; 61 | } 62 | max_grad = s.max_grad; 63 | }; 64 | void zero() 65 | { 66 | for (int i = 0; i < Nr; i++) 67 | for (int j = 0; j < Nc; j++) 68 | p[i][j].tx = p[i][j].ty = p[i][j].mag = 0.0; 69 | } 70 | 71 | /** 72 | * @brief ETF::set // get flows from input image 73 | * @param image //输入图片矩阵 74 | */ 75 | void set(imatrix& image); 76 | 77 | /** 78 | * @brief ETF::set2 //transform input image to flow map ,then further get flow from magnitude map of previous flow 79 | * @param image 80 | */ 81 | void set2(imatrix& image); 82 | 83 | /** 84 | * @brief ETF::Smooth // The ETF construction filter, with acceleration 85 | * @param half_w // kernel大小的一半 86 | * @param M // 迭代次数 87 | */ 88 | void Smooth(int half_w, int M); 89 | 90 | double GetMaxGrad() { return max_grad; } 91 | void normalize(); 92 | }; 93 | 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /FDOG.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-05-02T02:44:38 4 | # 5 | #------------------------------------------------- 6 | 7 | #QT += core 8 | 9 | #QT -= gui 10 | 11 | TARGET = FDOG 12 | CONFIG += console 13 | CONFIG -= app_bundle 14 | 15 | TEMPLATE = app 16 | 17 | 18 | SOURCES += main.cpp \ 19 | ETF.cpp \ 20 | fdog.cpp 21 | 22 | HEADERS += \ 23 | ETF.h \ 24 | fdog.h \ 25 | imatrix.h \ 26 | myvec.h 27 | 28 | INCLUDEPATH += C:/Opencv/include 29 | 30 | LIBS += -LC:/Opencv/lib/ \ 31 | -lopencv_core2410 \ 32 | -lopencv_highgui2410 \ 33 | -lopencv_imgproc2410d 34 | -------------------------------------------------------------------------------- /FDOG.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {6aa434a6-f676-473e-89fc-f91417282ab4} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | 0 45 | 8 46 | true 47 | 1 48 | true 49 | true 50 | true 51 | false 52 | 53 | 54 | 55 | ProjectExplorer.Project.PluginSettings 56 | 57 | 58 | 59 | ProjectExplorer.Project.Target.0 60 | 61 | Desktop Qt 5.4.0 MSVC2012 OpenGL 32bit 62 | Desktop Qt 5.4.0 MSVC2012 OpenGL 32bit 63 | qt.54.win32_msvc2012_opengl_kit 64 | 0 65 | 0 66 | 0 67 | 68 | C:/Workspaces/QT/build-FDOG-Desktop_Qt_5_4_0_MSVC2012_OpenGL_32bit-Debug 69 | 70 | 71 | true 72 | qmake 73 | 74 | QtProjectManager.QMakeBuildStep 75 | false 76 | true 77 | 78 | false 79 | false 80 | 81 | 82 | true 83 | Make 84 | 85 | Qt4ProjectManager.MakeStep 86 | 87 | false 88 | 89 | 90 | 91 | 2 92 | 构建 93 | 94 | ProjectExplorer.BuildSteps.Build 95 | 96 | 97 | 98 | true 99 | Make 100 | 101 | Qt4ProjectManager.MakeStep 102 | 103 | true 104 | clean 105 | 106 | 107 | 1 108 | 清理 109 | 110 | ProjectExplorer.BuildSteps.Clean 111 | 112 | 2 113 | false 114 | 115 | Debug 116 | 117 | Qt4ProjectManager.Qt4BuildConfiguration 118 | 2 119 | true 120 | 121 | 122 | C:/Workspaces/QT/build-FDOG-Desktop_Qt_5_4_0_MSVC2012_OpenGL_32bit-Release 123 | 124 | 125 | true 126 | qmake 127 | 128 | QtProjectManager.QMakeBuildStep 129 | false 130 | true 131 | 132 | false 133 | false 134 | 135 | 136 | true 137 | Make 138 | 139 | Qt4ProjectManager.MakeStep 140 | 141 | false 142 | 143 | 144 | 145 | 2 146 | 构建 147 | 148 | ProjectExplorer.BuildSteps.Build 149 | 150 | 151 | 152 | true 153 | Make 154 | 155 | Qt4ProjectManager.MakeStep 156 | 157 | true 158 | clean 159 | 160 | 161 | 1 162 | 清理 163 | 164 | ProjectExplorer.BuildSteps.Clean 165 | 166 | 2 167 | false 168 | 169 | Release 170 | 171 | Qt4ProjectManager.Qt4BuildConfiguration 172 | 0 173 | true 174 | 175 | 2 176 | 177 | 178 | 0 179 | 部署 180 | 181 | ProjectExplorer.BuildSteps.Deploy 182 | 183 | 1 184 | 在本地部署 185 | 186 | ProjectExplorer.DefaultDeployConfiguration 187 | 188 | 1 189 | 190 | 191 | 192 | false 193 | false 194 | false 195 | false 196 | true 197 | 0.01 198 | 10 199 | true 200 | 1 201 | 25 202 | 203 | 1 204 | true 205 | false 206 | true 207 | valgrind 208 | 209 | 0 210 | 1 211 | 2 212 | 3 213 | 4 214 | 5 215 | 6 216 | 7 217 | 8 218 | 9 219 | 10 220 | 11 221 | 12 222 | 13 223 | 14 224 | 225 | 2 226 | 227 | FDOG 228 | 229 | Qt4ProjectManager.Qt4RunConfiguration:C:/Workspaces/QT/FDOG/FDOG.pro 230 | %{sourceDir}\c.jpg 231 | FDOG.pro 232 | false 233 | true 234 | 235 | 3768 236 | false 237 | true 238 | false 239 | false 240 | true 241 | 242 | 1 243 | 244 | 245 | 246 | ProjectExplorer.Project.TargetCount 247 | 1 248 | 249 | 250 | ProjectExplorer.Project.Updater.FileVersion 251 | 18 252 | 253 | 254 | Version 255 | 18 256 | 257 | 258 | -------------------------------------------------------------------------------- /FDOG.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springzfx/FDOG/2063614bcdc550cb758520043ad62a68d471dae6/FDOG.v11.suo -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #FDOG(Flow-based DoG) 2 | this repository is a implement of `Kang H, Lee S, Chui C K. Flow-Based Image Abstraction[J]. IEEE Transactions on Visualization & Computer Graphics, 2009, 15(1):62-76.` 3 | 4 | 5 | #Envirnment 6 | to run this project, [QT and openCV](http://blog.csdn.net/springzfx/article/details/44019917) is needed. You may need to modify the `.pro' file to adapt your envirnment. 7 | ```c++ 8 | INCLUDEPATH += C:/Opencv/include 9 | 10 | LIBS += -LC:/Opencv/lib/ \ 11 | -lopencv_core2410 \ 12 | -lopencv_highgui2410 \ 13 | -lopencv_imgproc2410d 14 | ``` 15 | 16 | 17 | #Attention 18 | * I only use openCV to achieve image input and output in the `main.cpp`. So you can change it if you don't have openCV installed. 19 | 20 | * This project don't use any widget of QT, So you can transplant code to other IDEs(like,visual studio) easily. 21 | 22 | * Major code of this project is provided by my DIP teacher. I think the code may originally comes from the paper author. I'm not sure. 23 | 24 | 25 | #Example 26 | ![example](https://github.com/springzfx/FDOG/blob/master/example.jpg) -------------------------------------------------------------------------------- /a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springzfx/FDOG/2063614bcdc550cb758520043ad62a68d471dae6/a.jpg -------------------------------------------------------------------------------- /b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springzfx/FDOG/2063614bcdc550cb758520043ad62a68d471dae6/b.jpg -------------------------------------------------------------------------------- /c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springzfx/FDOG/2063614bcdc550cb758520043ad62a68d471dae6/c.jpg -------------------------------------------------------------------------------- /d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springzfx/FDOG/2063614bcdc550cb758520043ad62a68d471dae6/d.jpg -------------------------------------------------------------------------------- /example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springzfx/FDOG/2063614bcdc550cb758520043ad62a68d471dae6/example.jpg -------------------------------------------------------------------------------- /fdog.cpp: -------------------------------------------------------------------------------- 1 | //#include "stdafx.h" 2 | #include 3 | 4 | #include "fdog.h" 5 | #include "myvec.h" 6 | #include "imatrix.h" 7 | 8 | #define ABS(x) ( ((x)>0) ? (x) : (-(x)) ) 9 | #define round(x) ((int) ((x) + 0.5)) 10 | #define PI 3.1415926 11 | 12 | inline double gauss(double x, double mean, double sigma) 13 | { 14 | return ( exp( (-(x-mean)*(x-mean)) / (2*sigma*sigma) ) / sqrt(PI * 2.0 * sigma * sigma) ); 15 | } 16 | 17 | void MakeGaussianVector(double sigma, myvec& GAU) 18 | { 19 | int i, j; 20 | 21 | double threshold = 0.001; 22 | 23 | i = 0; 24 | while(1) { 25 | i++; 26 | if ( gauss((double)i, 0.0, sigma) < threshold ) 27 | break; 28 | } 29 | GAU.init(i+1); 30 | GAU.zero(); 31 | 32 | GAU[0] = gauss((double)0.0, 0.0, sigma); 33 | for (j = 1; j < GAU.getMax(); j++) { 34 | GAU[j] = gauss((double)j, 0.0, sigma); 35 | } 36 | } 37 | 38 | void GetDirectionalDoG(imatrix& image, ETF& e, mymatrix& dog, myvec& GAU1, myvec& GAU2, double tau) 39 | { 40 | myvec vn(2); 41 | double x, y, d_x, d_y; 42 | double weight1, weight2, w_sum1, sum1, sum2, w_sum2; 43 | 44 | int s; 45 | int x1, y1; 46 | int i, j; 47 | int dd; 48 | double val; 49 | 50 | int half_w1, half_w2; 51 | 52 | half_w1 = GAU1.getMax()-1; 53 | half_w2 = GAU2.getMax()-1; 54 | 55 | int image_x, image_y; 56 | 57 | image_x = image.getRow(); 58 | image_y = image.getCol(); 59 | 60 | for (i = 0; i < image_x; i++) { 61 | for (j = 0; j < image_y; j++) { 62 | sum1 = sum2 = 0.0; 63 | w_sum1 = w_sum2 = 0.0; 64 | weight1 = weight2 = 0.0; 65 | 66 | vn[0] = -e[i][j].ty; 67 | vn[1] = e[i][j].tx; 68 | 69 | if (vn[0] == 0.0 && vn[1] == 0.0) { //无流区域,设置白色 70 | sum1 = 255.0; 71 | sum2 = 255.0; 72 | dog[i][j] = sum1 - tau * sum2; 73 | continue; 74 | } 75 | d_x = i; d_y = j; 76 | //////////////////////////////////////// 77 | for (s = -half_w2; s <= half_w2; s++) { 78 | //////////////////////// 79 | x = d_x + vn[0] * s; 80 | y = d_y + vn[1] * s; 81 | ///////////////////////////////////////////////////// 82 | if (x > (double)image_x-1 || x < 0.0 || y > (double)image_y-1 || y < 0.0) 83 | continue; 84 | x1 = round(x); if (x1 < 0) x1 = 0; if (x1 > image_x-1) x1 = image_x-1; 85 | y1 = round(y); if (y1 < 0) y1 = 0; if (y1 > image_y-1) y1 = image_y-1; 86 | val = image[x1][y1]; //对原图像进行处理 87 | ///////////////////////////////////////////////////////// 88 | dd = ABS(s); 89 | if (dd > half_w1) weight1 = 0.0; 90 | else weight1 = GAU1[dd]; 91 | ////////////////////////////////// 92 | sum1 += val * weight1; 93 | w_sum1 += weight1; 94 | ///////////////////////////////////////////////////// 95 | weight2 = GAU2[dd]; 96 | sum2 += val * weight2; 97 | w_sum2 += weight2; 98 | } 99 | ///////////////////////// 100 | sum1 /= w_sum1; 101 | sum2 /= w_sum2; 102 | ////////////////////////////////////// 103 | dog[i][j] = sum1 - tau * sum2; 104 | } 105 | } 106 | 107 | } 108 | 109 | void GetFlowDoG(ETF& e, mymatrix& dog, mymatrix& tmp, myvec& GAU3) 110 | { 111 | myvec vt(2); 112 | double x, y, d_x, d_y; 113 | double weight1, w_sum1, sum1; 114 | 115 | int i_x, i_y, k; 116 | int x1, y1; 117 | double val; 118 | int i, j; 119 | 120 | int image_x = dog.getRow(); 121 | int image_y = dog.getCol(); 122 | 123 | int half_l; 124 | half_l = GAU3.getMax()-1; 125 | 126 | // int flow_DOG_sign = 0; 127 | 128 | double step_size = 1.0; 129 | 130 | for (i = 0; i < image_x; i++) { 131 | for (j = 0; j < image_y; j++) { 132 | sum1 = 0.0; 133 | w_sum1 = 0.0; 134 | weight1 = 0.0; 135 | ///////////////////////////////// 136 | val = dog[i][j]; 137 | weight1 = GAU3[0]; 138 | sum1 = val * weight1; 139 | w_sum1 += weight1; 140 | //////////////////////////////////////////////// 141 | d_x = (double)i; d_y = (double)j; 142 | i_x = i; i_y = j; 143 | //////////////////////////// 144 | for (k = 0; k < half_l; k++) { 145 | vt[0] = e[i_x][i_y].tx; 146 | vt[1] = e[i_x][i_y].ty; 147 | if (vt[0] == 0.0 && vt[1] == 0.0) { 148 | break; 149 | } 150 | x = d_x; 151 | y = d_y; 152 | ///////////////////////////////////////////////////// 153 | if (x > (double)image_x-1 || x < 0.0 || y > (double)image_y-1 || y < 0.0) 154 | break; 155 | x1 = round(x); if (x1 < 0) x1 = 0; if (x1 > image_x-1) x1 = image_x-1; 156 | y1 = round(y); if (y1 < 0) y1 = 0; if (y1 > image_y-1) y1 = image_y-1; 157 | val = dog[x1][y1]; 158 | ////////////////////////////// 159 | weight1 = GAU3[k]; 160 | //////////////////// 161 | sum1 += val * weight1; 162 | w_sum1 += weight1; 163 | ///////////////////////////////////////// 164 | d_x += vt[0] * step_size; 165 | d_y += vt[1] * step_size; 166 | ///////////////////////////////////////// 167 | i_x = round(d_x); 168 | i_y = round(d_y); 169 | if (d_x < 0 || d_x > image_x-1 || d_y < 0 || d_y > image_y-1) break; 170 | ///////////////////////// 171 | } 172 | //////////////////////////////////////////////// 173 | d_x = (double)i; d_y = (double)j; 174 | i_x = i; i_y = j; 175 | for (k = 0; k < half_l; k++) { 176 | vt[0] = -e[i_x][i_y].tx; 177 | vt[1] = -e[i_x][i_y].ty; 178 | if (vt[0] == 0.0 && vt[1] == 0.0) { 179 | break; 180 | } 181 | x = d_x; 182 | y = d_y; 183 | ///////////////////////////////////////////////////// 184 | if (x > (double)image_x-1 || x < 0.0 || y > (double)image_y-1 || y < 0.0) 185 | break; 186 | x1 = round(x); if (x1 < 0) x1 = 0; if (x1 > image_x-1) x1 = image_x-1; 187 | y1 = round(y); if (y1 < 0) y1 = 0; if (y1 > image_y-1) y1 = image_y-1; 188 | val = dog[x1][y1]; 189 | ////////////////////////////// 190 | weight1 = GAU3[k]; 191 | //////////////////// 192 | sum1 += val * weight1; 193 | w_sum1 += weight1; 194 | ///////////////////////////////////////// 195 | d_x += vt[0] * step_size; 196 | d_y += vt[1] * step_size; 197 | ///////////////////////////////////////// 198 | i_x = round(d_x); 199 | i_y = round(d_y); 200 | if (d_x < 0 || d_x > image_x-1 || d_y < 0 || d_y > image_y-1) break; 201 | ///////////////////////// 202 | } 203 | //////////////////////////////////////// 204 | sum1 /= w_sum1; 205 | ////////////////////////////////////// 206 | if (sum1 > 0) tmp[i][j] = 1.0; 207 | else tmp[i][j] = 1.0 + tanh(sum1); 208 | } 209 | } 210 | } 211 | 212 | void GetFDoG(imatrix& image, ETF& e, double sigma, double sigma3, double tau) 213 | { 214 | int i, j; 215 | 216 | int image_x = image.getRow(); 217 | int image_y = image.getCol(); 218 | 219 | myvec GAU1, GAU2, GAU3; 220 | MakeGaussianVector(sigma, GAU1); 221 | MakeGaussianVector(sigma*1.6, GAU2); 222 | 223 | int half_w1, half_w2, half_l; 224 | half_w1 = GAU1.getMax()-1; 225 | half_w2 = GAU2.getMax()-1; 226 | 227 | MakeGaussianVector(sigma3, GAU3); 228 | half_l = GAU3.getMax()-1; 229 | 230 | mymatrix tmp(image_x, image_y); 231 | mymatrix dog(image_x, image_y); 232 | 233 | GetDirectionalDoG(image, e, dog, GAU1, GAU2, tau); 234 | GetFlowDoG(e, dog, tmp, GAU3); 235 | 236 | for (i = 0; i < image_x; i++) { 237 | for (j = 0; j < image_y; j++) { 238 | image[i][j] = round(tmp[i][j] * 255.); 239 | } 240 | } 241 | } 242 | 243 | //void GaussSmoothSep(imatrix& image, double sigma) 244 | //{ 245 | // int i, j; 246 | // int MAX_GRADIENT = -1; 247 | // double g, max_g, min_g; 248 | // int s, t; 249 | // int x, y; 250 | // double weight, w_sum; 251 | 252 | // int image_x = image.getRow(); 253 | // int image_y = image.getCol(); 254 | 255 | // myvec GAU1; 256 | // MakeGaussianVector(sigma, GAU1); 257 | // int half = GAU1.getMax()-1; 258 | 259 | // mymatrix tmp(image_x, image_y); 260 | 261 | // max_g = -1; 262 | // min_g = 10000000; 263 | // for (j = 0; j < image_y; j++) { 264 | // for (i = 0; i < image_x; i++) { 265 | // g = 0.0; 266 | // weight = w_sum = 0.0; 267 | // for (s = -half; s <= half; s++) { 268 | // x = i+s; y = j; 269 | // if (x > image_x-1) x = image_x-1; 270 | // else if (x < 0) x = 0; 271 | // if (y > image_y-1) y = image_y-1; 272 | // else if (y < 0) y = 0; 273 | // weight = GAU1[ABS(s)]; 274 | // g += weight * image[x][y]; 275 | // w_sum += weight; 276 | // } 277 | // g /= w_sum; 278 | // if (g > max_g) max_g = g; 279 | // if (g < min_g) min_g = g; 280 | // tmp[i][j] = g; 281 | // } 282 | // } 283 | // for (j = 0; j < image_y; j++) { 284 | // for (i = 0; i < image_x; i++) { 285 | // g = 0.0; 286 | // weight = w_sum = 0.0; 287 | // for (t = -half; t <= half; t++) { 288 | // x = i; y = j+t; 289 | // if (x > image_x-1) x = image_x-1; 290 | // else if (x < 0) x = 0; 291 | // if (y > image_y-1) y = image_y-1; 292 | // else if (y < 0) y = 0; 293 | // weight = GAU1[ABS(t)]; 294 | // g += weight * tmp[x][y]; 295 | // w_sum += weight; 296 | // } 297 | // g /= w_sum; 298 | // if (g > max_g) max_g = g; 299 | // if (g < min_g) min_g = g; 300 | // image[i][j] = round(g); 301 | // } 302 | // } 303 | 304 | // TRACE("max_g = %f\n", max_g); 305 | // TRACE("min_g = %f\n", min_g); 306 | //} 307 | 308 | //void ConstructMergedImage(imatrix& image, imatrix& gray, imatrix& merged) 309 | //{ 310 | // int x, y; 311 | 312 | // int image_x = image.getRow(); 313 | // int image_y = image.getCol(); 314 | 315 | // for (y = 0; y < image_y; y++) { 316 | // for (x = 0; x < image_x; x++) { 317 | // if (gray[x][y] == 0) merged[x][y] = 0; 318 | // else merged[x][y] = image[x][y]; 319 | // } 320 | // } 321 | //} 322 | 323 | //void ConstructMergedImageMult(imatrix& image, imatrix& gray, imatrix& merged) 324 | //// using multiplication 325 | //{ 326 | // int x, y; 327 | // double gray_val, line_darkness; 328 | 329 | // int image_x = image.getRow(); 330 | // int image_y = image.getCol(); 331 | 332 | // for (y = 0; y < image_y; y++) { 333 | // for (x = 0; x < image_x; x++) { 334 | // gray_val = image[x][y] / 255.0; 335 | // line_darkness = gray[x][y] / 255.0; 336 | // gray_val *= line_darkness; 337 | // merged[x][y] = round(gray_val * 255.0); 338 | // } 339 | // } 340 | //} 341 | 342 | void Binarize(imatrix& image, double thres) 343 | { 344 | int i, j; 345 | double val; 346 | 347 | int image_x = image.getRow(); 348 | int image_y = image.getCol(); 349 | 350 | for (i = 0; i < image_x; i++) { 351 | for (j = 0; j < image_y; j++) { 352 | val = image[i][j] / 255.0; 353 | if (val < thres) 354 | image[i][j] = 0; 355 | else image[i][j] = 255; 356 | } 357 | } 358 | } 359 | 360 | void GrayThresholding(imatrix& image, double thres) 361 | { 362 | int i, j; 363 | double val; 364 | 365 | int image_x = image.getRow(); 366 | int image_y = image.getCol(); 367 | 368 | for (i = 0; i < image_x; i++) { 369 | for (j = 0; j < image_y; j++) { 370 | val = image[i][j] / 255.0; 371 | if (val < thres) 372 | image[i][j] = round(val * 255.0); 373 | else image[i][j] = 255; 374 | } 375 | } 376 | } 377 | 378 | -------------------------------------------------------------------------------- /fdog.h: -------------------------------------------------------------------------------- 1 | #ifndef _FDOG_H_ 2 | #define _FDOG_H_ 3 | #include "imatrix.h" 4 | #include "ETF.h" 5 | //extern 6 | void GaussSmoothSep(imatrix& image, double sigma); 7 | void ConstructMergedImage(imatrix& image, imatrix& gray, imatrix& merged); 8 | void ConstructMergedImageMult(imatrix& image, imatrix& gray, imatrix& merged); 9 | void GetFDoG(imatrix& image, ETF& e, double sigma, double sigma3, double tau); 10 | void Binarize(imatrix& image, double thres); 11 | void GrayThresholding(imatrix& image, double thres); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /imatrix.h: -------------------------------------------------------------------------------- 1 | #ifndef _IMATRIX_H_ 2 | #define _IMATRIX_H_ 3 | 4 | class imatrix { 5 | private: 6 | int Nr, Nc; 7 | void delete_all() { 8 | for (int i = 0; i < Nr; i++) 9 | delete[] p[i]; 10 | delete[] p; 11 | } 12 | public: 13 | int** p; 14 | 15 | imatrix() 16 | { 17 | Nr = 1, Nc = 1; 18 | p = new int*[Nr]; 19 | for(int i = 0; i < Nr; i++) 20 | p[i] = new int[Nc]; 21 | p[0][0]=1; 22 | }; 23 | imatrix(int i, int j) 24 | { 25 | Nr = i, Nc = j; 26 | 27 | p = new int*[Nr]; 28 | for(i = 0; i < Nr; i++) 29 | p[i] = new int[Nc]; 30 | }; 31 | imatrix(imatrix& b) { 32 | Nr = b.Nr; 33 | Nc = b.Nc; 34 | p = new int*[Nr]; 35 | for (int i = 0; i < Nr; i++) { 36 | p[i] = new int[Nc]; 37 | for (int j = 0; j < Nc; j++) { 38 | p[i][j] = b[i][j]; 39 | } 40 | } 41 | } 42 | void init(int i, int j) 43 | { 44 | delete_all(); 45 | Nr = i, Nc = j; 46 | p = new int*[Nr]; 47 | for(i = 0; i < Nr; i++) 48 | p[i] = new int[Nc]; 49 | }; 50 | 51 | ~imatrix() 52 | { 53 | delete_all(); 54 | } 55 | int* operator[](int i) { return p[i]; }; 56 | 57 | int& get( int i, int j ) const { return p[i][j]; } 58 | int getRow() const { return Nr; } 59 | int getCol() const { return Nc; } 60 | 61 | void zero() 62 | { 63 | for (int i = 0; i < Nr; i++) 64 | for (int j = 0; j < Nc; j++) 65 | p[i][j] = 0; 66 | } 67 | void copy(imatrix& b) 68 | { 69 | init(b.Nr, b.Nc); 70 | for (int i = 0; i < Nr; i++) 71 | for (int j = 0; j < Nc; j++) 72 | p[i][j] = b.p[i][j]; 73 | } 74 | }; 75 | 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "imatrix.h" 4 | #include "ETF.h" 5 | #include "fdog.h" 6 | #include "myvec.h" 7 | 8 | 9 | 10 | int main(int argc, char *argv[]){ 11 | 12 | //通过opencv载入图片 13 | IplImage *image = cvLoadImage(argv[1], 1); 14 | cvShowImage("ori",image); 15 | cvWaitKey(0); 16 | IplImage *gray_image = cvCreateImage(cvGetSize(image),image->depth,1); 17 | cvCvtColor(image, gray_image, CV_RGB2GRAY); //转换为灰度图 18 | cvShowImage("gray",gray_image); 19 | cvWaitKey(0); 20 | 21 | //img初始化 22 | int w=gray_image->width,h=gray_image->height; 23 | imatrix img(h,w); 24 | for (int i=0;i 5 | 6 | class myvec { 7 | private: 8 | 9 | public: 10 | int N; 11 | double* p; 12 | myvec() 13 | { 14 | N = 1; 15 | p = new double[1]; 16 | p[0]=1.0; 17 | }; 18 | myvec(int i) 19 | { 20 | N = i; 21 | p = new double[N]; 22 | }; 23 | ~myvec() 24 | { 25 | delete[] p; 26 | } 27 | double& operator[](int i) { return p[i]; } 28 | const double& operator[](int i) const { return p[i]; } 29 | void zero() { 30 | for (int i = 0; i < N; i++) 31 | p[i] = 0.0; 32 | } 33 | void make_unit() { 34 | double sum = 0.0; 35 | for (int i = 0; i < N; i++) { 36 | sum += p[i]*p[i]; 37 | } 38 | sum = sqrt(sum); 39 | if (sum > 0.0) { 40 | for (int i = 0; i < N; i++) { 41 | p[i] = p[i] / sum; 42 | } 43 | } 44 | } 45 | double norm() { 46 | double sum = 0.0; 47 | for (int i = 0; i < N; i++) { 48 | sum += p[i]*p[i]; 49 | } 50 | sum = sqrt(sum); 51 | return sum; 52 | } 53 | double get(int n) const { return p[n]; } 54 | int getMax() { return N; } 55 | void init(int i) { 56 | delete[] p; 57 | N = i; 58 | p = new double[N]; 59 | } 60 | }; 61 | 62 | class mymatrix { 63 | private: 64 | int Nr, Nc; 65 | double** p; 66 | void delete_all() { 67 | for (int i = 0; i < Nr; i++) 68 | delete[] p[i]; 69 | delete[] p; 70 | } 71 | public: 72 | mymatrix() 73 | { 74 | Nr = 1, Nc = 1; 75 | p = new double*[Nr]; 76 | for(int i = 0; i < Nr; i++) 77 | p[i] = new double[Nc]; 78 | p[0][0]=1.0; 79 | }; 80 | mymatrix(int i, int j) 81 | { 82 | Nr = i, Nc = j; 83 | p = new double*[Nr]; 84 | for(i = 0; i < Nr; i++) 85 | p[i] = new double[Nc]; 86 | }; 87 | mymatrix(mymatrix& b) { 88 | Nr = b.Nr; 89 | Nc = b.Nc; 90 | p = new double*[Nr]; 91 | for (int i = 0; i < Nr; i++) { 92 | p[i] = new double[Nc]; 93 | for (int j = 0; j < Nc; j++) { 94 | p[i][j] = b[i][j]; 95 | } 96 | } 97 | } 98 | ~mymatrix() { 99 | delete_all(); 100 | } 101 | double* operator[](int i) { return p[i]; }; 102 | double& get( int i, int j ) const { return p[i][j]; } 103 | int getRow() const { return Nr; } 104 | int getCol() const { return Nc; } 105 | void init(int i, int j) 106 | { 107 | delete_all(); 108 | Nr = i, Nc = j; 109 | p = new double*[Nr]; 110 | for(i = 0; i < Nr; i++) 111 | p[i] = new double[Nc]; 112 | }; 113 | void zero() 114 | { 115 | for (int i = 0; i < Nr; i++) 116 | for (int j = 0; j < Nc; j++) 117 | p[i][j] = 0.0; 118 | } 119 | }; 120 | 121 | 122 | #endif --------------------------------------------------------------------------------