snake_snaker - CSDN
snake 订阅
Snake
信息
操作系统
未知
开发语言
开源协议
未知
Snake
Snake is a clone of the popular Snake or Worm... 已更新 2007 年 03 月 5 日
收起全文
精华内容
参与话题
  • snake算法总结

    千次阅读 2018-06-07 14:08:45
    snake是一种主动轮廓模型,笨妞对主动轮廓模型的理解:你先给它一个初始轮廓,模型以初始轮廓为基准逐步迭代,来改进图像的轮廓,使其更加精确。主动轮廓模型目前用到了2种:CV和snake。前者没有看算法内部的原理。...

    snake是一种主动轮廓模型,笨妞对主动轮廓模型的理解:你先给它一个初始轮廓,模型以初始轮廓为基准逐步迭代,来改进图像的轮廓,使其更加精确。主动轮廓模型目前用到了2种:CV和snake。前者没有看算法内部的原理。而snake,以最原始的论文《Snakes: Active Contour Models》为出发点。


    1. snake原理

    snake在逐步迭代优化过程的目标是能量函数最小化,这个能量函数指的是轮廓能量和图像能量的总和(为什么要最小化这个能量总和,还不太清楚,论文也没有具体说)。snake的目标不像sobel、canny等找到整张图的轮廓。它只搜索你给出的初始轮廓附近,达到轮廓更精确的目标,至少原版的snake只能达到局部优化的目标。

    能量函数:


    其中指当前轮廓本身的能量,称为内部能量,而指图像上轮廓对应点的能量,称为外部能量,应该是方差相关的项。

    而内部能量由两部分构成:一阶导数的模(称为弹性能量)和二阶导数的模(弯曲能量)


    为什么是这样的呢?据说是因为曲线曲率的关系,闭合的轮廓曲线中,凸曲线按照法向量的方向,具有向内的作用力;凹曲线法向量向外,具有向外的力。而曲率计算就是跟一阶导数、二阶导数相关的。很复杂,不甚理解。

    在迭代过程中,弹性能量能快速的把轮廓压缩成光滑的圆;弯曲能量将轮廓拉成光滑的曲线或直线,他们的作用是保持轮廓的光滑和连续性。通常alpha越大,轮廓收敛越快;beta越大,轮廓越光滑。

    外部图像能量作者分了三种:线性能量,通常更亮度相关;边缘能量,由图像的边缘组成,而边缘可以通过sobel算子计算;终端能量。

    线性能量:

    边缘能量:

    终端(角点)能量:


    通常可以根据更期望轮廓趋向于哪方面来选择以上三种能量。在迭代优化过程中,外部能量会使轮廓朝(灰度)高梯度位置靠近。而通常梯度高的位置都是图像中前景与背景的界限或者物体与物体之间、物体内部不同部分的界限,适合用于分割。


    对于优化,优化的目标是总能量函数局部极小,通过能量函数极小或者迭代次数来控制迭代的终止。极小化能量函数通过欧拉方程计算解,作者在附录中用了数值方法进行推到,将欧拉方程推到为:


    其中


    引入外部能量:


    再转化为每一步迭代演进过程:


    A+ rI为五对角条带矩阵。


    2. GVF snake

    关于图像能量中line、edge、termatation计算其实都挺复杂的。反倒是计算梯度向量场简单一些。将图像能量由线、边缘、角点的能量替换为梯度向量场,就是GVF snake。


    3. 程序

    对于snake,skimage里面active_contour函数就是典型的snake算法,借用里面的实现程序:

    import numpy as np
    import scipy.linalg
    from scipy.interpolate import RectBivariateSpline
    from skimage.util import img_as_float
    from skimage.filters import sobel
    
    
    def active_contour(image, snake, alpha=0.01, beta=0.1,
                       w_line=0, w_edge=1, gamma=0.01,
                       bc='periodic', max_px_move=1.0,
                       max_iterations=2500, convergence=0.1):
        """Active contour model.
        Active contours by fitting snakes to features of images. Supports single
        and multichannel 2D images. Snakes can be periodic (for segmentation) or
        have fixed and/or free ends.
        The output snake has the same length as the input boundary.
        As the number of points is constant, make sure that the initial snake
        has enough points to capture the details of the final contour.
        Parameters
        ----------
        image : (N, M) or (N, M, 3) ndarray
            Input image.
        snake : (N, 2) ndarray
            Initialisation coordinates of snake. For periodic snakes, it should
            not include duplicate endpoints.
        alpha : float, optional
            Snake length shape parameter. Higher values makes snake contract
            faster.
        beta : float, optional
            Snake smoothness shape parameter. Higher values makes snake smoother.
        w_line : float, optional
            Controls attraction to brightness. Use negative values to attract to
            dark regions.
        w_edge : float, optional
            Controls attraction to edges. Use negative values to repel snake from
            edges.
        gamma : float, optional
            Explicit time stepping parameter.
        bc : {'periodic', 'free', 'fixed'}, optional
            Boundary conditions for worm. 'periodic' attaches the two ends of the
            snake, 'fixed' holds the end-points in place, and'free' allows free
            movement of the ends. 'fixed' and 'free' can be combined by parsing
            'fixed-free', 'free-fixed'. Parsing 'fixed-fixed' or 'free-free'
            yields same behaviour as 'fixed' and 'free', respectively.
        max_px_move : float, optional
            Maximum pixel distance to move per iteration.
        max_iterations : int, optional
            Maximum iterations to optimize snake shape.
        convergence: float, optional
            Convergence criteria.
        Returns
        -------
        snake : (N, 2) ndarray
            Optimised snake, same shape as input parameter.
        References
        ----------
        .. [1]  Kass, M.; Witkin, A.; Terzopoulos, D. "Snakes: Active contour
                models". International Journal of Computer Vision 1 (4): 321
                (1988).
        Examples
        --------
        >>> from skimage.draw import circle_perimeter
        >>> from skimage.filters import gaussian
        Create and smooth image:
        >>> img = np.zeros((100, 100))
        >>> rr, cc = circle_perimeter(35, 45, 25)
        >>> img[rr, cc] = 1
        >>> img = gaussian(img, 2)
        Initiliaze spline:
        >>> s = np.linspace(0, 2*np.pi,100)
        >>> init = 50*np.array([np.cos(s), np.sin(s)]).T+50
        Fit spline to image:
        >>> snake = active_contour(img, init, w_edge=0, w_line=1) #doctest: +SKIP
        >>> dist = np.sqrt((45-snake[:, 0])**2 +(35-snake[:, 1])**2) #doctest: +SKIP
        >>> int(np.mean(dist)) #doctest: +SKIP
        25
        """
        max_iterations = int(max_iterations)
        if max_iterations <= 0:
            raise ValueError("max_iterations should be >0.")
        convergence_order = 10
        valid_bcs = ['periodic', 'free', 'fixed', 'free-fixed',
                     'fixed-free', 'fixed-fixed', 'free-free']
        if bc not in valid_bcs:
            raise ValueError("Invalid boundary condition.\n" +
                             "Should be one of: "+", ".join(valid_bcs)+'.')
        img = img_as_float(image)
        height = img.shape[0]
        width = img.shape[1]
        RGB = img.ndim == 3
    
        # Find edges using sobel:
        if w_edge != 0:
            if RGB:
                edge = [sobel(img[:, :, 0]), sobel(img[:, :, 1]),
                        sobel(img[:, :, 2])]
            else:
                edge = [sobel(img)]
            for i in range(3 if RGB else 1):
                edge[i][0, :] = edge[i][1, :]
                edge[i][-1, :] = edge[i][-2, :]
                edge[i][:, 0] = edge[i][:, 1]
                edge[i][:, -1] = edge[i][:, -2]
        else:
            edge = [0]
    
        # Superimpose intensity and edge images:
        if RGB:
            img = w_line*np.sum(img, axis=2) \
                + w_edge*sum(edge)
        else:
            img = w_line*img + w_edge*edge[0]
    
        # Interpolate for smoothness:
        intp = RectBivariateSpline(np.arange(img.shape[1]),
                                   np.arange(img.shape[0]),
                                   img.T, kx=2, ky=2, s=0)
    
        x, y = snake[:, 0].astype(np.float), snake[:, 1].astype(np.float)
        xsave = np.empty((convergence_order, len(x)))
        ysave = np.empty((convergence_order, len(x)))
    
        # Build snake shape matrix for Euler equation
        n = len(x)
        a = np.roll(np.eye(n), -1, axis=0) + \
            np.roll(np.eye(n), -1, axis=1) - \
            2*np.eye(n)  # second order derivative, central difference
        b = np.roll(np.eye(n), -2, axis=0) + \
            np.roll(np.eye(n), -2, axis=1) - \
            4*np.roll(np.eye(n), -1, axis=0) - \
            4*np.roll(np.eye(n), -1, axis=1) + \
            6*np.eye(n)  # fourth order derivative, central difference
        A = -alpha*a + beta*b
    
        # Impose boundary conditions different from periodic:
        sfixed = False
        if bc.startswith('fixed'):
            A[0, :] = 0
            A[1, :] = 0
            A[1, :3] = [1, -2, 1]
            sfixed = True
        efixed = False
        if bc.endswith('fixed'):
            A[-1, :] = 0
            A[-2, :] = 0
            A[-2, -3:] = [1, -2, 1]
            efixed = True
        sfree = False
        if bc.startswith('free'):
            A[0, :] = 0
            A[0, :3] = [1, -2, 1]
            A[1, :] = 0
            A[1, :4] = [-1, 3, -3, 1]
            sfree = True
        efree = False
        if bc.endswith('free'):
            A[-1, :] = 0
            A[-1, -3:] = [1, -2, 1]
            A[-2, :] = 0
            A[-2, -4:] = [-1, 3, -3, 1]
            efree = True
    
        # Only one inversion is needed for implicit spline energy minimization:
        inv = scipy.linalg.inv(A+gamma*np.eye(n))
    
        # Explicit time stepping for image energy minimization:
        for i in range(max_iterations):
            fx = intp(x, y, dx=1, grid=False)
            fy = intp(x, y, dy=1, grid=False)
            if sfixed:
                fx[0] = 0
                fy[0] = 0
            if efixed:
                fx[-1] = 0
                fy[-1] = 0
            if sfree:
                fx[0] *= 2
                fy[0] *= 2
            if efree:
                fx[-1] *= 2
                fy[-1] *= 2
            xn = np.dot(inv, gamma*x + fx)
            yn = np.dot(inv, gamma*y + fy)
    
            # Movements are capped to max_px_move per iteration:
            dx = max_px_move*np.tanh(xn-x)
            dy = max_px_move*np.tanh(yn-y)
            if sfixed:
                dx[0] = 0
                dy[0] = 0
            if efixed:
                dx[-1] = 0
                dy[-1] = 0
            x += dx
            y += dy
            x[x<0] = 0
            y[y<0] = 0
            x[x>(height-1)] = height - 1
            y[y>(width-1)] = width - 1
    		
    
            # Convergence criteria needs to compare to a number of previous
            # configurations since oscillations can occur.
            j = i % (convergence_order+1)
            if j < convergence_order:
                xsave[j, :] = x
                ysave[j, :] = y
            else:
                dist = np.min(np.max(np.abs(xsave-x[None, :]) +
                                     np.abs(ysave-y[None, :]), 1))
                if dist < convergence:
                    break
    
        return np.array([x, y]).T

    这个程序有个bug,没有对新计算出的轮廓做约束,这样的话如果初始snake比较靠近图像的边,那么轮廓就会溢出到图像外。红色部分是个人做的修改。


    另外一个简化的gvf snake程序

    file_name = '24_82_11.bmp'
    #file_path = os.path.join('cell_split/23-2018-05-1708.57.22', file_name)
    img = skimage.color.rgb2gray(skimage.data.imread(file_name))
    f = filters.gaussian_gradient_magnitude(img,2.0)
    fx = filters.gaussian_filter(f,2.0,(1,0))
    fy = filters.gaussian_filter(f,2.0,(0,1))
    u = fx.copy()
    v = fy.copy()
    mu = 0.1
    for i in range(10000):
        m = (fx**2+fy**2)
        ut = mu*filters.laplace(u)-(u-fx)*m
        vt = mu*filters.laplace(v)-(v-fy)*m
        u += ut
        v += vt
    
    t = np.linspace(0,2*np.pi,50)
    
    for t in range(5000):
        x2 = filters.gaussian_filter(path,1.0,(2,0),mode='wrap')
        x4 = filters.gaussian_filter(x2,1.0,(2,0),mode='wrap')
        dx = np.array([u[int(x),int(y)] for y,x in path])
        dy = np.array([v[int(x),int(y)] for y,x in path])
        delta = np.array([dx,dy]).T
        path += 0.001*x2-0.001*x4+1.0*delta
        #print(path.shape)
        path[:,0][path[:,0]>129] = 129
        path[:,1][path[:,1]>105] = 105
    这个gvf snake基本的骨架是对的,但是太简单了,效果确实不好。





    展开全文
  • snake模型简介

    千次阅读 2018-01-04 15:19:24
    图像分割之(五)活动轮廓模型之Snake模型简介 zouxy09@qq.com http://blog.csdn.net/zouxy09    在“图像分割之(一)概述”中咱们简单了解了目前主流的图像分割方法。下面咱们主要学习下基于能量泛函的分割方法...

    图像分割之(五)活动轮廓模型之Snake模型简介

    zouxy09@qq.com

    http://blog.csdn.net/zouxy09

     

           在“图像分割之(一)概述”中咱们简单了解了目前主流的图像分割方法。下面咱们主要学习下基于能量泛函的分割方法。这里学习下Snake模型简单的知识,Level Set(水平集)模型会在后面的博文中说到。

     

    基于能量泛函的分割方法:

           该类方法主要指的是活动轮廓模型(active contour model)以及在其基础上发展出来的算法,其基本思想是使用连续曲线来表达目标边缘,并定义一个能量泛函使得其自变量包括边缘曲线,因此分割过程就转变为求解能量泛函的最小值的过程,一般可通过求解函数对应的欧拉(EulerLagrange)方程来实现,能量达到最小时的曲线位置就是目标的轮廓所在。

           主动轮廓线模型是一个自顶向下定位图像特征的机制,用户或其他自动处理过程通过事先在感兴趣目标附近放置一个初始轮廓线,在内部能量(内力)和外部能量(外力)的作用下变形外部能量吸引活动轮廓朝物体边缘运动,而内部能量保持活动轮廓的光滑性和拓扑性,当能量达到最小时,活动轮廓收敛到所要检测的物体边缘。

     

    一、曲线演化理论

           曲线演化理论在水平集中运用到,但我感觉在主动轮廓线模型的分割方法中,这个知识是公用的,所以这里我们简单了解下。

           曲线可以简单的分为几种:

           曲线存在曲率,曲率有正有负,于是在法向曲率力的推动下,曲线的运动方向之间有所不同:有些部分朝外扩展,而有些部分则朝内运动。这种情形如下图所示。图中蓝色箭头处的曲率为负,而绿色箭头处的曲率为正。

           简单曲线在曲率力(也就是曲线的二次导数)的驱动下演化所具有的一种非常特殊的数学性质是:一切简单曲线,无论被扭曲得多么严重,只要还是一种简单曲线,那么在曲率力的推动下最终将退化成一个圆,然后消逝(可以想象下,圆的所有点的曲率力都向着圆心,所以它将慢慢缩小,以致最后消逝)。

           描述曲线几何特征的两个重要参数是单位法矢和曲率,单位法矢描述曲线的方向,曲率则表述曲线弯曲的程度。曲线演化理论就是仅利用曲线的单位法矢和曲率等几何参数来研究曲线随时间的变形。曲线的演变过程可以认为是表示曲线在作用力 F 的驱动下,朝法线方向 N 以速度 v 演化。而速度是有正负之分的,所以就有如果速度 v 的符号为负,表示活动轮廓演化过程是朝外部方向的,如为正,则表示朝内部方向演化,活动曲线是单方向演化的,不可能同时往两个方向演化。

           所以曲线的演变过程,就是不同力在曲线上的作用过程,力也可以表达为能量。世界万物都趋向于能量最小而存在。因为此时它是最平衡的,消耗最小的(不知理解对不?)。那么在图像分割里面,我们目标是把目标的轮廓找到,那么在目标的轮廓这个地方,整个轮廓的能量是最小的,那么曲线在图像任何一个地方,都可以因为力朝着这个能量最小的轮廓演变,当演变到目标的轮廓的时候,因为能量最小,力平衡了,速度为0了,也就不动了,这时候目标就被我们分割出来了。

            那现在关键就在于:1)这个轮廓我们怎么表示;2)这些力怎么构造,构造哪些力才可以让目标轮廓这个地方的能量最小?

           这两个问题的描述和解决就衍生出了很多的基于主动轮廓线模型的分割方法。第一个问题的回答,就形成了两大流派:如果这个轮廓是参数表示的,那么就是参数活动轮廓模型(parametric active contour model),典型为snake模型,如果这个轮廓是几何表示的,那么就是几何活动轮廓模型(geometric active contour model),即水平集方法(Level Set),它是把二维的轮廓嵌入到三维的曲面的零水平面来表达的(可以理解为一座山峰的等高线,某个等高线把山峰切了,这个高度山峰的水平形状就出来了,也就是轮廓了),所以低维的演化曲线或曲面,表达为高维函数曲面的零水平集的间接表达形式(这个轮廓的变化,直观上我们就可以调整山峰的形状或者调整登高线的高度来得到)。

           那对于第二个问题,是两大流派都遇到的问题,是他们都需要解决的最关键的问题。哪些力才可以达到分割的目标呢?这将在后面聊到。

     

    二、Snakes模型

           自1987Kass提出Snakes模型以来,各种基于主动轮廓线的图像分割理解和识别方法如雨后春笋般蓬勃发展起来。Snakes模型的基本思想很简单,它以构成一定形状的一些控制点为模板(轮廓线),通过模板自身的弹性形变,与图像局部特征相匹配达到调和,即某种能量函数极小化,完成对图像的分割。再通过对模板的进一步分析而实现图像的理解和识别。

            简单的来讲,SNAKE模型就是一条可变形的参数曲线及相应的能量函数,以最小化能量目标函数为目标,控制参数曲线变形,具有最小能量的闭合曲线就是目标轮廓。

           构造Snakes模型的目的是为了调和上层知识和底层图像特征这一对矛盾。无论是亮度、梯度、角点、纹理还是光流,所有的图像特征都是局部的。所谓局部性就是指图像上某一点的特征只取决于这一点所在的邻域,而与物体的形状无关。但是人们对物体的认识主要是来自于其外形轮廓。如何将两者有效地融合在一起正是Snakes模型的长处。Snakes模型的轮廓线承载了上层知识,而轮廓线与图像的匹配又融合了底层特征。这两项分别表示为Snakes模型中能量函数的内部力和图像力

           模型的形变受到同时作用在模型上的许多不同的力所控制,每一种力所产生一部分能量,这部分能量表示为活动轮廓模型的能量函数的一个独立的能量项。

             Snake模型首先需要在感兴趣区域的附近给出一条初始曲线,接下来最小化能量泛函,让曲线在图像中发生变形并不断逼近目标轮廓。

            Kass等提出的原始Snakes模型由一组控制点:v(s)=[x(s), y(s)]   s[0, 1] 组成,这些点首尾以直线相连构成轮廓线。其中x(s)y(s)分别表示每个控制点在图像中的坐标位置。 s 是以傅立叶变换形式描述边界的自变量。在Snakes的控制点上定义能量函数(反映能量与轮廓之间的关系):

          其中第1项称为弹性能量v的一阶导数的模,第2项称为弯曲能量,是v的二阶导数的模,第3项是外部能量(外部力),在基本Snakes模型中一般只取控制点或连线所在位置的图像局部特征例如梯度:

    也称图像力。(当轮廓C靠近目标图像边缘,那么C的灰度的梯度将会增大,那么上式的能量最小,由曲线演变公式知道该点的速度将变为0,也就是停止运动了。这样,C就停在图像的边缘位置了,也就完成了分割。那么这个的前提就是目标在图像中的边缘比较明显了,否则很容易就越过边缘了。)

            弹性能量和弯曲能量合称内部能量(内部力),用于控制轮廓线的弹性形变,起到保持轮廓连续性和平滑性的作用。而第三项代表外部能量,也被称为图像能量,表示变形曲线与图像局部特征吻合的情况。内部能量仅仅跟snake的形状有关,而跟图像数据无关。而外部能量仅仅跟图像数据有关。在某一点的α和β的值决定曲线可以在这一点伸展和弯曲的程度。

           最终对图像的分割转化为求解能量函数Etotal(v)极小化(最小化轮廓的能量)。在能量函数极小化过程中,弹性能量迅速把轮廓线压缩成一个光滑的圆,弯曲能量驱使轮廓线成为光滑曲线或直线,而图像力则使轮廓线向图像的高梯度位置靠拢。基本Snakes模型就是在这3个力的联合作用下工作的。

            因为图像上的点都是离散的,所以我们用来优化能量函数的算法都必须在离散域里定义。所以求解能量函数Etotal(v)极小化是一个典型的变分问题(微分运算中,自变量一般是坐标等变量,因变量是函数;变分运算中,自变量是函数,因变量是函数的函数,即数学上所谓的泛函。对泛函求极值的问题,数学上称之为变分法)。

            在离散化条件(数字图像)下,由欧拉方程可知最终问题的答案等价于求解一组差分方程:(欧拉方程是泛函极值条件的微分表达式,求解泛函的欧拉方程,即可得到使泛函取极值的驻函数,将变分问题转化为微分问题。

           记外部力 F = − P Kass等将上式离散化后,对x(s)y(s)分别构造两个五对角阵的线性方程组,通过迭代计算进行求解。在实际应用中一般先在物体周围手动点出控制点作为Snakes模型的起始位置,然后对能量函数迭代求解。

     

         以上只是对snake简单的理解,如要深入,请参考其他更多专业文献。水平有限,错误在所难免,还望不吝指正。

     

    Reference

    李天庆等,Snake模型综述,计算机工程,2005,第31  9

    展开全文
  • Snake

    2019-08-03 10:02:49
    在学习操作系统这门课程时,老师让我们做个小游戏,来把之前学过的数据结构,操作系统的知识能在设计的过程中加深印象。 我做的是:贪吃蛇(会闪屏的贪吃蛇)和(没有棋盘)的五子棋。在那个只会C的时候,写的并...

       在学习操作系统这门课程时,老师让我们做个小游戏,来把之前学过的数据结构,操作系统的知识能在设计的过程中加深印象。

    我做的是:贪吃蛇(会闪屏的贪吃蛇)和(没有棋盘)的五子棋。在那个只会C的时候,写的并不好但也很开心。时间到了上半年,由于经常换操作系统(自己闲着没事瞎折腾),许多自己之前写的一些代码都丢了,没有拷贝下来。数独代码,2048游戏代码,贪吃蛇代码...都丢了。其实感觉好可惜,应该保存下来留个纪念也好,起码有个自己学习过的痕迹。在前几天,在同学的U盘中找到了当时用VC6.0写的贪吃蛇代码。现在再看代码发现里可以写的更好的地方有很多。这或许就是中进步。在这里仅贴出自己当时写的代码。当然在系统换成了ubuntu之后,也用GNU C编译器也写过贪吃蛇,这次解决了闪屏的问题。也知道了,编译器有好多种,有微软的编译器,也有GNU的编译器。大概从这以后系统就从win7换成了ubuntu来学习linux,中间也有试着把自己的笔记本系统换成CentOS,但安装没有成功,也就放弃去装CentOS。AMD的CPU和AMD的显卡,我比较悲催吧!网上找了好多和我一样的案例,按照他们的解决方法,问题依旧存在(瞎折腾的后果)。说了那么多,跑题了。还是把当时的代码贴出来吧!

    #include<iostream>
    #include<conio.h>
    #include<windows.h>
    #include<time.h>
    using namespace std;
    
    #define N 15
    #define M 15
    
    char Area[N][M];
    int snake[2][1000];
    
    void SetColor(unsigned short ForeColor=7,unsigned short BackGroundColor=0)
    {
        HANDLE Con=GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(Con,ForeColor|BackGroundColor);
    }
    
    void display(char Area[][M],int Score,int Speed)
    {
    
        system("cls");
        cout<<"       Score="<<Score<<"   Speed="<<Speed<<endl;
        for(int i=0;i<N;i++)
    {
    cout<<' '; for(int j=0;j<M;j++)
    { SetColor(j
    %15+1); cout<<Area[i][j]<<' '; } cout<<endl; }cout<<" By Guth "<<'\n'<<'\n'; } void dis() { int x,y; for(int i=0;i<N;i++) { for(int j=0;j<M;j++) { Area[i][j]=' '; } } for(int i=0;i<N;i++) { Area[0][i]=Area[N-1][i]='-'; Area[i][0]=Area[i][N-1]='|'; } srand(time(0)); do{ x=rand()%(N-2)+1; y=rand()%(M-2)+1; }while(Area[x][y]!=' '); snake[0][1]=x; snake[1][1]=y; Area[x][y]=1; } int main() { HANDLE hOut; CONSOLE_CURSOR_INFO cur_info={1,0}; hOut=GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorInfo(hOut,&cur_info); int head=1,tail=0; int x,y; char direction=77; int count=0; int Speed=180; int flag; dis(); srand(time(0)); do{ x=rand()%(N-2)+1; y=rand()%(M-2)+1; }while(Area[x][y]!=' '); Area[x][y]=3; display(Area,count,Speed); Sleep(1000); while(1) { int X,Y; if(kbhit()) { getch(); direction=getch(); } switch(direction) { case 72:X=snake[0][head]-1,Y=snake[1][head];break; case 80:X=snake[0][head]+1,Y=snake[1][head];break; case 75:X=snake[0][head],Y=snake[1][head]-1;break; case 77:X=snake[0][head],Y=snake[1][head]+1;break; default:cout<<"\t按键无效!"; return 0; } if(X==0||X==N-1||Y==0||Y==M-1) { cout<<"碰到墙壁!"; return 0; } if(Area[X][Y]!=' '&&!(X==x&&Y==y)) { cout<<"\t撞到自身!"; return 0; } if(x==X&&y==Y) { flag=0; count++; Area[snake[0][head]][snake[1][head]]=1; Area[X][Y]=1; head=(head+1)%100; snake[0][head]=X; snake[1][head]=Y; srand(time(0)); do{ x=rand()%(N-2)+1; y=rand()%(M-2)+1; }while(Area[x][y]!=' '); Area[x][y]=3; display(Area,count,Speed); } else { flag=1; Area[snake[0][tail]][snake[1][tail]]=' '; tail=(tail+1)%100; Area[snake[0][head]][snake[1][head]]=1; head=(head+1)%100; snake[0][head]=X; snake[1][head]=Y; Area[X][Y]=1; display(Area,count,Speed); } if(count%4==0&&flag==0){Speed=Speed-45;} Sleep(Speed); } return 0; }

    上面的代码和下面运行的gif图可能不太对应!(因为gif图是当时运行时的图,这个代码是我第几次改的,我已经不记得了,这也不重要了。)

     

    有点闪屏,现在再看上面的代码,int snake[2][2000]这样好可笑。内存什么的不要钱?这些我们不注意的点或许反映了一个的能力。


    其实当时,并不知道怎么去写贪吃蛇,因为它是动态的,自从我接触到了system("cls"),清屏。

    用数组[top++]和[head++]来模拟队列。上面的设计没有用到链表什么的感觉自己好lose。

    想到这里system("cls")我第一次是用在下面的



    跳动的心!当时好像是2.14那天,代码很简单!也有许多不足的地方,也贴出来,权当乐趣吧!


     

    #include<iostream>
    #include<windows.h>
    using namespace std;
    
    #define n 15
    #define m 21
    HANDLE hOut;
    CONSOLE_CURSOR_INFO cur_info={1,0};
    
    void SetColor(unsigned short ForeColor=7,unsigned short BackGroundColor=0)
    {
        HANDLE Con=GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(Con,ForeColor|BackGroundColor);
    }
    
                 char Xin[n][m]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,3,3,3,0,0,0,3,3,3,0,0,0,0,0,0,
                        0,0,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,0,0,0,0,
                        0,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,0,
                        0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,
                        0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,
                        0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,
                        0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,
                        0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,
                        0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,3,0,3,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
      
    void main()
    {
        hOut=GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleCursorInfo(hOut,&cur_info);
        
        int i,j,k;
    
    Loop:    for(i=0;i<n;i++)
            {
                for(j=0;j<m;j++)
                {
                k=rand()%10+2;
                SetColor(k);
                cout<<Xin[i][j]<<' ';
                }
                cout<<'\n';
            }
            system("cls");
            goto Loop;
    }

    还有个五子棋的,没有棋盘,无喷!当然后来也有改进。改进的代码已经丢了。+_+



    做的不好,在学习中去发现当时自己做的是多么可笑。                                                        

     

    转载于:https://www.cnblogs.com/Guth/p/4956297.html

    展开全文
  • snake_game.zip

    2020-06-22 09:14:12
    基于C++语言的纯控制台游戏,采用简单的布局和结构,界面简单,彩色动感,容易上手学习,比较适合C++学习小白练手。也可以边学习,边实践,不断练习自己的面向对象思想,还可以练习自己对于整体程序的结构思想。
  • 主动轮廓模型:Snake模型的python实现

    千次阅读 热门讨论 2019-08-27 15:28:47
    主要介绍python实现Snake模型的相关函数与代码示例,包括如下部分: 1. 调用skimage实现; 2. python实现

    质量声明:原创文章,内容质量问题请评论吐槽。如对您产生干扰,可私信删除。
    主要参考:Active Contour Model — skimage v0.16.dev0 docs - scikit-image


    skimage实现

    函数声明

    Active contours by fitting snakes to features of images. Supports single and multichannel 2D images. Snakes can be periodic (for segmentation) or have fixed and/or free ends. The output snake has the same length as the input boundary. As the number of points is constant, make sure that the initial snake has enough points to capture the details of the final contour.

    active_contour(image, snake, alpha=0.01, beta=0.1, w_line=0, w_edge=1, gamma=0.01,
            bc='periodic', max_px_move=1.0, max_iterations=2500, convergence=0.1)
    
        Parameters
        ----------
        image : (N, M) or (N, M, 3) ndarray
            Input image.
        snake : (N, 2) ndarray
            Initial snake coordinates. For periodic boundary conditions, endpoints
            must not be duplicated.
        alpha : float, optional
            Snake length shape parameter. Higher values makes snake contract
            faster.
        beta : float, optional
            Snake smoothness shape parameter. Higher values makes snake smoother.
        w_line : float, optional
            Controls attraction to brightness. Use negative values to attract toward
            dark regions.
        w_edge : float, optional
            Controls attraction to edges. Use negative values to repel snake from
            edges.
        gamma : float, optional
            Explicit time stepping parameter.
        bc : {'periodic', 'free', 'fixed'}, optional
            Boundary conditions for worm. 'periodic' attaches the two ends of the
            snake, 'fixed' holds the end-points in place, and 'free' allows free
            movement of the ends. 'fixed' and 'free' can be combined by parsing
            'fixed-free', 'free-fixed'. Parsing 'fixed-fixed' or 'free-free'
            yields same behaviour as 'fixed' and 'free', respectively.
        max_px_move : float, optional
            Maximum pixel distance to move per iteration.
        max_iterations : int, optional
            Maximum iterations to optimize snake shape.
        convergence: float, optional
            Convergence criteria.
    
        Returns
        -------
        snake : (N, 2) ndarray
            Optimised snake, same shape as input parameter.
    
        References
        ----------
        .. [1]  Kass, M.; Witkin, A.; Terzopoulos, D. "Snakes: Active contour
                models". International Journal of Computer Vision 1 (4): 321
                (1988). DOI:`10.1007/BF00133570`
    

    代码示例

    import numpy as np
    from matplotlib import pyplot as plt
    from skimage.color import rgb2gray
    from skimage import data
    from skimage.filters import gaussian
    from skimage.segmentation import active_contour
    
    img = data.astronaut() # 读入图像
    img = rgb2gray(img) # 灰度化
    
    # 圆的参数方程:(220, 100) r=100
    t = np.linspace(0, 2*np.pi, 400) # 参数t, [0,2π]
    x = 220 + 100*np.cos(t)
    y = 100 + 100*np.sin(t)
    
    # 构造初始Snake
    init = np.array([x, y]).T # shape=(400, 2)
    
    # Snake模型迭代输出
    snake = active_contour(gaussian(img,3), snake=init, alpha=0.1, beta=1, gamma=0.01, w_line=0, w_edge=10)
    
    # 绘图显示
    plt.figure(figsize=(5, 5))
    plt.imshow(img, cmap="gray")
    plt.plot(init[:, 0], init[:, 1], '--r', lw=3)
    plt.plot(snake[:, 0], snake[:, 1], '-b', lw=3)
    plt.xticks([]), plt.yticks([]), plt.axis("off")
    plt.show()
    

    结果显示

    astronaut:Active Contour Mode - Snake


    Numpy实现

    代码示例

    import cv2 as cv
    import numpy as np
    from matplotlib import pyplot as plt
    
    
    def getGaussianPE(src):
        """
        描述:计算负高斯势能(Negative Gaussian Potential Energy, NGPE)
        输入:单通道灰度图src
        输出:无符号的浮点型单通道,取值0.0 ~ 255.0
        """
        imblur = cv.GaussianBlur(src, ksize=(5, 5), sigmaX=3)
        dx = cv.Sobel(imblur, cv.CV_16S, 1, 0)  # X方向上取一阶导数,16位有符号数,卷积核3x3
        dy = cv.Sobel(imblur, cv.CV_16S, 0, 1)
        E = dx**2 + dy**2
        return E
    
    
    def getDiagCycleMat(alpha, beta, n):
        """
        计算5对角循环矩阵
        """
        a = 2 * alpha + 6 * beta
        b = -(alpha + 4 * beta)
        c = beta
        diag_mat_a = a * np.eye(n)
        diag_mat_b = b * np.roll(np.eye(n), 1, 0) + b * np.roll(np.eye(n), -1, 0)
        diag_mat_c = c * np.roll(np.eye(n), 2, 0) + c * np.roll(np.eye(n), -2, 0)
        return diag_mat_a + diag_mat_b + diag_mat_c
    
    
    def getCircleContour(centre=(0, 0), radius=(1, 1), N=200):
        """
        以参数方程的形式,获取n个离散点围成的圆形/椭圆形轮廓
        输入:中心centre=(x0, y0), 半轴长radius=(a, b), 离散点数N
        输出:由离散点坐标(x, y)组成的2xN矩阵
        """
        t = np.linspace(0, 2 * np.pi, N)
        x = centre[0] + radius[0] * np.cos(t)
        y = centre[1] + radius[1] * np.sin(t)
        return np.array([x, y])
    
    
    def getRectContour(pt1=(0, 0), pt2=(50, 50)):
        """
        根据左上、右下两个顶点来计算矩形初始轮廓坐标
        由于Snake模型适用于光滑曲线,故这里用不到该函数
        """
        pt1, pt2 = np.array(pt1), np.array(pt2)
        r1, c1, r2, c2 = pt1[0], pt1[1], pt2[0], pt2[1]
        a, b = r2 - r1, c2 - c1
        length = (a + b) * 2 + 1
        x = np.ones((length), np.float)
        x[:b] = r1
        x[b:a + b] = np.arange(r1, r2)
        x[a + b:a + b + b] = r2
        x[a + b + b:] = np.arange(r2, r1 - 1, -1)
        y = np.ones((length), np.float)
        y[:b] = np.arange(c1, c2)
        y[b:a + b] = c2
        y[a + b:a + b + b] = np.arange(c2, c1, -1)
        y[a + b + b:] = c1
        return np.array([x, y])
    
    
    def snake(img, snake, alpha=0.5, beta=0.1, gamma=0.1, max_iter=2500, convergence=0.01):
        """
        根据Snake模型的隐式格式进行迭代
        输入:弹力系数alpha,刚性系数beta,迭代步长gamma,最大迭代次数max_iter,收敛阈值convergence
        输出:由收敛轮廓坐标(x, y)组成的2xN矩阵, 历次迭代误差list
        """
        x, y, errs = snake[0].copy(), snake[1].copy(), []
        n = len(x)
        # 计算5对角循环矩阵A,及其相关逆阵
        A = getDiagCycleMat(alpha, beta, n)
        inv = np.linalg.inv(A + gamma * np.eye(n))
        # 初始化
        y_max, x_max = img.shape
        max_px_move = 1.0
        # 计算负高斯势能矩阵,及其梯度
        E_ext = -getGaussianPE(img)
        fx = cv.Sobel(E_ext, cv.CV_16S, 1, 0)
        fy = cv.Sobel(E_ext, cv.CV_16S, 0, 1)
        T = np.max([abs(fx), abs(fy)])
        fx, fy = fx / T, fy / T
        for g in range(max_iter):
            x_pre, y_pre = x.copy(), y.copy()
            i, j = np.uint8(y), np.uint8(x)
            try:
                xn = inv @ (gamma * x + fx[i, j])
                yn = inv @ (gamma * y + fy[i, j])
            except Exception as e:
                print("索引超出范围")
            # 判断收敛
            x, y = xn, yn
            err = np.mean(0.5 * np.abs(x_pre - x) + 0.5 * np.abs(y_pre - y))
            errs.append(err)
            if err < convergence:
                print(f"Snake迭代{g}次后,趋于收敛。\t err = {err:.3f}")
                break
        return x, y, errs
    
    
    def main():
        src = cv.imread("circle.jpg", 0)
        img = cv.GaussianBlur(src, (3, 3), 5)
    
        # 构造初始轮廓线
        init = getCircleContour((140, 95), (110, 80), N=200)
        # Snake Model
        x, y, errs = snake(img, snake=init, alpha=0.1, beta=1, gamma=0.1)
    
        plt.figure() # 绘制轮廓图
        plt.imshow(img, cmap="gray")
        plt.plot(init[0], init[1], '--r', lw=1)
        plt.plot(x, y, 'g', lw=1)
        plt.xticks([]), plt.yticks([]), plt.axis("off")
        plt.figure() # 绘制收敛趋势图
        plt.plot(range(len(errs)), errs)
        plt.show()
    
    
    if __name__ == '__main__':
        main()
    

    结果显示

    Snake迭代760次后,趋于收敛。	 err = 0.010
    
    在这里插入图片描述 在这里插入图片描述

    展开全文
  • 图像分割之(五)活动轮廓模型之Snake模型简介

    万次阅读 多人点赞 2013-03-24 11:56:40
    图像分割之(五)活动轮廓模型之Snake模型简介 zouxy09@qq.com http://blog.csdn.net/zouxy09    在“图像分割之(一)概述”中咱们简单了解了目前主流的图像分割方法。下面咱们主要学习下基于能量泛函的分割...
  • 主动轮廓模型(也称Active Contour Model、Snake)是Kass等人在1988年提出的,该算法将图像分割问题转换为求解能量泛函最小值的问题。主要思路是通过构造能量泛函,经过算法迭代,轮廓曲线由初始位置逐渐向使能量...
  • 贪吃蛇游戏(C语言)(在Dev c++、vc中运行通过)

    万次阅读 多人点赞 2016-12-27 13:31:18
    贪吃蛇游戏(C语言)在大一计算机实训时写的,其中较难理解的应该是句柄,需要自己网上查找资料 以下是代码片段:#include #include #include #include #define framex 5 #define framey 5 #define wide 20 ...
  • 我的程序 import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;...import java.util.ArrayList;...
  • 纯C语言实现经典小游戏——贪吃蛇(VS2017)

    万次阅读 多人点赞 2018-02-21 13:42:33
    假期无聊第二季,用C语言实现简单经典小游戏——贪吃蛇。特别适合新手熟悉C语言。(完整程序在文章最后!!!) 主要涉及C语言知识点如下: 结构体,函数的定义及调用,指针变量,指针和数组,逻辑表达式,基本的...
  • QT写的贪吃蛇(C++)

    万次阅读 多人点赞 2019-09-29 15:21:28
    这个qt写的贪吃蛇是我在通过学校老师所录的视频简单学习之后,再根据网络上的视频做出的一个贪吃蛇小游戏。该游戏所实现的功能如下: ①资源文件的使用 ②父子窗口的协调出现,父窗口的背景覆盖 ...
  • C语言+easyX界面库实现贪吃蛇

    万次阅读 2017-05-07 12:45:17
    问题描述: 实现贪吃蛇游戏,有等级,分数,并且会保存最高等级和最高分easysnake.h代码:#pragma once#include #include #include #include #include #include #include "resource.
  • 贪吃蛇智能版(中级)

    万次阅读 2017-05-07 12:44:46
    说明: 相对于上一个版本,这次主要完善了一下智能模式,虽然蛇有了一定的智能,但是仍然有一定的局限性,局限性体现在看得不够远,所以目前智能称为中级,附上代码:easysnake.h#pragma once#include ...
  • <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>JavaScript实现贪吃蛇游戏_/艾孜尔江撰/</title> <style> article, aside, d...
  • 贪吃蛇智能版(专家)

    万次阅读 2017-05-07 12:43:26
    在高级版本的基础之上,主要针对以下问题进行了处理: 当长度逐渐变成,超过100之后,随机wander+追尾有比较大的随机性,弄不好就把自己围死了,这个时候已经不能再看到实物马上就去吃了,在吃之前必须先调整好自身...
  • 这个版本也是这个贪吃蛇系列的最后一个版本了(虽然蛇长度变得很长之后,食物在某些区域,蛇的行走路线还有优化的空间,但是近期应该不会再进行更新了),下面对之前所有的迭代版本做一个总结:版本一、只有闯关模式...
  • 贪吃蛇智能版(高级)

    万次阅读 2017-05-07 12:43:58
    说明: 在贪吃蛇智能版(中级)的基础之上,增加了判断小食物是否安全的方法,并且增加了在寻找食物路径失败和寻找尾巴失败之后,会进行一小段的随机溜达,直到重新找到路径为止,当然这段溜达会有一定风险,这个在...
  • 贪吃蛇C语言实现(简易版)

    万次阅读 多人点赞 2017-01-28 11:47:13
    一 引言 刚学习完C语言,寒假就迫不及待的学习这个贪吃蛇小程序。不得不说,写完还是大有收获的。 二 基本原理 ...对于贪吃蛇怎么在屏幕上移动,当初自己也是懵逼,哈哈。其实就是不断刷新屏幕,在一个循环里,每...
  • C#winform 经典小游戏贪吃蛇V1.0(一)

    万次阅读 多人点赞 2018-12-27 09:38:04
    关于V1.0   为什么我给这个版本定义为V1.0嘞,因为在这个版本中仅仅实现了蛇的自动行进,按键对蛇的行进方向的操作和吃掉食物蛇身的增长等操作。 但是任何事情都必须一步一步来,当我们完成这个乞丐版的...
  • C语言-手把手教你写贪吃蛇AI(上)

    千次阅读 2017-04-03 16:45:44
    源代码: 总共由三个文件组成gluttonous.h,source.c &...#ifndef SNAKE_H_ #define SNAKE_H_ #include #include //SetConsoleCursorPosition, sleep函数的头函数 #include //time()的头函数 #include //malloc()的头函
1 2 3 4 5 ... 20
收藏数 21,755
精华内容 8,702
关键字:

snake