2019-11-26 10:56:37 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <complex>
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
#include <iterator>
|
|
|
|
|
|
|
|
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-28 16:08:21 +01:00
|
|
|
int filter(const cv::Mat& img, cv::Mat output, int seuil) {
|
|
|
|
bool detect = false;
|
|
|
|
uchar R, G, B;
|
|
|
|
int rows = img.rows;
|
|
|
|
int cols = img.cols;
|
|
|
|
int dim = img.channels();
|
|
|
|
int indexNB;
|
|
|
|
|
|
|
|
for (int index=0,indexNB=0;index<dim*rows*cols;index+=dim,indexNB++) {
|
|
|
|
detect=0;
|
|
|
|
B = img.data[index ];
|
|
|
|
G = img.data[index + 1];
|
|
|
|
R = img.data[index + 2];
|
|
|
|
|
|
|
|
if ((R>G) && (R>B))
|
|
|
|
if (((R-B)>=seuil) || ((R-G)>=seuil))
|
|
|
|
detect=1;
|
|
|
|
if (detect==1)
|
|
|
|
output.data[indexNB]=255;
|
|
|
|
else
|
|
|
|
output.data[indexNB]=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal cont2sig(const contour& cont) {
|
|
|
|
csignal sig;
|
2019-11-28 16:08:21 +01:00
|
|
|
for (auto p: cont) {
|
|
|
|
sig.push_back(complex(p.x, p.y));
|
2019-11-26 13:24:33 +01:00
|
|
|
}
|
|
|
|
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) {
|
2019-11-28 16:08:21 +01:00
|
|
|
res.push_back(x-mean);
|
2019-11-26 13:50:55 +01:00
|
|
|
}
|
|
|
|
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();
|
|
|
|
|
2019-11-26 18:01:16 +01:00
|
|
|
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;
|
2019-11-26 18:01:16 +01:00
|
|
|
auto odd_back_it = std::back_inserter(odd);
|
|
|
|
auto even_back_it = std::back_inserter(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) {
|
2019-11-26 18:01:16 +01:00
|
|
|
*(even_back_it++) = *it;
|
2019-11-26 10:56:37 +01:00
|
|
|
insert_in_even = false;
|
|
|
|
} else {
|
2019-11-26 18:01:16 +01:00
|
|
|
*(odd_back_it++) = *it;
|
2019-11-26 10:56:37 +01:00
|
|
|
insert_in_even = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 13:24:33 +01:00
|
|
|
csignal odd_fft = fft_rec(odd);
|
|
|
|
csignal even_fft = fft_rec(even);
|
2019-11-26 18:01:16 +01:00
|
|
|
csignal res(size, complex());
|
2019-11-26 10:56:37 +01:00
|
|
|
|
2019-11-26 18:01:16 +01:00
|
|
|
for (int k=0; k<size/2; ++k) {
|
|
|
|
complex t = std::exp(complex(0, -2*pi()*k/size)) * odd_fft[k];
|
|
|
|
res[k] = even_fft[k] + t;
|
|
|
|
res[size/2+k] = even_fft[k] - t;
|
2019-11-26 10:56:37 +01:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 18:01:16 +01:00
|
|
|
csignal fft(const csignal& input, int N=0) {
|
|
|
|
int opt_size;
|
|
|
|
if (N < input.size()) {
|
|
|
|
opt_size = 1 << (int)std::ceil(std::log(input.size())/std::log(2));
|
2019-11-28 16:08:21 +01:00
|
|
|
} else if (N==0){
|
|
|
|
opt_size = input.size();
|
2019-11-26 18:01:16 +01:00
|
|
|
} else {
|
|
|
|
opt_size = 1 << (int)std::ceil(std::log(N)/std::log(2));
|
|
|
|
}
|
2019-11-26 14:22:52 +01:00
|
|
|
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-28 16:08:21 +01:00
|
|
|
void operator*=(csignal& sig, complex& m) {
|
|
|
|
for(auto x: sig) {
|
|
|
|
x *= m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator*=(csignal& sig, complex&& m) {
|
|
|
|
for(auto x: sig) {
|
|
|
|
x *= m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator/=(csignal& sig, complex& m) {
|
|
|
|
for(auto x: sig) {
|
|
|
|
x /= m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator/=(csignal& sig, complex&& m) {
|
|
|
|
for(auto x: sig) {
|
|
|
|
x /= m;
|
|
|
|
}
|
|
|
|
}
|
2019-11-26 13:45:25 +01:00
|
|
|
|
2019-11-28 16:08:21 +01:00
|
|
|
csignal extract(const csignal& tfd, int cmax) {
|
|
|
|
csignal res;
|
|
|
|
for (int k=0; k<cmax; ++k) {
|
|
|
|
res.push_back(tfd[tfd.size() - cmax + k]);
|
|
|
|
}
|
|
|
|
for (int k=cmax; k<2*cmax; ++k) {
|
|
|
|
res.push_back(tfd[k]);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
contour sig2cont(const csignal& sig) {
|
|
|
|
contour res;
|
|
|
|
for (auto x: sig) {
|
|
|
|
res.push_back(cv::Point(x.real(), x.imag()));
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
csignal desc2sig(const csignal& desc, complex mean, int N, int kmin) {
|
|
|
|
csignal cont;
|
|
|
|
auto desc_it = desc.begin();
|
|
|
|
|
|
|
|
for (int m=0; m<N; ++m) {
|
2019-11-26 13:45:25 +01:00
|
|
|
complex sum;
|
2019-11-28 16:08:21 +01:00
|
|
|
for (int k=0; k<desc.size(); ++k) {
|
|
|
|
sum += desc[k]*std::exp(complex(0, 2*pi()*(k+kmin)*m/N));
|
2019-11-26 13:45:25 +01:00
|
|
|
}
|
2019-11-28 16:08:21 +01:00
|
|
|
cont.push_back(mean + sum);
|
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) {
|
|
|
|
csignal z = cont2sig(cont);
|
|
|
|
complex zm = mean(z);
|
2019-11-26 13:50:55 +01:00
|
|
|
csignal tfd = fft(diff(z, zm));
|
2019-11-28 16:08:21 +01:00
|
|
|
tfd /= tfd.size();
|
|
|
|
csignal desc = extract(tfd, cmax);
|
|
|
|
|
|
|
|
if (std::abs(desc[desc.size()-1]) > std::abs(desc[0])) {
|
|
|
|
std::reverse(desc.begin(), desc.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
double phy = std::arg(desc[desc.size()-1]*desc[0])/2;
|
|
|
|
desc *= std::exp(complex(0, -phy));
|
|
|
|
double theta = std::arg(desc[0]);
|
|
|
|
|
|
|
|
for (int k=0; k<desc.size(); ++k) {
|
|
|
|
desc[k] *= std::exp(complex(0, -theta*k));
|
|
|
|
}
|
|
|
|
desc /= desc[0];
|
|
|
|
|
|
|
|
csignal sig = desc2sig(desc, zm, z.size(), cmax);
|
|
|
|
return sig2cont(sig);
|
2019-11-26 13:24:33 +01:00
|
|
|
};
|
|
|
|
|
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;
|
2019-11-28 16:08:21 +01:00
|
|
|
}
|
2019-11-26 10:56:37 +01:00
|
|
|
}
|
|
|
|
return id;
|
|
|
|
};
|
|
|
|
}
|