snake算法(snake模型算法)
snake算法(snake模型算法)
急!!snake算法怎么使用(MATLAB)
主要公式为曲线能量Esnake(公式1);Esnake由内部能量Eint(公式2)及外部能量Eext(公式3)组成;而根据公式2内部能量Eint是由一阶导得到的平滑性约束(弹性绳子)二阶导得到的气球约束(刚性棍子)共同决定;根据公式3外部能Eext由梯度场决定(另一个分量不考虑)那么粗略表示为Esnake=Vs+Vss+Eext;可以认为当Esnake的能量达到最小时snake曲线和物体的边缘一致。
上面这些基本是每个论文上面都有的,下面照我的理解来讲。结合很多论文上用的那个U形物体,snake检测它的轮廓时,预先以一个圆形的像素圈套住它作为初始的snake线,可以取一定个数的点来离散化snake线,那么这时就可以求这条snake线与原始图像间的曲线能量Esnake了;Vs对应的是一阶的平滑性,可转化为snake线中相邻像素之间的坐标;值越大能量越大平滑性也就越;Vss对应的是二阶的刚性;可转化为snake线中某点和它相邻的线上点间的法线方向的增长度量;Eext是梯度场能量,是由原本的灰度图决定的,可转化为snake中某点在灰度图中的邻域梯度。求出了这三个;再以一定的方式进行循环逼近那个使Esnake最小的snake线就找到了轮廓。
贪吃蛇原理啥?
#define N 200
#include
#include
#include
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP 0x4800
#define ESC 0x011b
int i,key;
int score=0;/得分/
int speed=50000;/游戏速度自己调整/
struct Food
{
int x;/食物的横坐标/
int y;/食物的纵坐标/
int yes;/判断是否要出现食物的变量/
}food;/食物的结构体/
struct Snake
{
int x[N];
int y[N];
int node;/蛇的节数/
int direction;/蛇移动方向/
int life;/ 蛇的生命,0活着,1亡/
}snake;
void Init(void);/图形驱动/
void Close(void);/图形结束/
void DrawK(void);/开始画面/
void GameOver(void);/结束游戏/
void GamePlay(void);/玩游戏具体过程/
void PrScore(void);/输出成绩/
/主函数/
void main(void)
{
Init();/图形驱动/
DrawK();/开始画面/
GamePlay();/玩游戏具体过程/
Close();/图形结束/
}
/图形驱动/
void Init(void)
{
int gd=DETECT,gm;
registerbgidriver(EGAVGA_driver);
initgraph(&gd,&gm,"c:\\program files\\winyes\\tc20h\\bgi");
cleardev();
}
/开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙/
void DrawK(void)
{
/setbkcolor(LIGHTGREEN);/
setcolor(11);
setlinestyle(SOLID_LINE,0,THICK_WIDTH);/设置线型/
for(i=50;i<=600;i+=10)/画围墙/
{
rectangle(i,40,i+10,49); /上边/
rectangle(i,451,i+10,460);/下边/
}
for(i=40;i<=450;i+=10)
{
rectangle(50,i,59,i+10); /左边/
rectangle(601,i,610,i+10);/右边/
}
}
/玩游戏具体过程/
void GamePlay(void)
{
randomize();/随机数发生器/
food.yes=1;/1表示需要出现新食物,0表示已经存在食物/
snake.life=0;/活着/
snake.direction=1;/方向往右/
snake.x[0]=100;snake.y[0]=100;/蛇头/
snake.x[1]=110;snake.y[1]=100;
snake.node=2;/节数/
PrScore();/输出得分/
while(1)/可以重复玩游戏,压ESC键结束/
{
while(!kbhit())/在没有按键的情况下,蛇自己移动身体/
{
if(food.yes==1)/需要出现新食物/
{
food.x=rand()%400+60;
food.y=rand()%350+60;
while(food.x%10!=0)/食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到/
food.x++;
while(food.y%10!=0)
food.y++;
food.yes=0;/画面上有食物了/
}
if(food.yes==0)/画面上有食物了就要显示/
{
setcolor(GREEN);
rectangle(food.x,food.y,food.x+10,food.y-10);
}
for(i=snake.node-1;i>0;i--)/蛇的每个环节往前移动,也就是贪吃蛇的关键算法/
{
snake.x[i]=snake.x[i-1];
snake.y[i]=snake.y[i-1];
}
/1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头/
switch(snake.direction)
{
case 1:snake.x[0]+=10;break;
case 2: snake.x[0]-=10;break;
case 3: snake.y[0]-=10;break;
case 4: snake.y[0]+=10;break;
}
for(i=3;i { if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0]) { GameOver();/显示失败/ snake.life=1; break; } } if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55|| snake.y[0]>455)/蛇是否撞到墙壁/ { GameOver();/本次游戏结束/ snake.life=1; /蛇/ } if(snake.life==1)/以上两种判断以后,如果蛇就跳出内循环,重新开始/ break; if(snake.x[0]==food.x&&snake.y[0]==food.y)/吃到食物以后/ { setcolor(0);/把画面上的食物东西去掉/ rectangle(food.x,food.y,food.x+10,food.y-10); snake.x[snake.node]=-20;snake.y[snake.node]=-20; /新的一节先放在看不见的位置,下次循环就取前一节的位置/ snake.node++;/蛇的身体长一节/ food.yes=1;/画面上需要出现新的食物/ score+=10; PrScore();/输出新得分/ } setcolor(4);/画出蛇/ for(i=0;i rectangle(snake.x[i],snake.y[i],snake.x[i]+10, snake.y[i]-10); delay(speed); setcolor(0);/用黑色去除蛇的的一节/ rectangle(snake.x[snake.node-1],snake.y[snake.node-1], snake.x[snake.node-1]+10,snake.y[snake.node-1]-10); } /endwhile(!kbhit)/ if(snake.life==1)/如果蛇就跳出循环/ break; key=bioskey(0);/接收按键/ if(key==ESC)/按ESC键退出/ break; else if(key==UP&&snake.direction!=4) /判断是否往相反的方向移动/ snake.direction=3; else if(key==RIGHT&&snake.direction!=2) snake.direction=1; else if(key==LEFT&&snake.direction!=1) snake.direction=2; else if(key==DOWN&&snake.direction!=3) snake.direction=4; }/endwhile(1)/ } /游戏结束/ void GameOver(void) { cleardev(); PrScore(); setcolor(RED); settextstyle(0,0,4); outtextxy(200,200,"GAME OVER"); getch(); } /输出成绩/ void PrScore(void) { char str[10]; setfillstyle(SOLID_FILL,YELLOW); bar(50,15,220,35); setcolor(6); settextstyle(0,0,2); sprintf(str,"score:%d",score); outtextxy(55,20,str); } /图形结束/ void Close(void) { getch(); closegraph(); } N = length(x); alpha = alpha ones(1,N); beta = betaones(1,N); % produce the five diagnal vectors alpham1 = [alpha(2:N) alpha(1)]; alphap1 = [alpha(N) alpha(1:N-1)]; betam1 = [beta(2:N) beta(1)]; betap1 = [beta(N) beta(1:N-1)]; a = betam1; b = -alpha - 2beta - 2betam1; c = alpha + alphap1 +betam1 + 4beta + betap1; d = -alphap1 - 2beta - 2betap1; e = betap1; % generate the parameters matrix A = diag(a(1:N-2),-2) + diag(a(N-1:N),N-2); A = A + diag(b(1:N-1),-1) + diag(b(N), N-1); A = A + diag(c); A = A + diag(d(1:N-1),1) + diag(d(N),-(N-1)); A = A + diag(e(1:N-2),2) + diag(e(N-1:N),-(N-2)); invAI = inv(A + gamma diag(ones(1,N))); for count = 1:ITER, vfx = interp2(fx,x,y,'linear'); vfy = interp2(fy,x,y,'linear'); % deform snake x = invAI (gamma x + kappavfx); y = invAI (gamma y + kappavfy); end 循环+Sleep可以完成这个功能的 比如说我现在定义了一个小方块,让他自动移动 int i,j; int a[25][80]={0}; //用数组来覆盖整个运行界面 int x=10,y=0; //定义一个x,y表示方块当前的位置 while(1) { //清楚之前的输出信息 ("cls");//这是调用的命令行,作用是清屏 a[x][y]=1; //数组元素为1就表示在界面上的这个位置显示方块 //在屏幕上相应位置输出方块 for( i = 0; i<25 ; i++) for( j=0; j<80 ;j++) if(a[i][j]==0) printf(" "); //等于0就表示该位置不是方块,输出一个空格 else printf("%c",2); //否则就输出这个方块 //然后重置这个数组,这个可以和上一个循环合并在一起 for( i = 0; i<25 ; i++) for( j=0; j<80 ;j++) a[i][j]=0; // 更改方块所在的位置 //向上 x=x-1; //向下 x=x+1; //向左 y=y-1; //向右 y=y-1; //上面的四句保留一句就可以了 //然后休息休息 Sleep(300); } 基本算法就如代码所示 具体的肯定和你向做的效果不一样 比如说你要控制蛇的方向 那改变位置的时候就需要判断 而且,改变一条蛇和改变一个方块也不一样 不过总体思路是这样子的 仅作参考 注意一点,Sleep函数是window头文件里面的 需要导入window头文件 如果不是Windows系统,请替换为相应的函数 当前做instance segmentation的大多数工作采用了Mask R- 的Pipeline。 它基本的pipeline是先检测物体矩形框,然后在矩形框中做逐像素分割。 Mask R-达到了很好的instance segmentation的结果,但是这样的pipeline其实有一些limitation: 考虑到逐像素分割有诸多限制,文章的工作选择用contour来表示物体的shape。Contour是一组有序的点,而且是首尾相连的。比如中猫的边缘就是一个Contour。 Contour相对于用稠密像素表示物体有两大优势: 实例分割是许多计算机视觉任务中的重要手段,目前大多数的算法都采用在给定的bbox中进行pixel-wise分割的方法。受snake算法和Curve-GCN的启发,论文采用基于轮廓的逐步调整策略,提出了Deep snake算法进行实时实例分割,该算法将初始轮廓逐渐优化为目标的边界,如图所示,达到很好的性能且依然保持很高的实时性(32.3fps)。 Deep snake方法将初始轮廓逐渐优化为目标的边界来进行目标分割,即将物体轮廓作为输入,基于主干特征预测每个顶点的偏移量。为了充分利用轮廓拓扑结构,论文使用循环卷积(circular convolution)进行顶点特征的学习,有助于学习轮廓的优化,并基于deep snake提出了一套实时实例分割的流程。 传统的snake算法将顶点的坐标作为变量来优化人工设计的能量函数(energy function),通过最小化能量函数来拟合目标边界。由于能量函数通常是非凸的,而且需要基于低维图像特征进行人工设计,通常会陷于局部解。 而deep snake则是直接从数据学习如何微调轮廓,对于个顶点,首先构造每个顶点的特征向量,顶点的特征为对应的网络特征和顶点坐标的concate,其中为主干网络输出的特征图,为顶点处的双线性值输出,附加的用于描述顶点间的位置关系,是平移不变的,由每个顶点坐标减去轮廓中所有顶点的最小和得到相对坐标。 在获得顶点特征后,需要对轮廓特征进一步学习,顶点的特征可以视作1-D离散信号,然后使用标准卷积对顶点逐个进行处理,但这样会破坏轮廓的拓扑结构。因此,将顶点特征定义为公式1的周期信号,然后使用公式2的循环卷积进行特征学习,为可学习的卷积核,为标准卷积作。 将deep snake加入到目标检测模型中进行实例分割,流程如图b所示。模型首先产生目标框,将其构建成菱形框,然后使用deep snake算法将菱形顶点调整为目标极点,构造八边形轮廓,进行迭代式deep snake轮廓调整得到目标形状 论文采用ExtreNet的极点思想,能够很好地包围物体。在得到矩形框后,获取4条边的中心点连成菱形轮廓,使用deep snake对菱形轮廓调整成极点,然后每个极点放置一条边,连接边构造多边形,每个极点的边为其对应的bbox边的,若边超过原bbox范围会被截断。在实际使用时,菱形轮廓输入deep snake前会平均上采样到40个点(有助于deep snake计算),但损失函数计算只考虑的对应偏移 对八边形平均采样个点,将上极点作为起点,同样地,GT轮廓对物体边缘平均采样个点,将靠近的点作为起点,一般为128。如果顶点离GT很远,很难直接正确调整,于是采用迭代式地进行deep snake调整,实验采用的迭代次数为3次。 轮廓是目标空间位置的一种扩展表示方法,通过调整轮廓到物体边缘能够帮助解决detector的定位误 由于遮挡,一个实例可能包含多个组件,然而一个轮廓只能勾勒出bbox内的一个组件。为了解决这个问题,使用RoIAlign来提取初始bbox特征,然后配合detector来检测组件的box,再对每个box进行上述的轮廓调整,结合初始bbox内相同类别的组件输出最终的物体形状。 极点的损失函数如公式3,为预测的极点。 迭代轮廓调整的损失函数如公式4,为调整后的顶点,为对应的GT边缘点。对于检测部分,则采用跟原检测函数一样的损失函数。 使用CenterNet作为检测器,对于物体检测,使用跟原来一样的设定输出类别相关的box,而对于组件检测,则使用类不可知的CenterNet,对于的特征图,输出的中心点heatmap和的box大小特征图。 Baseline将轮廓视为图结构,然后使用GCN进行轮廓调整,初始轮廓为围绕bbox的椭圆,Arichitecture加入Fusion block,Initial proal加入论文的轮廓初始化方法,是将GCN修改为循环卷积,可以看到每个步骤都对AP有提升。 论文也对比了卷积类型以及迭代次数对结构的影响,可以看到循环卷积的结果比GCN要好。 论文在不同的数据集上都取得了不错的效果,作者在每个数据集上的训练参数都有点不一样,具体参数可以看看原文 论文提出基于轮廓的实例分割方法Deep snake,轮廓调整是个很不错的方向,引入循环卷积,不仅提升了性能还减少了计算量,保持了实时性,但是Deep snake的大体结构不够优雅,应该还有一些工作可以补 [1] 彭思达 - 实例分割新思路: Deep Snake (CVPR20'Oral Paper) [2] Deep Snake: 基于轮廓调整的SOTA实例分割方法,速度32.3fps| CVPR 2020 [3] He, Kaiming, et al. "Mask r-cnn." In ICCV, 2017. [4] Kass, Michael, Andrew Witkin, and Demetri Terzopoulos. "Snakes: Active contour models." In IJCV, 1988. [5] Ling, Huan, et al. "Fast interactive object annotation with curve-gcn." In CVPR, 2019. [6] Zhou, Xingyi, Jiacheng Zhuo, and Philipp Krahenbuhl. "Bottom-up object detection by grouping extreme and center points." In CVPR, 2019. [7] Zhou, Xingyi, Dequan Wang, and Philipp Krahenbuhl. "Objects as points." In arXiv preprint arXiv:1904.07850, 2019. #include #include #include #define LEFT 0x4b00 #define RIGHT 0x4d00 #define DOWN 0x5000 #define UP 0x4800 #define ESC 0x011b int i,key; int score=0; int speed=32000; struct Food /食物的结构体/ { int x; /食物的横坐标/ int y; /食物的纵坐标/ int yes; /食物是否出现的变量/ }food; struct Snack /蛇的结构体/ { int x[N]; int y[N]; int node; /蛇的节数/ int direction; /蛇的方向/ int life; /蛇的生命,0活着,1亡/ }snake; void Init(void); /图形驱动/ void Close(void); /关闭游戏函数/ void DrawK(void); /画图函数/ void GameOver(void);/输出失败函数/ void GamePlay(); /游戏控制函数 主要程序/ void PrScore(void); /分数输出函数/ DELAY(char ch)/调节游戏速度/ { if(ch=='3') { delay(speed); /delay是延迟函数/ delay(speed); } else if(ch=='2') { delay(speed); } } Menu()/游戏开始菜单/ { char ch; printf("Please choose the speed:\n"); printf("1-Fast 2-Normal 3-Slow\n"); printf("\nPlease Press The numbers..\n"); do {ch=getch();} while(ch!='1'&&ch!='2'&&ch!='3'); clrscr(); return(ch); } /主函数/ void main(void) { int ch; ch=Menu(); Init(); DrawK(); GamePlay(ch); Close(); } void Init(void) { int gd=DETECT,gm; initgraph(&gd,&gm,"c:\\tc"); cleardev(); } void DrawK(void) { setcolor(11); setlinestyle(SOLID_LINE,0,THICK_WIDTH); for(i=50;i<=600;i+=10) { rectangle(i,40,i+10,49); /画出上边框/ rectangle(i,451,i+10,460); /画出下边框/ } for(i=40;i<=450;i+=10) { rectangle(50,i,59,i+10); /画出左边框/ rectangle(601,i,610,i+10); /画出右边框/ } } void GamePlay(char ch) { randomize(); /随机数发生器/ food.yes=1; /1代表要出现食物,0表示以存在食物/ snake.life=0; snake.direction=1; snake.x[0]=100;snake.y[0]=100; snake.x[1]=110;snake.y[1]=100; snake.node=2; PrScore(); while(1) /可以重复游戏/ { while(!kbhit()) /在没有按键的情况下蛇自己移动/ { if(food.yes==1) /需要食物/ { food.x=rand()%400+60; food.y=rand()%350+60; /使用rand函数随机产生食物坐标/ while(food.x%10!=0) food.x++; while(food.y%10!=0) food.y++; /判断食物是否出现在整格里/ food.yes=0; /现在有食物了/ } if(food.yes==0) /有食物了就要显示出来/ { setcolor(GREEN); rectangle(food.x,food.y,food.x+10,food.y-10); } for(i=snake.node-1;i>0;i--) /贪吃蛇的移动算法/ { snake.x[i]=snake.x[i-1]; snake.y[i]=snake.y[i-1]; /贪吃蛇的身体移动算法/ } switch(snake.direction) /贪吃蛇的头部移动算法,以此来控制移动/ { case 1:snake.x[0]+=10;break; case 2:snake.x[0]-=10;break; case 3:snake.y[0]-=10;break; case 4:snake.y[0]+=10;break; } for(i=3;i { if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0]) { GameOver(); snake.life=1; break; } } /下面是判断是否撞到墙壁/ if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||snake.y[0]>455) { GameOver(); snake.life=1; } if(snake.life==1) /如果亡就退出循环/ break; if(snake.x[0]==food.x&&snake.y[0]==food.y) /判断蛇是否吃到食物/ { setcolor(0); rectangle(food.x,food.y,food.x+10,food.y-10); /吃的食物后用黑色将食物擦去/ snake.x[snake.node]=-20;snake.y[snake.node]=-20; /现把增加的一节放到看不到的地方去/ snake.node++; food.yes=1; score+=10; PrScore(); } setcolor(4); /每次移动后将后面的身体擦去/ for(i=0;i rectangle(snake.x[i],snake.y[i],snake.x[i]+10,snake.y[i]-10); delay(speed); DELAY(ch); setcolor(0); rectangle(snake.x[snake.node-1],snake.y[snake.node-1],snake.x[snake.node-1]+10,snake.y[snake.node-1]-10); } if(snake.life==1) break; key=bioskey(0); /接受按键/ if(key==ESC) break; else if(key==UP&&snake.direction!=4)/判断是否改变方向/ snake.direction=3; else if(key==RIGHT&&snake.direction!=2) snake.direction=1; else if(key==LEFT&&snake.direction!=1) snake.direction=2; else if(key==DOWN&&snake.direction!=3) snake.direction=4; } } void GameOver(void) { cleardev(); setcolor(RED); settextstyle(0,0,4); outtextxy(200,200,"GAME OVER"); getch(); } void PrScore(void) { char str[10]; setfillstyle(SOLID_FILL,YELLOW); bar(50,15,220,35); setcolor(6); settextstyle(0,0,2); sprintf(str,"scord:%d",score); outtextxy(55,20,str); } void Close(void) { getch(); closegraph(); } 版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至836084111@qq.com 举报,一经查实,本站将立刻删除。如何实现snake算法的matlab编程,来提取图像中划痕缺陷的边缘,谁有程序不妨发上来
c语言贪吃蛇怎么让蛇自己动起来啊?
【Paper Reading】Deep Snake for Real-Time Instance Segmentation CVPR2020`Oral Paper
求贪吃蛇的C++程序代码