代码之家  ›  专栏  ›  技术社区  ›  G_T

平滑一个凹凸不平的圆

  •  3
  • G_T  · 技术社区  · 8 年前

    我正在检测圆形物体的边缘,并获得“凹凸不平”的不规则边缘。为了使我的形状更均匀,有没有把边缘磨平?

    例如,在下面的代码中,我生成了一个“凹凸”的圆(左)。是否有平滑或移动平均类型的函数,我可以用来获得或近似“平滑”圆(右)。最好使用某种参数,我可以控制实际图像,因为它不是完全圆形的。

    导入numpy as np 将matplotlib.pyplot导入为plt Fig,(凹凸,平滑)=plt.子批次(ncols=2,FigSize=(14,7)) an=np.linspace(0,2*np.pi,100) 凹凸图(3*np.cos(an)+np.random.normal(0.03100),3*np.sin(an)+np.random.normal(0.03100) 平滑绘图(3*np.cos(an),3*np.sin(an))

    
    

    .

    例如,在下面的代码中,我生成了一个“凹凸”的圆(左)。是否有平滑或移动平均类型的函数,我可以用来获得或近似“平滑”圆(右)。最好是有一些参数,我可以控制,因为我的实际图像不是完全圆形的。

    import numpy as np
    import matplotlib.pyplot as plt
    
    fig, (bumpy, smooth) = plt.subplots(ncols=2, figsize=(14, 7))
    
    an = np.linspace(0, 2 * np.pi, 100) 
    
    bumpy.plot(3 * np.cos(an) + np.random.normal(0,.03,100), 3 * np.sin(an) + np.random.normal(0,.03,100))
    
    smooth.plot(3 * np.cos(an), 3 * np.sin(an))
    

    3 回复  |  直到 8 年前
        1
  •  5
  •   dhanushka    8 年前
    signal = x + yj

    import numpy as np
    from matplotlib import pyplot as plt
    
    r = 3
    theta = np.linspace(0, 2 * np.pi, 100) 
    noise_level = 2
    # construct the signal
    x = r *  np.cos(theta) + noise_level * np.random.normal(0,.03,100)
    y = r *  np.sin(theta) + noise_level * np.random.normal(0,.03,100)
    signal = x + 1j*y
    # FFT and frequencies
    fft = np.fft.fft(signal)
    freq = np.fft.fftfreq(signal.shape[-1])
    # filter
    cutoff = 0.1
    fft[np.abs(freq) > cutoff] = 0
    # IFFT
    signal_filt = np.fft.ifft(fft)
    
    plt.figure()
    plt.subplot(121)
    plt.axis('equal')
    plt.plot(x, y, label='Noisy')
    plt.subplot(122)
    plt.axis('equal')
    plt.plot(signal_filt.real, signal_filt.imag, label='Smooth')
    

    figure

        2
  •  6
  •   Cris Luengo    8 年前
    This Q&A shows how to accomplish that using MATLAB

    import numpy as np
    import matplotlib.pyplot as plt
    
    # Some test data (from Question, but with offset added):
    an = np.linspace(0, 2 * np.pi, 100) 
    x = 3 * np.cos(an) + np.random.normal(0,.03,100) + 3.8
    y = 3 * np.sin(an) + np.random.normal(0,.03,100) + 5.4
    
    plt.plot(x, y)
    
    # Approximate the ellipse:
    L, V = np.linalg.eig(np.cov(x, y))
    r = np.sqrt(2*L)                       # radius
    cos_phi = V[0, 0]
    sin_phi = V[1, 0]                      # two components of minor axis direction
    m = np.array([np.mean(x), np.mean(y)]) # centroid
    
    # Draw the ellipse:
    x_approx = r[0] * np.cos(an) * cos_phi - r[1] * np.sin(an) * sin_phi + m[0];
    y_approx = r[0] * np.cos(an) * sin_phi + r[1] * np.sin(an) * cos_phi + m[1];
    
    plt.plot(x_approx, y_approx, 'r')
    plt.show()
    

    fitted ellipse

    a slightly more complex centroid computation is needed

        3
  •  3
  •   Spektre    8 年前
    喜欢

    p(i) = 0.5*p(i) + 0.25*p(i-1) + 0.25*p(i+1) 
    

    在哪里? p(i) i-th 点。记住原著是个好主意 P(I) 因为它用于下一次迭代(以避免移位)。您可以分别处理每个轴。您可以使用任何权重,但它们的和应为1.0。你可以使用任何数量的邻居,不仅仅是2个(但在这种情况下,你需要记住更多的要点)。对称的重量会减少移动。你可以多次使用fir…

    这里小 2D C++ 例子:

    //---------------------------------------------------------------------------
    const int n=50;     // points
    float pnt[n][2];    // points x,y ...
    //---------------------------------------------------------------------------
    void pnt_init()
        {
        int i;
        float a,da=2.0*M_PI/float(n),r;
        Randomize();
        for (a=0.0,i=0;i<n;i++,a+=da)
            {
            r=0.75+(0.2*Random());
            pnt[i][0]=r*cos(a);
            pnt[i][1]=r*sin(a);
            }
        }
    //---------------------------------------------------------------------------
    void pnt_smooth()
        {
        int i,j;
        float p0[2],*p1,*p2,tmp[2],aa0[2],aa1[2],bb0[2],bb1[2];
        // bb = original BBOX
        for (j=0;j<2;j++) { bb0[j]=pnt[0][j]; bb1[j]=pnt[0][j]; }
        for (i=0;i<n;i++)
         for (p1=pnt[i],j=0;j<2;j++)
            {
            if (bb0[j]>p1[j]) bb0[j]=p1[j];
            if (bb1[j]<p1[j]) bb1[j]=p1[j];
            }
        // FIR filter
        for (j=0;j<2;j++) p0[j]=pnt[n-1][j];                    // remember p[i-1]
        p1=pnt[0]; p2=pnt[1];                                   // pointers to p[i],p[i+1]
        for (i=0;i<n;i++,p1=p2,p2=pnt[(i+1)%n])
            {
            for (j=0;j<2;j++)
                {
                tmp[j]=p1[j];                                   // store original p[i]
                p1[j]=(0.1*p0[j]) + (0.8*p1[j]) + (0.1*p2[j]);  // p[i] = FIR(p0,p1,p2)
                p0[j]=tmp[j];                                   // remeber original p1 as p[i-1] for next iteration
                }
            }
        // aa = new BBOX
        for (j=0;j<2;j++) { aa0[j]=pnt[0][j]; aa1[j]=pnt[0][j]; }
        for (i=0;i<n;i++)
         for (p1=pnt[i],j=0;j<2;j++)
            {
            if (aa0[j]>p1[j]) aa0[j]=p1[j];
            if (aa1[j]<p1[j]) aa1[j]=p1[j];
            }
        // compute scale transform aa -> bb
        for (j=0;j<2;j++) tmp[j]=(bb1[j]-bb0[j])/(aa1[j]-aa0[j]);   // scale
        // convert aa -> bb
        for (i=0;i<n;i++)
         for (p1=pnt[i],j=0;j<2;j++)
          p1[j]=bb0[0]+((p1[j]-aa0[j])*tmp[j]);
        }
    //---------------------------------------------------------------------------
    

    我还添加了在平滑之前和之后检查bbox,这样形状就不会改变大小和位置。在某些情况下,质心在位置校正方面优于bbox。

    这里预览了FIR滤波器的多种应用:

    preview