2019-11-26 10:56:37 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <complex>
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
#include <iterator>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
namespace math {
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
using complex = std::complex<double>;
|
2019-11-26 10:56:37 +01:00
|
|
|
using signal = std::vector<double>;
|
|
|
|
using csignal = std::vector<complex>;
|
|
|
|
using contour = std::vector<cv::Point>;
|
|
|
|
constexpr double pi() {return std::atan(1)*4;}
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal cont2sig(const contour& cont) {
|
|
|
|
csignal sig;
|
|
|
|
auto sig_it = sig.begin();
|
|
|
|
auto cont_it = cont.begin();
|
|
|
|
|
|
|
|
for (auto cont_it = cont.begin(); cont_it != cont.end(); ++cont_it) {
|
|
|
|
*(sig_it++) = complex((*cont_it).x, (*cont_it).y);
|
|
|
|
}
|
|
|
|
return sig;
|
2019-11-26 10:56:37 +01:00
|
|
|
};
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
complex mean(const csignal& sig) {
|
|
|
|
complex res = 0;
|
|
|
|
for (auto x: sig) {
|
|
|
|
res += x;
|
|
|
|
}
|
|
|
|
return complex(res.real()/sig.size(), res.imag()/sig.size());
|
|
|
|
};
|
|
|
|
|
2019-11-26 13:45:25 +01:00
|
|
|
csignal diff(const csignal& input, complex mean) {
|
2019-11-26 13:50:55 +01:00
|
|
|
csignal res;
|
|
|
|
for (auto x: input) {
|
|
|
|
res.push_back(x - mean);
|
|
|
|
}
|
|
|
|
return res;
|
2019-11-26 13:45:25 +01:00
|
|
|
}
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal fft_rec(const csignal& input) {
|
2019-11-26 10:56:37 +01:00
|
|
|
int size = input.size();
|
|
|
|
|
|
|
|
if (size == 1) {
|
2019-11-26 13:50:55 +01:00
|
|
|
return input;
|
2019-11-26 10:56:37 +01:00
|
|
|
} else {
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal odd;
|
|
|
|
csignal even;
|
|
|
|
std::back_insert_iterator<csignal> odd_back_it(odd);
|
|
|
|
std::back_insert_iterator<csignal> even_back_it(even);
|
2019-11-26 10:56:37 +01:00
|
|
|
bool insert_in_even = false;
|
|
|
|
|
|
|
|
for (auto it = input.begin(); it != input.end(); ++it) {
|
|
|
|
if (insert_in_even) {
|
|
|
|
*even_back_it++ = *it;
|
|
|
|
insert_in_even = false;
|
|
|
|
} else {
|
|
|
|
*odd_back_it++ = *it;
|
|
|
|
insert_in_even = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal odd_fft = fft_rec(odd);
|
|
|
|
csignal even_fft = fft_rec(even);
|
|
|
|
csignal res;
|
2019-11-26 10:56:37 +01:00
|
|
|
res.reserve(size);
|
|
|
|
|
|
|
|
for (int k = 0; k<size/2; ++k) {
|
2019-11-26 13:24:33 +01:00
|
|
|
complex t = std::exp(complex(0, -2*pi()*k/size)) * odd[k];
|
2019-11-26 10:56:37 +01:00
|
|
|
res[k] = even[k] + t;
|
|
|
|
res[size/2+k] = even[k] - t;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal fft(const csignal& input) {
|
2019-11-26 14:22:52 +01:00
|
|
|
int opt_size = 1 << (int)std::ceil(std::log(input.size())/std::log(2));
|
|
|
|
csignal sig(input);
|
|
|
|
for (int i=0; i<opt_size-input.size(); ++i) {
|
|
|
|
sig.push_back(complex(0, 0));
|
|
|
|
}
|
|
|
|
return fft_rec(sig);
|
2019-11-26 10:56:37 +01:00
|
|
|
};
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
contour coef2cont(const csignal& tfd, complex mean, int size, int cmax) {
|
2019-11-26 10:56:37 +01:00
|
|
|
contour cont;
|
|
|
|
auto tf_it = tfd.begin();
|
|
|
|
auto cont_it = cont.begin();
|
2019-11-26 14:22:52 +01:00
|
|
|
int kmin = tfd.size()/2 - cmax;
|
|
|
|
int kmax = tfd.size()/2 + cmax;
|
2019-11-26 13:45:25 +01:00
|
|
|
|
|
|
|
for (int m=0; m<tfd.size(); ++m) {
|
|
|
|
complex sum;
|
|
|
|
for (int k=kmin; k<kmax; ++k) {
|
|
|
|
sum += tfd[k]*std::exp(complex(0, 2*pi()*k*m/tfd.size()));
|
|
|
|
}
|
|
|
|
complex zm = mean + sum;
|
|
|
|
*(cont_it++) = cv::Point(zm.real(), zm.imag());
|
2019-11-26 10:56:37 +01:00
|
|
|
}
|
|
|
|
return cont;
|
|
|
|
};
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
contour simplify_contour(const contour& cont, int cmax) {
|
|
|
|
contour res;
|
|
|
|
csignal z = cont2sig(cont);
|
|
|
|
complex zm = mean(z);
|
2019-11-26 13:50:55 +01:00
|
|
|
csignal tfd = fft(diff(z, zm));
|
2019-11-26 13:24:33 +01:00
|
|
|
return coef2cont(tfd, zm, 0, cmax);
|
|
|
|
};
|
|
|
|
|
2019-11-26 10:56:37 +01:00
|
|
|
int max_cont(const std::vector<contour>& contours) {
|
|
|
|
int max = 0;
|
|
|
|
int id = 0;
|
|
|
|
for (int i=0; i<contours.size(); ++i) {
|
|
|
|
if (contours[i].size() > max) {
|
|
|
|
max = contours[i].size();
|
|
|
|
id = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
};
|
|
|
|
}
|