对字符边缘线条采样
使用FFTW库进行变换
c++代码如下
#include <fftw3.h>
int main(void){
#if 0
//小写k
const int N = 14;
static double inX[] = {
34.5543,24.6715,7.1652,7.0168,7.0168,-0.2379,-0.2379,7.0168,7.0168,7.1652,23.784,33.1105,14.6043,34.5543
};
static double inY[] = {
-32.3503,-32.3503,-52.0769,-52.0769,-32.3503,-32.3503,-92.9378,-92.9378,-54.5206,-54.5206,-73.2847,-73.2847,-53.5956,-32.3503
};
#endif
#if 1
//正字
const int N = 60;
static double inX[N] = {
-38.2939,-34.272,-30.2502,-26.2283,-26.2283,-26.2283,-26.2283,-24.1059,-21.9835,-19.8611,-19.8611,-19.8611,-19.8611,
-13.5939,-7.3267,-1.0595,-1.0595,-1.0595,-1.0595,-12.3356,-23.6116,-34.8877,-34.8877,-34.8877,-34.8877,-12.434,
10.0196,32.4733,32.4733,32.4733,32.4733,23.4175,14.3618,5.3061,5.3061,5.3061,5.3061,13.5228,21.7394,29.9561,29.9561,
29.9561,29.9561,21.7394,13.5228,5.3061,5.3061,5.3061,5.3061,15.3488,25.3915,35.4342,35.4342,35.4342,35.4342,10.8582,
-13.7179,-38.2939,-38.2939,-38.2939
};
static double inY[N] = {
-6.6747,-6.6747,-6.6747,-6.6747,-19.9002,-33.1257,-46.3512,-46.3512,-46.3512,-46.3512,-33.1257,-19.9002,-6.6747,-6.6747,
-6.6747,-6.6747,-23.4289,-40.183,-56.9372,-56.9372,-56.9372,-56.9372,-58.8617,-60.7861,-62.7106,-62.7106,-62.7106,-62.7106,
-60.7861,-58.8617,-56.9372,-56.9372,-56.9372,-56.9372,-50.4726,-44.008,-37.5434,-37.5434,-37.5434,-37.5434,-35.6434,-33.7434,
-31.8434,-31.8434,-31.8434,-31.8434,-23.4538,-15.0643,-6.6747,-6.6747,-6.6747,-6.6747,-4.7502,-2.8257,-0.9012,-0.9012,-0.9012,
-0.9012,-2.8257,-4.7502
};
#endif
const int DIM = 2;
double(*in_cpx)[N] = (double(*)[N])fftw_malloc(sizeof(double) * DIM * N);
for (int i = 0; i < N; i++) {
in_cpx[0][i] = inX[i];
in_cpx[1][i] = inY[i];
}
const int out_N = N / 2 + 1;
fftw_complex (*out_cpx)[out_N] = (fftw_complex(*)[out_N])fftw_malloc(sizeof(fftw_complex) * DIM * out_N);
fftw_plan fft = fftw_plan_dft_r2c_2d(DIM,N, &in_cpx[0][0], &out_cpx[0][0], FFTW_ESTIMATE);
fftw_execute(fft);
//频域
struct FreqDomain {
double freq; //频率
double amp; //振幅
double phase; //相位
static bool sort_amp(const FreqDomain& a, const FreqDomain& b){ //按振幅排序 从高到低
return a.amp > b.amp;
}
};
FreqDomain (*fd)[out_N] = (FreqDomain(*)[out_N])malloc(sizeof(FreqDomain) * DIM * out_N);
for (int dim = 0; dim < DIM; dim++) {
for (int i = 0; i < out_N; i++) {
double amp = sqrt(out_cpx[dim][i][0] * out_cpx[dim][i][0] + out_cpx[dim][i][1] * out_cpx[dim][i][1]);
amp = amp /N / 2.;
double phase = atan2(out_cpx[dim][i][1], out_cpx[dim][i][0]);
fd[dim][i] = { (double)i,amp ,phase };
}
}
std::sort(&fd[0][0], &fd[0][out_N - 1], FreqDomain::sort_amp); //优先选择振幅大的对形状影响大
std::sort(&fd[1][0], &fd[1][out_N - 1], FreqDomain::sort_amp);
printf("\n(频率 - 幅度 - 相位):\n");
for (int dim = 0; dim < 2; dim++) {
for (int i = 0; i < out_N; i++) {
//cout << fd[dim][i].freq << " - " << fd[dim][i].amp << " - " << fd[dim][i].phase << "\n";
if(fd[dim][i].freq!=0.)
cout << "cos(t*" << fd[dim][i].freq << ".+" << fd[dim][i].phase << ")*" << fd[dim][i].amp << "+" << "\n";
}
cout << "\n\n" << endl;
}
free(fd);
fftw_destroy_plan(fft);
fftw_free(in_cpx);
fftw_free(out_cpx);
return 0;
}
为了方便,把得到的输出做成代码字符
选取前十五项在在线shader中展现
可把以下glsl代码完整Ctrl+A Ctrl+V 粘贴到
glsl着色器语言在线编辑器 | 踏得网 (techbrood.com)
#ifdef GL_ES
precision mediump float;
#endif
//www.shadertoy.com/view/3ljXWK
uniform vec2 u_resolution; //canvas size (width,height)
uniform vec2 u_mouse; //mouse position in screen pixels
uniform float u_time; //time in seconds since load
const float pi2=6.283185307179586476925286766559;
const float pi=3.1415926535897932384626433832795;
float seg(vec2 p, vec2 a,vec2 b){
p -= a, b -= a;
return length(p - b *clamp(dot(p, b) / dot(b, b), 0., 1.));
}
mat2 rot2(float a){
float c=cos(a),s=sin(a);
return mat2(c,-s,s,c);
}
vec2 fun(float t){
return vec2(
cos(t*1.+1.21726)*7.83828+cos(t*5.+-1.91267)*4.96699+cos(t*3.+2.22147)*4.94093+
cos(t*2.+2.74981)*2.58167+cos(t*4.+0.738464)*2.04554+cos(t*7.+-1.89346)*1.16736+cos(t*6.+-1.34842)*0.896264+
cos(t*9.+-1.28521)*0.836555+cos(t*15.+1.91267)*0.665449+cos(t*11.+1.28521)*0.581258+cos(t*13.+1.89346)*0.378547+
cos(t*25.+-1.91267)*0.356616+cos(t*17.+-2.22147)*0.200202+cos(t*14.+1.34842)*0.191153+cos(t*29.+-1.28521)*0.172894
,
cos(t*1.+2.856)*9.97011+cos(t*5.+-2.79972)*4.96699+cos(t*3.+-2.81893)*3.12151+
cos(t*7.+-0.650674)*1.84778+cos(t*4.+2.91921)*1.43848+cos(t*6.+0.832333)*1.2745+cos(t*15.+2.79972)*0.66545+
cos(t*9.+0.353534)*0.657681+cos(t*13.+0.650673)*0.599188+cos(t*8.+-1.17901)*0.524768+
cos(t*11.+-0.353536)*0.456974+cos(t*25.+-2.79972)*0.356616+cos(t*14.+-0.832328)*0.27182+
cos(t*12.+1.179)*0.25128+cos(t*2.+-2.38645)*0.24988
);
}
void main() {
float t=u_time*0.5;
vec2 st = gl_FragCoord.xy/u_resolution.xy-0.5;
st.x *= u_resolution.x/u_resolution.y;
st*=50.;
vec3 color = vec3(1.);
float n=1.e10;
vec2 a=fun(0.);
for(float i=1.;i<101.;i++){
float ia=i/100.*pi2;
vec2 b=fun(ia);
n=min(n,seg(st*rot2(pi*0.25),a,b)-0.172);
a=b;
}
color=mix(vec3(0.2,0.5,0.9),color,smoothstep(0.,0.03,n));
color=mix(vec3(0.),color,0.5+smoothstep(0.,0.002,min(abs(st.x),abs(st.y))-0.1));
gl_FragColor = vec4(color,1.0);
}
使用圆弧多的图形效果更好, 参考 www.shadertoy.com/view/3ljXWK
结果如下 直角处有点奇怪,至少有看的出来形状