Blogger Template by Blogcrowds.

CodeTank Games

CodeTank 是一款基于html5的编程小游戏,由于曾经做过一段时间的机器人足球,类似的小游戏对我来说并不陌生,其主要功能就是为用户提供一系列游戏运行的基本操作,对于这一款游戏来说比如设置tank的运行,tank的雷达的运行和tank火炮的运行,同时还有一系列基础的动作和函数,用户通过这一系列的基础动作和函数设计战术动作从而达到消灭敌人保全自己的目的。
这类游戏的鼻祖为一个叫Robcode的游戏,当然在腾讯刚开始推出这一款编程小游戏时也有不少质疑,很多人觉得这一款游戏是抄袭Robocode,当然也有许多人为腾讯辩护,关于抄袭的这个问题我在这篇文章中并不打算过多的进行讨论,如果大家有兴趣可以参看这篇文章,先不讨论其优劣,我们还是先来看看这一款游戏的界面,通过QQ号可以直接登录(我大企鹅就是牛逼~),登录以后我们遍可以添加自己的tank了,可是我们还没有任何tank呀,所以在这个时候我们需要创建我们的第一个tank,关于新手创建tank的过程在帮助文档中有详细描述,在这篇文章中也会简单的给大家做一个简短的介绍,由于javascript我自己也不是很熟,只是一边自己学习思考一篇记录一下自己的心得体会。
,首先工欲善其事必先利其器,所以我们对codetank提供的代码结构必须要有所了解,并且,最好是能够熟悉其官方示例代码,基于这个原则我们先来了解其基本框架:

Jx().$package(function(J){
 Robot = new J.Class({extend : tank.Robot},{

  /**
  *robot主循环
  **/ 
  run:function(){
   
  },

  /**
  *看到其他robot的处理程序
  **/
  onScannedRobot:function(e){
   
  },

  /**
  *被子弹击中的处理程序
  **/
  onHitByBullet:function(e){
   
  },

  /**
  *和墙碰撞的处理程序
  **/
  onHitWall:function(e){
   
  },

  onRobotDeath:function(e){
   
  }
 });
});
查看其官方示例发现其代码结构比较简单明确,首先我们可以看到,主要的函数接口有5个,分别为主函数接口,扫描到敌人的函数接口,被子弹击中的函数接口,和墙碰撞以及与其他机器人碰撞的接口,这些接口看起来都比较简单,然后我们可以查看几何官方示例代码,主要包括了开炮,运行、旋转等操作,都十分具有代表性,在实际中我们可以参考其示例代码设计自己的战术,通过这几天的学习我设计了一套简单的战术,也许并不是太有效但是毕竟是自己设计的第一个战术,还是很开心的我的战术基本描述为:
1.根据tank位置找到离当前位置最近的角落点
2.让tank运行到最近的角落点,在这个过程中如果发现敌人直接开炮。在运行到角落点的过程中运行顺序为让tank保持方便逆时针运行的方向,这个主要是方便下面步骤进行批处理。
3.运行到角落后扫描整个战场,此时只用扫描90°方向,大大提高了扫描效率
4.在扫描过程中发现敌方的坦克则应该立即开炮,当然以最大火力开炮(暂时不考虑炮身发热)
5.若在角落被击中则以逆时针方向躲避到下一角落,在躲避过程中首先旋转炮管使其与tank运行方法一致,运行到下一个角落进行扫描。
6.若在运行过程中碰撞到其他tank则直接调转炮身刚正面(这个战术有待商榷)
7若与墙壁发生碰撞,则进行调整运行到最近角落
以上为整个战术过程,实际代码如下:
Jx().$package(function(J){
    var corner=false;
    var flag=1;
    var stopWhenSeeRobot;
    var smartTurn=function(angle){
        if(angle>180){
            angle=angle-360;
        }
        else if(angle<-180){
            angle=angle+360;
        }
        return angle;        
    };
    var getGunAngleToTurn=function(angleGunToTurn){
        return (angleGunToTurn+this.getHeading()-this.getGunHeading())%360;
    };    
    var smartFire=function(robot,robotDistance) {
        if (robotDistance > 200 || robot.getEnergy() < 15) {

            robot.fire(1);
  } else if (robotDistance > 50) {
   robot.fire(2);
  } else {
   robot.fire(3);
  }
 }
    var widthorheight=false;
    Robot = new J.Class({extend : tank.Robot},{
     /**
  *robot主函数
  **/ 
  run:function(){
           this.setUI(tank.ui["While"]);
            this.say("square ghost!","#887cff");

        var currentPos=this.getPos();
         var size=this.getBattleFieldSize();
            var sizeTank=this.getSize();
   var heading=this.getHeading();
            var dis1=Math.abs(currentPos[0])+Math.abs(currentPos[1]);
            var dis2=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]);
            var dis3=Math.abs(currentPos[0])+Math.abs(currentPos[1]-size[1]);
            var dis4=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]-size[1]);
            var mindis=Math.min(Math.min(dis1,dis2),Math.min(dis3,dis4));
           if(mindis===(dis1)){
               
                this.say("1");
                this.turnLeft(smartTurn(90-heading),null);
       widthorheight=false;
       this.ahead(currentPos[1]-sizeTank[1]);
       this.turnLeft(90);
       this.ahead(currentPos[0]-sizeTank[0]);
           } 
          else if(mindis===(dis2)){
              
               this.say("2");
                this.turnLeft(smartTurn(360-heading));
       this.ahead(size[0]-sizeTank[0]-currentPos[0]);
                this.turnLeft(90);
       this.ahead(currentPos[1]-sizeTank[1]);
       widthorheight=true;
      
            }
            else if(mindis===dis3){
                
                this.say("3");
                this.turnLeft(smartTurn(180-heading));
       this.ahead(currentPos[0]-sizeTank[0]);
                 this.turnLeft(90);
       this.ahead(size[1]-currentPos[1]-sizeTank[1]);  
                widthorheight=true;
                
            }
            else{
                
                this.say("4");
                this.turnLeft(smartTurn(270-heading));
                this.ahead(size[1]-currentPos[1]-sizeTank[1]);       
                 this.turnLeft(90);
       this.ahead(size[0]-currentPos[0]-sizeTank[0]);
                widthorheight=false;
                
            }
            corner=true;
            this.loop(function(){
                var tankangle=this.getHeading();
                var angleToTurn1=smartTurn(tankangle-this.getGunHeading()+90);
                this.turnGunLeft(angleToTurn1); 
                this.turnGunLeft(90);
    this.turnGunRight(90);
            });
  },
        
     /**
  *看到其他robot的处理程序
  **/ 
  onScannedRobot:function(e){
            this.say("别跑啊亲!~","#887cff");
            var size=this.getBattleFieldSize();
            var sizeTank=this.getSize();
            if (stopWhenSeeRobot){
                var dis=e.getDistance();
                 if(dis<50)
                 {
                    this.fire(3);
                    this.turnLeft(90);
                 if(widthorheight){
                     var dis=size[0]-2*sizeTank[0];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }
                 if(!widthorheight){
                     var dis=size[1]-2*sizeTank[1];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }    
                 widthorheight=!widthorheight;
                 }
    this.stopMove();
             var angleToRobot=e.getBearing();
             var angleGunToTurn=getGunAngleToTurn.call(this,angleToRobot);
             this.turnGunLeft(smartTurn(angleGunToTurn));
   // smartFire(this,e.getDistance());
       this.fire(3);
                this.scan();
   }
   else{
   // smartFire(this,e.getDistance());
             this.fire(3);
   }
            
  },
        /**
  *被子弹击中的处理程序
  **/
  onHitByBullet:function(e){
            var tankangle=this.getHeading();
            var angleToTurn1=smartTurn(tankangle-this.getGunHeading());
            this.say(angleToTurn1.toString());
            this.turnGunLeft(smartTurn(angleToTurn1));
            var currentPos=this.getPos();
            var size=this.getBattleFieldSize();
            var sizeTank=this.getSize(); 
             this.say(corner.toString());
            if(corner){     
                this.turnLeft(90);
                 if(widthorheight){
                     var dis=size[0]-2*sizeTank[0];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }
                 if(!widthorheight){
                     var dis=size[1]-2*sizeTank[1];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }    
                 widthorheight=!widthorheight;
           }
           
        },
        /**
  *和墙碰撞的处理程序
  **/ 
  onHitWall:function(e){  
          var currentPos=this.getPos();
      var size=this.getBattleFieldSize();
            var sizeTank=this.getSize();
   var heading=this.getHeading();
            var dis1=Math.abs(currentPos[0])+Math.abs(currentPos[1]);
            var dis2=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]);
            var dis3=Math.abs(currentPos[0])+Math.abs(currentPos[1]-size[1]);
            var dis4=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]-size[1]);
             var mindis=Math.min(Math.min(dis1,dis2),Math.min(dis3,dis4));
          if(mindis===(dis1)){
                this.say("1");
                this.turnLeft(smartTurn(90-heading));
       widthorheight=false;
       this.ahead(currentPos[1]-sizeTank[1]);
       this.turnLeft(90);
       this.ahead(currentPos[0]-sizeTank[0]);
           } 
          else if(mindis===(dis2)){
               this.say("2");
                this.turnLeft(smartTurn(360-heading));
       this.ahead(size[0]-sizeTank[0]-currentPos[0]);
                this.turnLeft(90);
       this.ahead(currentPos[1]-sizeTank[1]);
       widthorheight=true;
       
            }
            else if(mindis===dis3){
                this.say("3");
                this.turnLeft(smartTurn(180-heading));
       this.ahead(currentPos[0]-sizeTank[0]);
                 this.turnLeft(90);
       this.ahead(size[1]-currentPos[1]-sizeTank[1]);  
                widthorheight=true;
            }
            else{
                this.say("4");
                this.turnLeft(smartTurn(270-heading));
                this.ahead(size[1]-currentPos[1]-sizeTank[1]);       
                 this.turnLeft(90);
       this.ahead(size[0]-currentPos[0]-sizeTank[0]);
                widthorheight=false;
            }
  },
  onHitRobot:function(e){
            var tankangle=this.getHeading();
            var angleToTurn1=smartTurn(tankangle-this.getGunHeading());
            this.turnGunLeft(smartTurn(angleGunToTurn));
            this.fire(3);
  }
 });
});
代码较为冗长且没有足够的注释,各位勉强看一下,以上代码为开源代码,搜索kq2h5可以找到我的代码,欢迎大家来战,同时也欢迎大家提出改进意见。
以上代码的设计思路主要参考示例代码中的corner代码,由于在角落只受到来自某一个象限的攻击,所以极大的保护了自己,特别是在混战当中,另外位于角落的tank只要将炮身旋转90°即可扫描整个战场,大大提高了扫描战场的效率,当然也就更加容易发现“敌人”,基于此目的我参考了corner示例代码,然而示例代码不管tank在任何位置都要跑到左上角,这无疑给敌人提供了许多攻击的机会,所以我选择最近的角落,另外若是受到攻击不进行躲避的话也就成了活靶子,所以我设计了一个躲避算法,当然,这个躲避算法太有规律了,并不是很好的算法,整个战术还有待改进和提高。

不如意

小时候很要强,不管做什么事情总是要做得比别人好,对于曾经的自己来说这个很重要,因为证明自己的优秀与成功总是对少年有着特别的吸引力,得到别人的夸赞总是那么的舒畅。
可是随着时间的推移,我们看到了太多的少年天才,看到了太多的煊赫家室,看到了太多无奈与妥协,所以我们终于接受了自己只是一个平凡的普通人这个事实。所以有人在没有主角光环加持下变得不知所措,变得茫然甚至报复社会。我能理解他们,曾经以为自己是主角,到最后却只是陪衬的滋味是有多么难受!!
其实并没有什么不公平,只是有些许的无奈罢了,若生天地间,事事都如意,那才是一件让人惊恐的事情吧。面对太多困惑,面对太多不知所措,面对太多惶恐,面对太多忽视与尴尬,我们才会渐渐成长,我们不是这个世界的中心,可是我们却是我们生活的中心,那些不如意让我们渐渐成长为一个坚强的样子,然后撑起生活的天空。
最近天气不太好,天气也是阴沉沉的,气压有些大,加上闷热的天气让人觉得很沉闷,呆在实验室也有种特别厌恶的情绪,所以早早的就离开了~

Hello Tutorial!

Welcome to StackEdit!

Hey! I’m your first Markdown document in StackEdit1. Don’t delete me, I’m very helpful! I can be recovered anyway in the Utils tab of the Settings dialog.

Documents

StackEdit stores your documents in your browser, which means all your documents are automatically saved locally and are accessible offline!
Note:
  • StackEdit is accessible offline after the application has been loaded for the first time.
  • Your local documents are not shared between different browsers or computers.
  • Clearing your browser’s data may delete all your local documents! Make sure your documents are synchronized with Google Drive or Dropbox (check out the Synchronization section).

Create a document

The document panel is accessible using the button in the navigation bar. You can create a new document by clicking New document in the document panel.

Switch to another document

All your local documents are listed in the document panel. You can switch from one to another by clicking a document in the list or you can toggle documents using Ctrl+[ and Ctrl+].

Rename a document

You can rename the current document by clicking the document title in the navigation bar.

Delete a document

You can delete the current document by clicking Delete document in the document panel.

Export a document

You can save the current document to a file by clicking Export to disk from the menu panel.
Tip: Check out the Publish a document section for a description of the different output formats.

Synchronization

StackEdit can be combined with Google Drive and Dropbox to have your documents saved in the Cloud. The synchronization mechanism takes care of uploading your modifications or downloading the latest version of your documents.
Note:
  • Full access to Google Drive or Dropbox is required to be able to import any document in StackEdit. Permission restrictions can be configured in the settings.
  • Imported documents are downloaded in your browser and are not transmitted to a server.
  • If you experience problems saving your documents on Google Drive, check and optionally disable browser extensions, such as Disconnect.

Open a document

You can open a document from Google Drive or the Dropbox by opening the Synchronize sub-menu and by clicking Open from…. Once opened, any modification in your document will be automatically synchronized with the file in your Google Drive / Dropbox account.

Save a document

You can save any document by opening the Synchronize sub-menu and by clicking Save on…. Even if your document is already synchronized with Google Drive or Dropbox, you can export it to a another location. StackEdit can synchronize one document with multiple locations and accounts.

Synchronize a document

Once your document is linked to a Google Drive or a Dropbox file, StackEdit will periodically (every 3 minutes) synchronize it by downloading/uploading any modification. A merge will be performed if necessary and conflicts will be detected.
If you just have modified your document and you want to force the synchronization, click the button in the navigation bar.
Note: The button is disabled when you have no document to synchronize.

Manage document synchronization

Since one document can be synchronized with multiple locations, you can list and manage synchronized locations by clicking Manage synchronization in the Synchronize sub-menu. This will let you remove synchronization locations that are associated to your document.
Note: If you delete the file from Google Drive or from Dropbox, the document will no longer be synchronized with that location.

Publication

Once you are happy with your document, you can publish it on different websites directly from StackEdit. As for now, StackEdit can publish on Blogger, Dropbox, Gist, GitHub, Google Drive, Tumblr, WordPress and on any SSH server.

Publish a document

You can publish your document by opening the Publish sub-menu and by choosing a website. In the dialog box, you can choose the publication format:
  • Markdown, to publish the Markdown text on a website that can interpret it (GitHub for instance),
  • HTML, to publish the document converted into HTML (on a blog for example),
  • Template, to have a full control of the output.
Note: The default template is a simple webpage wrapping your document in HTML format. You can customize it in the Advanced tab of the Settings dialog.

Update a publication

After publishing, StackEdit will keep your document linked to that publication which makes it easy for you to update it. Once you have modified your document and you want to update your publication, click on the button in the navigation bar.
Note: The button is disabled when your document has not been published yet.

Manage document publication

Since one document can be published on multiple locations, you can list and manage publish locations by clicking Manage publication in the menu panel. This will let you remove publication locations that are associated to your document.
Note: If the file has been removed from the website or the blog, the document will no longer be published on that location.

Markdown Extra

StackEdit supports Markdown Extra, which extends Markdown syntax with some nice features.
Tip: You can disable any Markdown Extra feature in the Extensions tab of the Settings dialog.
Note: You can find more information about Markdown syntax here and Markdown Extra extension here.

Tables

Markdown Extra has a special syntax for tables:
Item Value
Computer $1600
Phone $12
Pipe $1
You can specify column alignment with one or two colons:
Item Value Qty
Computer $1600 5
Phone $12 12
Pipe $1 234

Definition Lists

Markdown Extra has a special syntax for definition lists too:
Term 1
Term 2
Definition A
Definition B
Term 3
Definition C
Definition D
part of definition D

Fenced code blocks

GitHub’s fenced code blocks are also supported with Highlight.js syntax highlighting:
// Foo
var bar = 0;
Tip: To use Prettify instead of Highlight.js, just configure the Markdown Extra extension in the Settings dialog.
Note: You can find more information:
  • about Prettify syntax highlighting here,
  • about Highlight.js syntax highlighting here.

Footnotes

You can create footnotes like this2.

SmartyPants

SmartyPants converts ASCII punctuation characters into “smart” typographic punctuation HTML entities. For example:
ASCII HTML
Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
Quotes "Isn't this fun?" “Isn’t this fun?”
Dashes -- is en-dash, --- is em-dash – is en-dash, — is em-dash

Table of contents

You can insert a table of contents using the marker [TOC]:


MathJax

You can render LaTeX mathematical expressions using MathJax, as on math.stackexchange.com:
The Gamma function satisfying is via the Euler integral

Tip: To make sure mathematical expressions are rendered properly on your website, include MathJax into your template:
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>

Note: You can find more information about LaTeX mathematical expressions here.

UML diagrams

You can also render sequence diagrams like this:
Created with Raphaël 2.1.2AliceAliceBobBobHello Bob, how are you?Bob thinksI am good thanks!
And flow charts like this:
Created with Raphaël 2.1.2StartMy OperationYes or No?Endyesno
Note: You can find more information:
  • about Sequence diagrams syntax here,
  • about Flow charts syntax here.

Support StackEdit



  1. StackEdit is a full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.
  2. Here is the text of the footnote.

最动人的莫过于音乐与诗——南方姑娘

南方姑娘
作词:赵雷 作曲:赵雷
演唱:赵雷
北方的村庄住着一个南方的姑娘
她总是喜欢穿着带花的裙子站在路旁
她的话不多但笑起来是那么平静悠扬
她柔弱的眼神里装的是什么 是思念的忧伤
南方的小镇阴雨的冬天没有北方冷
她不需要臃肿的棉衣去遮盖她似水的面容
她在来去的街头留下影子芳香才会某然的心痛
眨眼的时间芳香已飘散影子已不见
南方姑娘 你是否习惯北方的秋凉
南方姑娘 你是否喜欢北方人的直爽
日子过的就像那些不眠的晚上
她嚼着口香糖对墙满谈着理想
南方姑娘 我们都在忍受着漫长
南方姑娘 是不是高楼遮住了你的希望
昨日的雨曾淋漓过她瘦弱的肩膀
夜空的北斗也没有让她找到迷途的方向
阳光里她在院子中央晾晒着衣裳
在四季的风中她散着头发安慰着时光
南方姑娘 你是否爱上了北方
南方姑娘 你说今天你就要回到你的家乡
思念让人心伤 她呼唤着你的泪光
南方的果子已熟 那是你简单的理想
啦……啦……
很早很早就想写一篇关于民谣的音乐赏析,一直在犹豫,不知道哪一首歌比较好,在本科毕业的时候曾和朋友们一起排练了很久那首老狼的《睡在我上铺的兄弟》,当时听着这首歌也是感动的热泪盈眶。也许是因为毕业季的忧伤吧,又过了这么些年,现在听到这首歌也是感触特别深,当然还有许许多多的民谣都是我喜欢的。为什么是这一首,因为前段时间刚练了这一首比较熟。
我理解的民谣就是简单的叙事,从生活中的小事出发,把一件简单的事情娓娓道来,没有那些华丽的语言和曲调和声,简单的语言加上简单的和弦,还有一张略带沙哑的嗓子。随着年纪的增加,那些疯狂的摇滚和jazz已经离我们渐渐远去,那些华丽深沉的古典又太过高不可攀,于是就渐渐爱上了民谣,爱上了这种简单的调调,简单干净的和弦,不需要有多好的嗓音,不需要有多高超的技巧,不需要有多么热情的观众,一个人也好,一群人也罢,只是唱着我们想唱的歌,享受音乐和生活的简单快乐。
好了,下面我们说说这首歌吧,其实这是我第一次听赵雷的歌,也是听过的他的唯一一首歌。这首歌很简单,也很直白,到网上看了很多人对这首歌的体会,有很多人提到听首歌就不由得想起了自己的那个她,只不过因为最后种种原因而没有能够在一起,这确实挺让人遗憾的。可是转头一想这又何尝不是另一种美呢,因为遗憾,所以才回在心中保留着最美好的样子,因为思念所以才有呼唤。因为前世的一万次回眸已经换来了此生最好的相遇,这样不就够了么!也曾想起那个在阳光下晾晒这衣服的姑娘不是么?也曾想起你们一起畅谈过的理想不是么?现实虽然无奈,但是毕竟在心中还有那一些美好。这让我想起了星爷在大话西游中,紫霞在至尊宝心中依旧留下了一滴眼泪不是么!

图像修补算法

小尺度,基于微分方程的方法:
1.BSBC算法:
算法的基本思想:
image
我认为这个算法其实就是一个迭代的思想,对原始位置的像素进行迭代求解,经过多次迭代之后像素位置的值趋向于稳定,当值趋向于稳定之后就认为达到了修复的目的。
BSBC修复步骤:
a).首先由用户提供修复的图像并指明要修复的区域,用一个和待修复图像同样尺寸的2维逻辑矩阵来标识要修复的区域,(1表示要修复,0表示不要修复)

image
image
b)然后进入修补循环
修补循环主要由三个部分构成:信息传递与像素值更新、扩散过程、程序终止检验。
(1)信息传递与像素值更新,(每次循环执行A次此步骤):图像的缺损意味着某种信息的丢失。图像修补的目的就在于将可靠的信息从完好的区域到缺损的区域更新方程为:
Eq(1)
image
其中image为控制更新速率的常数,值越大表示每次更新的值越多,更新越快但是精度比较低,image为每次更新的值,其表达式为:
Eq(2)
image
每一个像素点的信息值用该店的拉普拉斯算子表示,这样等照线上的点将具有相同的拉普拉斯值:
image
因为等照度线上的点应具有相同的的拉普拉斯值,所以如果等照度线在破损区的边界处断裂,就需要沿着等照度线的方向更新image,更新的公式为:
image
等照度线的方向为梯度方向旋转90°得到,因为等照度线上各个点的灰度相同,且沿着等照度线的方向变化最小,而沿着梯度方向的灰度变化最大,应与等照度线的方向正交,梯度的方向为:
image,对梯度方向进行归一化,得到归一化的等照度线方向。归一化的公式为:
Eq(3)
image
求等照度方向的源码为:
image
从源码我们看出其实就是求xx方向和yy方向的梯度值,然后对梯度值进行归一化得到等照度方向。
公式2中image为收敛因子,通过收敛因子可以防止更新向着正反馈的方向进行
Eq(4)
image
收敛因子下标M表示与0比取较大值,下标m表示与0比取较小值,下标x,y表示沿着坐标轴方向的差分,下标b,f分别表示向前和向后的差分。
整个信息传递与像素更新过程总结:
首先得到更新方程,更新方程是从影像原始值出发进行迭代,对于待修补的区域,更新的公式见公式1,然后更新公式中有两个参数分别为更新率控制常数image和每次更新的值image更新率控制常数是用户给定的,每次更新的值通过公式2求取,公式2中有三个参数,像素点信息值,等照度方向,和收敛因子,像素点信息值可以通过该点的拉普拉斯算符表示,等照度线的方向为梯度方向旋转90°得到,然后得到归一化等照度线方向通过公式3,最后通过公式4求取收敛因子防止更新向着正反馈的方向进行。
2)扩散过程
扩散的目的是为了消除在更新过程中产生的混叠与模糊。扩散的方程为:
Eq(5)
image
image是待修复区域加上其向外扩张的区域,K表示的是等照度线的曲率,imageimage内为1,否则为0,则扩散过程的离散表示为:
Eq(6)
image
3)终止条件,当图像的状态趋于稳定之后我们可以认为图像的修复结束,跳出修复循环,程序结束,终止条件的过程数学公式表达为:
Eq(7)
image
当公式7中SSD小于某个给定阈值时则终止。
基于影像块匹配的影像修复方法:
主要思想为利用已知区域中的相似块来填补待修复区域的空白,主要是在待修复影像的边界处选取一定窗口大小的影像,通过在正确影像区域寻找相似性最大的区域进行寻找,找到相似性最大的区域进行填补。
image
上图说明了整个影像修复的过程,image为正确的影像区域,image为待修复的影像区域,image为正确影像与待修复影像的边界。我们在b图中找到一个边界点上待修复的点p,在整个影像区域找到相似行最大的区域q,然后使用q对未修复的影像进行填补,最后更新影像待修复和已知修复区域的边界。
通过优先级设置修补辩解的起始位置:
image
对于边界上p点的一个模板范围image,其中有一部分在已知区域中,一部分在未知区域中,我们定义优先级计算为:
Eq(8)
image
其中C为信心系数,D为数据系数,信心系数和数据系数的计算公式为:
Eq(9)
image
其中image为未知区域的面积,image为归一化系数,对于8bit的灰度图像,归一化系数为255,image为与p点的边界正交的单位向量,image为P点的等照度线方向。对每一个边界点都计算优先系数,得到优先系数最大的边界点位置,从优先系数最大的边界点位置进行处理。信心系数在初始化过程中,在已知区域为1,在未知区域为0。
信心系数是衡量修复可靠性的依据,对于一个未知区域,周围已知像素越多则对次像素进行修复的可靠性越大。位置系数为衡量待修补点的位置的关键性,一般在纹理交接处的点应该最先修补,有较大的数据系数
image
上述两图说明了信心系数和数据系数,对于图a,在绿色区域具有较高的信心系数在红色区域具有较低的信心系数,对于图b,在绿色区域具有较高的数据系数,数据系数在影像结构纹理连续的地方具有较大值。
传播纹理和结构信息:
结构和纹理信息的修复通过在已知区域寻找和未知区域最相似的区域来进行修复,修复公式描述如下:
Eq(10)
image
信心系数值的更新:
进行区域修复后需要对边界进行更新,更新边界的优先级系数:
Eq(11)
image
通过这样简单的更新规则可以允许使用前一次填补好的进行下一次的计算。
整个处理过程如下:
image
参考文献:
Bertalmio M, Sapiro G, Caselles V, et al. Image inpainting[C]//Proceedings of the 27th annual conference on Computer graphics and interactive techniques. ACM Press/Addison-Wesley Publishing Co., 2000: 417-424.

Criminisi A, Pérez P, Toyama K. Region filling and object removal by exemplar-based image inpainting[J]. Image Processing, IEEE Transactions on, 2004, 13(9): 1200-1212.

Java Web 开发学习(三)——界面的美化

想做一个关于根据日期进行查询的功能,而此功能最好是能够选择输入的日期,这样就能够方便进行查询和格式化,当然咯在选择日期的时候应该选择一个日期范围,这样才能比较好的获取输入日期。
但是boostrap并没有直接提供一个可供输入的日期控件啊!!!为什么连一个可供输入的日期选择控件都不给我。好吧面对这种情况理论上应该自己添开发一个控件,可是我对前端真的不熟,臣妾真的做不到啊!所以我在网上搜索再三终于让我找到了一个比较好用的控件:https://github.com/dangrossman/bootstrap-daterangepicker这时此控件的git地址,控件的介绍很详细,使用起来也比较简单,总的来说就是选择起始日期和终止日期,最终显示在text标签上,控件的下载后介绍图片为:
image
通过此控件选择起始和终止日期,然后根据起始和终止日期作为一个表单提交给服务器,服务器获取此表单之后解析起止时间,然后在数据库中查询,最终将得到的查询结果显示出来。具体使用代码为:

image
通过代码可以看到,我们首先构建了一个表单,然后生成一个group标签,group标签中有输入的text,这个text与我们的daterangepicker绑定,然后有一个提交按钮,按钮设置图标,下面就是daterangepicker的js代码,然后在head中引入需要用到的头文件,整个控件就能使用了,由于我是在一个局部使用,所以时间选择为上下排布,这样我们得到了一个选择时间范围的搜索,具体情况如下:
image
上面一部分提到了数据范围输入提交表单,下面我们提一提循环显示框,在网上闲逛时突然发现一个超炫的显示窗口,于是乎也用到了我的界面上,虽然感觉有点不搭调,但是好歹看起来比较炫丽,显示效果为:
image
由于截动态图比较大,而且比较麻烦,所以懒得截动态图了,起始整个显示框是3D的且可以进行旋转,看起来是不是很吊,这个控件主要来源算了,找不到了,大家有兴趣可以网上找找,当然,这个控件还是有一些缺点的也不能说是缺点吧,就是感觉自己用的不是很好,在网页缩放的时候不能自动的进行响应式的布局,在这一点上我觉得对这个控件本身的应用造成了极大的限制,在此情况下,此控件做一个web端的界面是可以的,但是移植到移动端恐怕会引起一些不舒适。
下面是我整个代码的Git地址有兴趣可以下载下来看看:https://github.com/wuweiFrank/JavaDemo1

我有一壶酒,足以慰风尘。
去时青丝结,归乃华发生。

少年江湖梦,终老尽归尘。

四顾皆茫然,新坟堆旧坟。

较新的博文 较旧的博文 主页