使用FFTW+C++画2d字符“正“

对字符边缘线条采样

使用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

结果如下  直角处有点奇怪,至少有看的出来形状

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值