当前位置:   article > 正文

主成分分析(PCA) C++ 实现_pca c++

pca c++

主成分分析(Principal Components Analysis, PCA)简介可以参考: http://blog.csdn.net/fengbingchun/article/details/78977202

以下是PCA的C++实现,参考OpenCV 3.3中的cv::PCA类。

使用ORL Faces Database作为测试图像。关于ORL Faces Database的介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/79008891 

pca.hpp:

  1. #ifndef FBC_NN_PCA_HPP_
  2. #define FBC_NN_PCA_HPP_
  3. #include <vector>
  4. #include <string>
  5. namespace ANN {
  6. template<typename T = float>
  7. class PCA {
  8. public:
  9. PCA() = default;
  10. int load_data(const std::vector<std::vector<T>>& data, const std::vector<T>& labels);
  11. int set_max_components(int max_components);
  12. int set_retained_variance(double retained_variance);
  13. int load_model(const std::string& model);
  14. int train(const std::string& model);
  15. // project into the eigenspace, thus the image becomes a "point"
  16. int project(const std::vector<T>& vec, std::vector<T>& result) const;
  17. // re-create the image from the "point"
  18. int back_project(const std::vector<T>& vec, std::vector<T>& result) const;
  19. private:
  20. // width,height,eigen_vectors;width,height,eigen_values;width,height,means
  21. int save_model(const std::string& model) const;
  22. void calculate_covariance_matrix(std::vector<std::vector<T>>& covar, bool scale = false); // calculate covariance matrix
  23. int eigen(const std::vector<std::vector<T>>& mat, bool sort_ = true); // calculate eigen vectors and eigen values
  24. // generalized matrix multiplication: dst = alpha*src1.t()*src2 + beta*src3.t()
  25. int gemm(const std::vector<std::vector<T>>& src1, const std::vector<std::vector<T>>& src2, double alpha,
  26. const std::vector<std::vector<T>>& src3, double beta, std::vector<std::vector<T>>& dst, int flags = 0) const;
  27. int gemm(const std::vector<T>& src1, const std::vector<std::vector<T>>& src2, double alpha,
  28. const std::vector<T>& src3, double beta, std::vector<T>& dst, int flags = 0) const; // GEMM_2_T: flags = 1
  29. int normalize(T* dst, int length);
  30. int computeCumulativeEnergy() const;
  31. int subtract(const std::vector<T>& vec1, const std::vector<T>& vec2, std::vector<T>& result) const;
  32. typedef struct Size_ {
  33. int width;
  34. int height;
  35. } Size_;
  36. std::vector<std::vector<T>> data;
  37. std::vector<T> labels;
  38. int samples_num = 0;
  39. int features_length = 0;
  40. double retained_variance = -1.; // percentage of variance that PCA should retain
  41. int max_components = -1; // maximum number of components that PCA should retain
  42. std::vector<std::vector<T>> eigen_vectors; // eigenvectors of the covariation matrix
  43. std::vector<T> eigen_values; // eigenvalues of the covariation matrix
  44. std::vector<T> mean;
  45. int covar_flags = 0; // when features_length > samples_num, covar_flags is 0, otherwise is 1
  46. };
  47. } // namespace ANN
  48. #endif // FBC_NN_PCA_HPP_
pca.cpp:

  1. #include "pca.hpp"
  2. #include <iostream>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <memory>
  7. #include <fstream>
  8. #include "common.hpp"
  9. namespace ANN {
  10. template<typename T>
  11. int PCA<T>::load_data(const std::vector<std::vector<T>>& data, const std::vector<T>& labels)
  12. {
  13. this->samples_num = data.size();
  14. this->features_length = data[0].size();
  15. if (samples_num > features_length) {
  16. fprintf(stderr, "now only support samples_num <= features_length\n");
  17. return -1;
  18. }
  19. this->data.resize(this->samples_num);
  20. for (int i = 0; i < this->samples_num; ++i) {
  21. this->data[i].resize(this->features_length);
  22. memcpy(this->data[i].data(), data[i].data(), sizeof(T)* this->features_length);
  23. }
  24. this->labels.resize(this->samples_num);
  25. memcpy(this->labels.data(), labels.data(), sizeof(T)*this->samples_num);
  26. return 0;
  27. }
  28. template<typename T>
  29. int PCA<T>::set_max_components(int max_components)
  30. {
  31. CHECK(data.size() > 0);
  32. int count = std::min(features_length, samples_num);
  33. if (max_components > 0) {
  34. this->max_components = std::min(count, max_components);
  35. }
  36. this->retained_variance = -1.;
  37. }
  38. template<typename T>
  39. int PCA<T>::set_retained_variance(double retained_variance)
  40. {
  41. CHECK(retained_variance > 0 && retained_variance <= 1);
  42. this->retained_variance = retained_variance;
  43. this->max_components = -1;
  44. }
  45. template<typename T>
  46. void PCA<T>::calculate_covariance_matrix(std::vector<std::vector<T>>& covar, bool scale)
  47. {
  48. const int rows = samples_num;
  49. const int cols = features_length;
  50. const int nsamples = rows;
  51. double scale_ = 1.;
  52. if (scale) scale_ = 1. / (nsamples /*- 1*/);
  53. mean.resize(cols, (T)0.);
  54. for (int w = 0; w < cols; ++w) {
  55. for (int h = 0; h < rows; ++h) {
  56. mean[w] += data[h][w];
  57. }
  58. }
  59. for (auto& value : mean) {
  60. value = 1. / rows * value;
  61. }
  62. // int dsize = ata ? src.cols : src.rows; // ata = false;
  63. int dsize = rows;
  64. covar.resize(dsize);
  65. for (int i = 0; i < dsize; ++i) {
  66. covar[i].resize(dsize, (T)0.);
  67. }
  68. Size_ size{ data[0].size(), data.size() };
  69. T* tdst = covar[0].data();
  70. int delta_cols = mean.size();
  71. T delta_buf[4];
  72. int delta_shift = delta_cols == size.width ? 4 : 0;
  73. std::unique_ptr<T[]> buf(new T[size.width]);
  74. T* row_buf = buf.get();
  75. for (int i = 0; i < size.height; ++i) {
  76. const T* tsrc1 = data[i].data();
  77. const T* tdelta1 = mean.data();
  78. for (int k = 0; k < size.width; ++k) {
  79. row_buf[k] = tsrc1[k] - tdelta1[k];
  80. }
  81. for (int j = i; j < size.height; ++j) {
  82. double s = 0;
  83. const T* tsrc2 = data[j].data();
  84. const T* tdelta2 = mean.data();
  85. for (int k = 0; k < size.width; ++k) {
  86. s += (double)row_buf[k] * (tsrc2[k] - tdelta2[k]);
  87. }
  88. tdst[j] = (T)(s * scale_);
  89. }
  90. if (i < covar.size()-1) {
  91. tdst = covar[i + 1].data();
  92. }
  93. }
  94. }
  95. namespace {
  96. template<typename _Tp>
  97. static inline _Tp hypot_(_Tp a, _Tp b)
  98. {
  99. a = std::abs(a);
  100. b = std::abs(b);
  101. if (a > b) {
  102. b /= a;
  103. return a*std::sqrt(1 + b*b);
  104. }
  105. if (b > 0) {
  106. a /= b;
  107. return b*std::sqrt(1 + a*a);
  108. }
  109. return 0;
  110. }
  111. } // namespace
  112. template<typename T>
  113. int PCA<T>::eigen(const std::vector<std::vector<T>>& mat, bool sort_ = true)
  114. {
  115. using _Tp = T; // typedef T _Tp;
  116. auto n = mat.size();
  117. for (const auto& m : mat) {
  118. if (m.size() != n) {
  119. fprintf(stderr, "mat must be square and it should be a real symmetric matrix\n");
  120. return -1;
  121. }
  122. }
  123. eigen_values.resize(n, (T)0.);
  124. std::vector<T> V(n*n, (T)0.);
  125. for (int i = 0; i < n; ++i) {
  126. V[n * i + i] = (_Tp)1;
  127. eigen_values[i] = mat[i][i];
  128. }
  129. const _Tp eps = std::numeric_limits<_Tp>::epsilon();
  130. int maxIters{ (int)n * (int)n * 30 };
  131. _Tp mv{ (_Tp)0 };
  132. std::vector<int> indR(n, 0), indC(n, 0);
  133. std::vector<_Tp> A;
  134. for (int i = 0; i < n; ++i) {
  135. A.insert(A.begin() + i * n, mat[i].begin(), mat[i].end());
  136. }
  137. for (int k = 0; k < n; ++k) {
  138. int m, i;
  139. if (k < n - 1) {
  140. for (m = k + 1, mv = std::abs(A[n*k + m]), i = k + 2; i < n; i++) {
  141. _Tp val = std::abs(A[n*k + i]);
  142. if (mv < val)
  143. mv = val, m = i;
  144. }
  145. indR[k] = m;
  146. }
  147. if (k > 0) {
  148. for (m = 0, mv = std::abs(A[k]), i = 1; i < k; i++) {
  149. _Tp val = std::abs(A[n*i + k]);
  150. if (mv < val)
  151. mv = val, m = i;
  152. }
  153. indC[k] = m;
  154. }
  155. }
  156. if (n > 1) for (int iters = 0; iters < maxIters; iters++) {
  157. int k, i, m;
  158. // find index (k,l) of pivot p
  159. for (k = 0, mv = std::abs(A[indR[0]]), i = 1; i < n - 1; i++) {
  160. _Tp val = std::abs(A[n*i + indR[i]]);
  161. if (mv < val)
  162. mv = val, k = i;
  163. }
  164. int l = indR[k];
  165. for (i = 1; i < n; i++) {
  166. _Tp val = std::abs(A[n*indC[i] + i]);
  167. if (mv < val)
  168. mv = val, k = indC[i], l = i;
  169. }
  170. _Tp p = A[n*k + l];
  171. if (std::abs(p) <= eps)
  172. break;
  173. _Tp y = (_Tp)((eigen_values[l] - eigen_values[k])*0.5);
  174. _Tp t = std::abs(y) + hypot_(p, y);
  175. _Tp s = hypot_(p, t);
  176. _Tp c = t / s;
  177. s = p / s; t = (p / t)*p;
  178. if (y < 0)
  179. s = -s, t = -t;
  180. A[n*k + l] = 0;
  181. eigen_values[k] -= t;
  182. eigen_values[l] += t;
  183. _Tp a0, b0;
  184. #undef rotate
  185. #define rotate(v0, v1) a0 = v0, b0 = v1, v0 = a0*c - b0*s, v1 = a0*s + b0*c
  186. // rotate rows and columns k and l
  187. for (i = 0; i < k; i++)
  188. rotate(A[n*i + k], A[n*i + l]);
  189. for (i = k + 1; i < l; i++)
  190. rotate(A[n*k + i], A[n*i + l]);
  191. for (i = l + 1; i < n; i++)
  192. rotate(A[n*k + i], A[n*l + i]);
  193. // rotate eigenvectors
  194. for (i = 0; i < n; i++)
  195. rotate(V[n*k + i], V[n*l + i]);
  196. #undef rotate
  197. for (int j = 0; j < 2; j++) {
  198. int idx = j == 0 ? k : l;
  199. if (idx < n - 1) {
  200. for (m = idx + 1, mv = std::abs(A[n*idx + m]), i = idx + 2; i < n; i++) {
  201. _Tp val = std::abs(A[n*idx + i]);
  202. if (mv < val)
  203. mv = val, m = i;
  204. }
  205. indR[idx] = m;
  206. }
  207. if (idx > 0) {
  208. for (m = 0, mv = std::abs(A[idx]), i = 1; i < idx; i++) {
  209. _Tp val = std::abs(A[n*i + idx]);
  210. if (mv < val)
  211. mv = val, m = i;
  212. }
  213. indC[idx] = m;
  214. }
  215. }
  216. }
  217. // sort eigenvalues & eigenvectors
  218. if (sort_) {
  219. for (int k = 0; k < n - 1; k++) {
  220. int m = k;
  221. for (int i = k + 1; i < n; i++) {
  222. if (eigen_values[m] < eigen_values[i])
  223. m = i;
  224. }
  225. if (k != m) {
  226. std::swap(eigen_values[m], eigen_values[k]);
  227. for (int i = 0; i < n; i++)
  228. std::swap(V[n*m + i], V[n*k + i]);
  229. }
  230. }
  231. }
  232. eigen_vectors.resize(n);
  233. for (int i = 0; i < n; ++i) {
  234. eigen_vectors[i].resize(n);
  235. eigen_vectors[i].assign(V.begin() + i * n, V.begin() + i * n + n);
  236. }
  237. return 0;
  238. }
  239. template<typename T>
  240. int PCA<T>::gemm(const std::vector<std::vector<T>>& src1, const std::vector<std::vector<T>>& src2, double alpha,
  241. const std::vector<std::vector<T>>& src3, double beta, std::vector<std::vector<T>>& dst, int flags) const
  242. {
  243. CHECK(flags == 0); // now only support flags = 0
  244. CHECK(typeid(T).name() == typeid(double).name() || typeid(T).name() == typeid(float).name()); // T' type can only be float or double
  245. CHECK(beta == 0. && src3.size() == 0);
  246. Size_ a_size{ src1[0].size(), src1.size() }, d_size{ src2[0].size(), a_size.height };
  247. int len{ (int)src2.size() };
  248. CHECK(a_size.height == len);
  249. CHECK(d_size.height == dst.size() && d_size.width == dst[0].size());
  250. for (int y = 0; y < d_size.height; ++y) {
  251. for (int x = 0; x < d_size.width; ++x) {
  252. dst[y][x] = 0.;
  253. for (int t = 0; t < d_size.height; ++t) {
  254. dst[y][x] += src1[y][t] * src2[t][x];
  255. }
  256. dst[y][x] *= alpha;
  257. }
  258. }
  259. return 0;
  260. }
  261. template<typename T>
  262. int PCA<T>::gemm(const std::vector<T>& src1, const std::vector<std::vector<T>>& src2, double alpha,
  263. const std::vector<T>& src3, double beta, std::vector<T>& dst, int flags = 0) const
  264. {
  265. CHECK(flags == 0 || flags == 1); // when flags = 1, GEMM_2_T
  266. CHECK(typeid(T).name() == typeid(double).name() || typeid(T).name() == typeid(float).name()); // T' type can only be float or double
  267. Size_ a_size{ src1.size(), 1 }, d_size;
  268. int len = 0;
  269. switch (flags) {
  270. case 0:
  271. d_size = Size_{ src2[0].size(), a_size.height };
  272. len = src2.size();
  273. CHECK(a_size.width == len);
  274. break;
  275. case 1:
  276. d_size = Size_{ src2.size(), a_size.height };
  277. len = src2[0].size();
  278. CHECK(a_size.width == len);
  279. break;
  280. }
  281. if (!src3.empty()) {
  282. CHECK(src3.size() == d_size.width);
  283. }
  284. dst.resize(d_size.width);
  285. const T* src3_ = nullptr;
  286. std::vector<T> tmp(dst.size(), (T)0.);
  287. if (src3.empty()) {
  288. src3_ = tmp.data();
  289. } else {
  290. src3_ = src3.data();
  291. }
  292. if (src1.size() == src2.size()) {
  293. for (int i = 0; i < dst.size(); ++i) {
  294. dst[i] = (T)0.;
  295. for (int j = 0; j < src2.size(); ++j) {
  296. dst[i] += src1[j] * src2[j][i];
  297. }
  298. dst[i] *= alpha;
  299. dst[i] += beta * src3_[i];
  300. }
  301. } else {
  302. for (int i = 0; i < dst.size(); ++i) {
  303. dst[i] = (T)0.;
  304. for (int j = 0; j < src1.size(); ++j) {
  305. dst[i] += src1[j] * src2[i][j];
  306. }
  307. dst[i] *= alpha;
  308. dst[i] += beta * src3_[i];
  309. }
  310. }
  311. return 0;
  312. }
  313. template<typename T>
  314. int PCA<T>::normalize(T* dst, int length)
  315. {
  316. T s = (T)0., a = (T)1.;
  317. for (int i = 0; i < length; ++i) {
  318. s += dst[i] * dst[i];
  319. }
  320. s = std::sqrt(s);
  321. s = s > DBL_EPSILON ? a / s : 0.;
  322. for (int i = 0; i < length; ++i) {
  323. dst[i] *= s;
  324. }
  325. return 0;
  326. }
  327. template<typename T>
  328. int PCA<T>::computeCumulativeEnergy() const
  329. {
  330. std::vector<T> g(eigen_values.size(), (T)0.);
  331. for (int ig = 0; ig < eigen_values.size(); ++ig) {
  332. for (int im = 0; im <= ig; ++im) {
  333. g[ig] += eigen_values[im];
  334. }
  335. }
  336. int L{ 0 };
  337. for (L = 0; L < eigen_values.size(); ++L) {
  338. double energy = g[L] / g[eigen_values.size() - 1];
  339. if (energy > retained_variance) break;
  340. }
  341. L = std::max(2, L);
  342. return L;
  343. }
  344. template<typename T>
  345. int PCA<T>::train(const std::string& model)
  346. {
  347. CHECK(retained_variance > 0. || max_components > 0);
  348. int count = std::min(features_length, samples_num), out_count = count;
  349. if (max_components > 0) out_count = std::min(count, max_components);
  350. covar_flags = 0;
  351. if (features_length <= samples_num) covar_flags = 1;
  352. std::vector<std::vector<T>> covar(count); // covariance matrix
  353. calculate_covariance_matrix(covar, true);
  354. eigen(covar, true);
  355. std::vector<std::vector<T>> tmp_data(samples_num), evects1(count);
  356. for (int i = 0; i < samples_num; ++i) {
  357. tmp_data[i].resize(features_length);
  358. evects1[i].resize(features_length);
  359. for (int j = 0; j < features_length; ++j) {
  360. tmp_data[i][j] = data[i][j] - mean[j];
  361. }
  362. }
  363. gemm(eigen_vectors, tmp_data, 1., std::vector<std::vector<T>>(), 0., evects1, 0);
  364. eigen_vectors.resize(evects1.size());
  365. for (int i = 0; i < eigen_vectors.size(); ++i) {
  366. eigen_vectors[i].resize(evects1[i].size());
  367. memcpy(eigen_vectors[i].data(), evects1[i].data(), sizeof(T)* evects1[i].size());
  368. }
  369. // normalize all eigenvectors
  370. if (retained_variance > 0) {
  371. for (int i = 0; i < eigen_vectors.size(); ++i) {
  372. normalize(eigen_vectors[i].data(), eigen_vectors[i].size());
  373. }
  374. // compute the cumulative energy content for each eigenvector
  375. int L = computeCumulativeEnergy();
  376. eigen_values.resize(L);
  377. eigen_vectors.resize(L);
  378. } else {
  379. for (int i = 0; i < out_count; ++i) {
  380. normalize(eigen_vectors[i].data(), eigen_vectors[i].size());
  381. }
  382. if (count > out_count) {
  383. eigen_values.resize(out_count);
  384. eigen_vectors.resize(out_count);
  385. }
  386. }
  387. save_model(model);
  388. return 0;
  389. }
  390. template<typename T>
  391. int PCA<T>::subtract(const std::vector<T>& vec1, const std::vector<T>& vec2, std::vector<T>& result) const
  392. {
  393. CHECK(vec1.size() == vec2.size() && vec1.size() == result.size());
  394. for (int i = 0; i < vec1.size(); ++i) {
  395. result[i] = vec1[i] - vec2[i];
  396. }
  397. return 0;
  398. }
  399. template<typename T>
  400. int PCA<T>::project(const std::vector<T>& vec, std::vector<T>& result) const
  401. {
  402. CHECK(!mean.empty() && !eigen_vectors.empty() && mean.size() == vec.size());
  403. std::vector<T> tmp_data(mean.size());
  404. subtract(vec, mean, tmp_data);
  405. gemm(tmp_data, eigen_vectors, 1, std::vector<T>(), 0, result, 1);
  406. return 0;
  407. }
  408. template<typename T>
  409. int PCA<T>::back_project(const std::vector<T>& vec, std::vector<T>& result) const
  410. {
  411. CHECK(!mean.empty() && !eigen_vectors.empty() && eigen_vectors.size() == vec.size());
  412. gemm(vec, eigen_vectors, 1, mean, 1, result, 0);
  413. return 0;
  414. }
  415. template<typename T>
  416. int PCA<T>::load_model(const std::string& model)
  417. {
  418. std::ifstream file(model.c_str(), std::ios::in | std::ios::binary);
  419. if (!file.is_open()) {
  420. fprintf(stderr, "open file fail: %s\n", model.c_str());
  421. return -1;
  422. }
  423. int width = 0, height = 0;
  424. file.read((char*)&width, sizeof(width) * 1);
  425. file.read((char*)&height, sizeof(height) * 1);
  426. std::unique_ptr<T[]> data(new T[width * height]);
  427. file.read((char*)data.get(), sizeof(T)* width * height);
  428. eigen_vectors.resize(height);
  429. for (int i = 0; i < height; ++i) {
  430. eigen_vectors[i].resize(width);
  431. T* p = data.get() + i * width;
  432. memcpy(eigen_vectors[i].data(), p, sizeof(T)* width);
  433. }
  434. file.read((char*)&width, sizeof(width));
  435. file.read((char*)&height, sizeof(height));
  436. CHECK(height == 1);
  437. eigen_values.resize(width);
  438. file.read((char*)eigen_values.data(), sizeof(T)* width * height);
  439. file.read((char*)&width, sizeof(width));
  440. file.read((char*)&height, sizeof(height));
  441. CHECK(height == 1);
  442. mean.resize(width);
  443. file.read((char*)mean.data(), sizeof(T)* width * height);
  444. file.close();
  445. return 0;
  446. }
  447. template<typename T>
  448. int PCA<T>::save_model(const std::string& model) const
  449. {
  450. std::ofstream file(model.c_str(), std::ios::out | std::ios::binary);
  451. if (!file.is_open()) {
  452. fprintf(stderr, "open file fail: %s\n", model.c_str());
  453. return -1;
  454. }
  455. int width = eigen_vectors[0].size(), height = eigen_vectors.size();
  456. std::unique_ptr<T[]> data(new T[width * height]);
  457. for (int i = 0; i < height; ++i) {
  458. T* p = data.get() + i * width;
  459. memcpy(p, eigen_vectors[i].data(), sizeof(T) * width);
  460. }
  461. file.write((char*)&width, sizeof(width));
  462. file.write((char*)&height, sizeof(height));
  463. file.write((char*)data.get(), sizeof(T)* width * height);
  464. width = eigen_values.size(), height = 1;
  465. file.write((char*)&width, sizeof(width));
  466. file.write((char*)&height, sizeof(height));
  467. file.write((char*)eigen_values.data(), sizeof(T)* width * height);
  468. width = mean.size(), height = 1;
  469. file.write((char*)&width, sizeof(width));
  470. file.write((char*)&height, sizeof(height));
  471. file.write((char*)mean.data(), sizeof(T)* width * height);
  472. file.close();
  473. return 0;
  474. }
  475. template class PCA<float>;
  476. template class PCA<double>;
  477. } // namespace ANN
main.cpp:

  1. #include "funset.hpp"
  2. #include <iostream>
  3. #include "perceptron.hpp"
  4. #include "BP.hpp""
  5. #include "CNN.hpp"
  6. #include "linear_regression.hpp"
  7. #include "naive_bayes_classifier.hpp"
  8. #include "logistic_regression.hpp"
  9. #include "common.hpp"
  10. #include "knn.hpp"
  11. #include "decision_tree.hpp"
  12. #include "pca.hpp"
  13. #include <opencv2/opencv.hpp>
  14. // =============================== PCA(Principal Components Analysis) ===================
  15. namespace {
  16. void normalize(const std::vector<float>& src, std::vector<unsigned char>& dst)
  17. {
  18. dst.resize(src.size());
  19. double dmin = 0, dmax = 255;
  20. double smin = src[0], smax = smin;
  21. for (int i = 1; i < src.size(); ++i) {
  22. if (smin > src[i]) smin = src[i];
  23. if (smax < src[i]) smax = src[i];
  24. }
  25. double scale = (dmax - dmin) * (smax - smin > DBL_EPSILON ? 1. / (smax - smin) : 0);
  26. double shift = dmin - smin * scale;
  27. for (int i = 0; i < src.size(); ++i) {
  28. dst[i] = static_cast<unsigned char>(src[i] * scale + shift);
  29. }
  30. }
  31. } // namespace
  32. int test_pca()
  33. {
  34. const std::string image_path{ "E:/GitCode/NN_Test/data/database/ORL_Faces/" };
  35. const std::string image_name{ "1.pgm" };
  36. std::vector<cv::Mat> images;
  37. for (int i = 1; i <= 15; ++i) {
  38. std::string name = image_path + "s" + std::to_string(i) + "/" + image_name;
  39. cv::Mat mat = cv::imread(name, 0);
  40. if (!mat.data) {
  41. fprintf(stderr, "read image fail: %s\n", name.c_str());
  42. return -1;
  43. }
  44. images.emplace_back(mat);
  45. }
  46. save_images(images, "E:/GitCode/NN_Test/data/pca_src.jpg", 5);
  47. cv::Mat data(images.size(), images[0].rows * images[0].cols, CV_32FC1);
  48. for (int i = 0; i < images.size(); ++i) {
  49. cv::Mat image_row = images[i].clone().reshape(1, 1);
  50. cv::Mat row_i = data.row(i);
  51. image_row.convertTo(row_i, CV_32F);
  52. }
  53. int features_length = images[0].rows * images[0].cols;
  54. std::vector<std::vector<float>> data_(images.size());
  55. std::vector<float> labels(images.size(), 0.f);
  56. for (int i = 0; i < images.size(); ++i) {
  57. data_[i].resize(features_length);
  58. memcpy(data_[i].data(), data.row(i).data, sizeof(float)* features_length);
  59. }
  60. const std::string save_model_file{ "E:/GitCode/NN_Test/data/pca.model" };
  61. ANN::PCA<float> pca;
  62. pca.load_data(data_, labels);
  63. double retained_variance{ 0.95 };
  64. pca.set_retained_variance(retained_variance);
  65. pca.train(save_model_file);
  66. const std::string read_model_file{ save_model_file };
  67. ANN::PCA<float> pca2;
  68. pca2.load_model(read_model_file);
  69. std::vector<cv::Mat> result(images.size());
  70. for (int i = 0; i < images.size(); ++i) {
  71. std::vector<float> point, reconstruction;
  72. pca2.project(data_[i], point);
  73. pca2.back_project(point, reconstruction);
  74. std::vector<unsigned char> dst;
  75. normalize(reconstruction, dst);
  76. cv::Mat tmp(images[i].rows, images[i].cols, CV_8UC1, dst.data());
  77. tmp.copyTo(result[i]);
  78. }
  79. save_images(result, "E:/GitCode/NN_Test/data/pca_result.jpg", 5);
  80. return 0;
  81. }
执行结果如下,上三行为原始图像,下三行为使用PCA重建图像的结果,经比较与OpenCV 3.3结果一致:



GitHub:  https://github.com/fengbingchun/NN_Test

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/222019
推荐阅读
相关标签
  

闽ICP备14008679号