本项目实现两种不同的图像表示——小图像和SIFT特征包,以及两种不同的分类技术——最近邻和线性SVM。通过试验得到准确率是
小图像和最近邻分类器 (准确率20.50%).
SIFT表示包和最近邻分类器 (准确率49.99%).
SIFT表示包和线性SVM分类器 (准确率68.10%). 以下通过4个方面进行详细说明:
小图像特征.最近邻分类器.SIFT表示包.SVM分类器 系统环境:
操作系统:WIN7
实现平台:MATLAB2014a
一.小图像特征表示 小图像表示法比较简单,对图像进行抽样,使图像缩小至16*16的大小。
代码如下:
N = size(image_paths,1); image_feats = [];
for i = 1:N path = image_paths{i,1};
image = imread(path);
%image = rgb2gray(single(image)/255); %转换为灰度图像
image = imresize(image,[16,16]); %转换为16*16的大小
image = reshape(image, 1, 256); %转换为1*256的大小
image_feats = cat(1,image_feats,image);
end
二.最近邻分类器 KNN近邻分类器是一种有监督的分类算法。此项目中,测试图像直接在训练图像集中寻找距离最短的图像,将本测试图像的类别就分为此距离最短的训练图像的类别
实现起来也很简单,以下是代码:
predicted_categories = [];
D = vl_alldist2(test_image_feats',train_image_feats'); %行转换为列进行距离计算256列
[Y,I] = min(D); %最小距离的计算
predicted_categories = train_labels(I); %返回最近邻(最相似)的类别
三.SIFT表示包 Bag-of-words模型是信息检索领域常用的文档表示方法。在信息检索中,BOW模型假定对于一个文档,忽略它的单词顺序和语法、句法等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的,不依赖于其它单词是否出现。也就是说,文档中任意一个位置出现的任何单词,都不受该文档语意影响而独立选择的。
去下载
看了u-boot的relocate_code函数,以及查了网上其他人的帖子后,写一下自己对relocate_code的理解。
参考文章
http://blog.csdn.net/skyflying2012/article/details/37660265
http://blog.csdn.net/gjq_1988/article/details/22315913
1. 重定向
uboot最重要的一个功能就是relocate,重定向。重定向最通俗的说,就是把NAND Flash上程序搬到内存中。重定向涉及到三个地址,链接地址、加载地址和运行地址。我们先假设这三个地址都是0x32000000。
链接地址是我们在uboot里面配置的,由链接器读取并用于生成uboot的二进制。
加载地址是uboot重定向时,拷贝源码的目的地址。通俗地讲,就是把NAND Flash里的uboot代码拷贝到内存的哪个地址上。
运行地址是指uboot在内存中运行的地址。uboot运行时的一些寻址操作,就跟运行地址有关系。
由于uboot的二进制文件直接或间接地包括了内存的绝对物理地址,所以以上三个地址一般是一样的。通俗地讲,uboot把内存的绝对物理地址固定在了二进制文件里,所以uboot应该被拷贝到内存哪个地方,下一条指令应该跳转到哪个物理地址都是在编译的时候就已经固定的。
2. 旧版本uboot的重定向
旧版本的uboot只有一个重定向,而且这个重定向是由移植uboot的工程师,根据具体的板子配置来编写的。比如从NAND Flash拷贝0x32000000开始的内存地址;或者从NOR Flash拷贝到0x80800000开始的内存地址。这都是由CPU和板子配置决定的。
3. 新版本uboot的重定向
新版本的uboot有两个重定向,第一个重定向跟老版本是一模一样的,目的就是从NAND Flash或者NOR Flash这些存储设备中把代码拷贝到内存地址(destA)中。还有第二个重定向,这个重定向函数就是relocate_code。这部分代码是uboot官方做好的,我们并不需要修改。它的作用就是把uboot从当前的位置(destA)拷贝到内存的高端地址(destB)上。Linux内核一般用的低端的内存地址,所以uboot选了一个高端地址。但至于为什么还得有第二次的重定向,原因我并不清楚。即使把第二次的重定向屏蔽,uboot还是可以正常运行的。
4.relocate_code函数原理
relocate_code并不是简单的把destA的内容拷贝到destB就完事这么简单的。如果就这样直接拷贝,uboot是运行不了的,原因如第1点所述。
看了别人的文章以后,有了大致的概念。这里我假设要把0x32000000地址上的uboot重定向到0x80000000。
1)链接器要加上-pie的选项,这样生成的代码就是位置无关的。通俗地讲,就是以前我要跳转到一个函数,可能我就直接一条语句,就跳过去了。
320068c8: eb001688 bl 320068e4 <funcA> ;funcA在0x320068e4的地址,直接跳转到0x320068e4的绝对地址 .... 320068e4 <funcA>: 320068e4: e59f0000 mov r0, r1 .... 但位置无关的代码,就会根据PC的值,做一个相对位置的跳转,而PC值是可以在运行时被修改的。 320068c8: eb001688 ldr r0, [pc, #20];这里表示是把将要跳转的地址放到r0中,没有把绝对地址固定在命令里。r0=pc+8+20=0x320068c8+8+20。这个8是由ARM的流水线机制决定的,PC里的值是当前地址+8.
320068cc: e3a00000 mov pc, r0; 把r0的值赋给pc,实现跳转 .... 320068e4 <funcA>: 320068e4: e59f0000 mov r0, r1 .... 上面的代码在relocate_code之后,直接修改pc到新位置0x80000000,这个时候由于funcA的位置已经变为0x800068e4,而pc的值也变为0x800068c8,所以经过计算以后的跳转是不会出错的。
2) 有了上面的一点还不够,上面只实现了重定向以后函数的跳转,但一些全局变量的位置还是不正确。
全局变量的重定向,借助了一个叫GOT(Global Offset Table)的表。每一条GOT Entry记录了一个对象的地址,这个对象可以是变量或者函数。
简单来说,就是不能识别指针和非指针的GC
寄存器,调用栈和全局变量空间都是不明确的根
以调用栈为例:
调用栈里有调用帧,调用帧里有函数内的局部变量和参数的值,不过,局部变量既有int double这样的非指针,也有void * 这样的指针,而对于GC调用帧的值只是一堆位的排列,所以,GC并不能识别指针和非指针,所以,叫做不明确的根
保守式GC:把不能识别指针还是非指针的对象当做指针来保守处理,也就是当成活动对象保留下来
比如C里边的union
union{ long n; void *ptr;}ambiguous_data; 它是联合体,所以,GC没法发识别是指针还是非指针,当对象有这样的数据结构时,就可能会识别错误
优点:处理程序不依赖于GC,代码编写者即使没有意识到GC的存在,程序也会自己回收
缺点:
1)识别指针和非指针需要耗费成本
2)错误识别的指针会被当成活动的对象,包括其子对象,可能会造成垃圾对象压迫堆
3)能够使用的GC算法有限
### 精准式GC
可以精准的识别指针和非指针
打标签:利用指针的值是4的倍数的特性(所以低2位都是0),作为识别指针和非指针的依据
1)将非指针的值向左移动1位
2)将低1位置1
注意,打标签的过程不要让数据溢出,用这种方式打标签的话,处理程序里的数值都会是奇数,在程序里进行计算时必须先取消标签,再计算数值,基本上打标签和取消标签都是在程序里手动执行的
优点:不会留下非活动对象
缺点:要求处理程序的配合,给实现者带来麻烦,且每次取消标签,再重新设置,会影响到程序处理的整体速度
#### 间接引用:
根和对象之间是有一个句柄存在的,它持有指向对象的指针,且局部变量和全局变量这些不明确的跟里没有指向对象的指针,值的指针,只装着指向句柄,也就是mutator操作对象时,要经过有句柄的间接引用来执行处理,也就是如果采用间接引用,即使移到了引用目标的对象,也不用改写关键的值,只需要改写句柄里的指针即可
优点:有可能实现GC复制算法和压缩标记算法
缺点:所有对象都是间接引用,会拉低访问对象内数据的速度,这会关系到整个语言的处理速度
#### 保守式GC复制
就是把不明确的根指向的对象以外的对象都复制的GC算法,需要满足以下前提:
1)根是不明确的根
2)没有不明确的数据结构(表明GC可以明确判断对象里的域是指针还是非指针)
3)对象大小随意
4)CPU是32位(不是说,必须是32位,而是在此以32位CPU为例)
堆结构:
堆被分成一定大小的页,那些未被分配到对象的空页则有一个$current_space以外的编号
分配:
1)正在使用的页刚好有符合mutator申请的对象大小的分块,直接分配
2)正在使用的页没有合适的分块,会被分配到新的页,然后将改页设置object标记
3)申请分配大小超过页空间时,和平时分配一样,在开头设定object,然后在第二个页之后设置continued标志
当正在使用的页 + 准备分配的页 >= 总夜大小/2时,就会开始运行GC
GC执行的过程:先对next_space的值++,然后将保留有从根引用对象的页的编号设定为next_page的值,即2,最后GC把所有从根引用的页next_space++之后,就把to页里的对象的子对象复制到空白页,复制完成之后,GC就结束了,这时程序把current_page的值设定为next_space的值
注意,它不会回收包含有从根指向的对象的页里的垃圾对象,而且也不会回收这个垃圾对象所引用的子对象
#### 黑名单机制
黑名单就是把需要注意的地址空间记录下来
在将对象分配到黑名单内的地址时,所分配的对象有以下限制:
1)小对象
2)没有子对象的对象
这样,即使对象成了垃圾且没有被回收也不会有很大的损失
优点:使保守式GC因错误识别对象而压迫堆的问题得到缓解,堆的使用效率提升
缺点:需要花费时间检查黑名单
相信很多同学在写js的时候都遇到过闭包的问题,让我们先来看一个背景介绍, 有这样一组按钮,可能是成千上万个,他们需要一个点击事件来处理不同的情况,最暴力的办法是为每个按钮绑定一个事件,但这显然不是最佳的方法。那么最佳的方法是什么呢?假如他们每个按钮都有一个序号(我将这些按钮的id以升序排列,并存放在数组click_pops中,对应的button的id即为’#’+click_pops[i]),那么有人可能想对序号排序,然后对每个按钮添加绑定事件,大概是这样
for(var i = 0; i < click_pops.length; i ++){ $('#'+click_pops[i]).on('click',function(e){ toItsOwnFunc(i); }) } 可是这样真的可以嘛?不妨一试,你会看到这并不会像想象中的那样为每个按钮添加点击事件,这个问题的解答主要是由于ES5的作用域的问题,当进行过这层循环后,i的最终值为click_pops.length,所以只有#click_pops[click_pops.length]才绑定了点击事件,如果你仔细并理解了闭包,那么你可能就会有以下的想法了
for(var i = 0; i < click_pops.length; i ++){ $('#'+click_pops[i]).on('click',(function(i){ return function(){ toItsOwnFunc(i); } })(i)) } 这里就是用了闭包做了处理了,我们传入一个局部变量i,这样使得每次都是真的在为第i个元素绑定事件。
说到绑定事件,原生的绑定事件是这样的 function addEvent(obj,type,handle){ try{ // Chrome、FireFox、Opera、Safari、IE9.0及其以上版本 obj.addEventListener(type,handle,false); }catch(e){ try{ // IE8.0及其以下版本 obj.attachEvent('on' + type,handle); }catch(e){ // 早期浏览器 obj['on' + type] = handle; } } }
1、类的概念: <?php //使用class关键字定义类 class NBAPlayer{ //使用访问修饰符定义属性 public $name="wuyonghu"; //使用__construct关键字定义构造函数 function __construct($name) { //使用$this表示当前实例对象 $this ->name=$name; echo "构造函数调用了"; } //使用__destruct关键字定义析构函数 function __destruct() { echo "对象销毁了"; } //使用function关键字定义方法 public function run(){ echo "调用了run的方法"; } } //使用new关键字实例化 $wuyonghu=new NBAPlayer("吴永胡"); //使用->符号来访问到对象中的属性 对应的属性不需要添加$符号了 echo $wuyonghu->name; echo "<br>"; //使用->符号来调用对应实例的方法 $wuyonghu->run(); 对象引用的概念: //这两个是不同的引用 $wuyonghu1=$wuyonghu; //同一个引用 不同名字而已 $wuyonghu1=&$wuyonghu;
初次使用spring boot,按照其官网Building a RESTful Web Service搭建运行一个demo,代码如下:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>personal.timeless</groupId> <artifactId>CommentSystem</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>CommentSystem Maven Webapp</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <scope>test</scope> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </pluginRepository> </pluginRepositories> </project> controller Comment.
今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式。
BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能;当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度等等。Android中的广播机制设计的非常出色,很多事情原本需要开发者亲自操作的,现在只需等待广播告知自己就可以了,大大减少了开发的工作量和开发周期。而作为应用开发者,就需要数练掌握Android系统提供的一个开发利器,那就是BroadcastReceiver。
在我们详细分析创建BroadcastReceiver的两种注册方式前,我们先罗列本次分析的大纲: (1)对静态和动态两种注册方式进行概念阐述以及演示实现步骤
(2)简述两种BroadcastReceiver的类型(为后续注册方式的对比做准备)
(3)在默认广播类型下设置优先级和无优先级情况下两种注册方式的比较
(4)在有序广播类型下两种注册方式的比较
(5)通过接受打电话的广播,在程序(Activity)运行时和终止运行时,对两种注册方式的比较
(6)总结两种方式的特点
第一步:静态和动态注册方式基本概念以及实现步骤 构建Intent,使用sendBroadcast方法发出广播定义一个广播接收器,该广播接收器继承BroadcastReceiver,并且覆盖onReceive()方法来响应事件注册该广播接收器,我们可以在代码中注册(动态注册),也可以AndroidManifest.xml配置文件中注册(静态注册)。
动态注册: 效果如下图:
这里就不演示点击按钮布局的实现了,MainActivity.java中实现代码如下:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
DynamicReceiver dynamicReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化IntentFilter对象
IntentFilter filter = new IntentFilter();
filter.addAction("panhouye");
dynamicReceiver = new DynamicReceiver();
//注册广播接收
registerReceiver(dynamicReceiver,filter);
}
//按钮点击事件
public void send2(View v){
Intent intent = new Intent();
intent.
主题简介: 游戏开发是所有软件开发类型中最难的一种,不仅技术门槛高,而且要求各种专业人员(策划、程序、美术等等)高度的协同配合。所以实际项目过程中,需要有明确的流程和规范,确保游戏进度良性推进。简单地说,就是要让团队每个人明确要做什么;什么时候完成;完成到什么程度。
演讲内容:
为什么要有规范
?游戏开发是所有软件开发类型中最难的一种。 ?要求各种专业人员(策划、程序、美术等等)高度的协同配合。 ?确保游戏进度良性推进。
规范的目的
?让团队每个人都明确: ?要做什么? ?什么时候完成? ?完成到什么程度?
? 悲剧: ? 前期松散,后期加班,工作量无从估计。
一、 游戏项目流程
1. 原型阶段 ? 实现游戏的必要技术验证。 ? 产出:一个最简单的只有1关或者1个场景的的游戏原型。美术效果图。 2. Alpha版阶段 ? 完善游戏角色的逻辑,定义完善的数据结构和关卡配置,制作游戏UI,菜单UI等。 ? 产出:一个能玩若干关卡的版本。 3. Beta版阶段 ? 完善逻辑,批量制作美术,关卡或者其他游戏内容,细化UI等各方面。加IAP, GameCenter等。 ? 产出:完整的可玩版本,具备所有的游戏内容、关卡等。 4. 产品阶段 ? 测试,修Bug,图标,截图,多语言说明,视频录制等等准备上线需要做的一切事情。提交上线。 ? 产出:可以提交上线的app包。
二、 项目结构
Unity项目目录结构
? 自定义目录以“_”开头。? 一级目录 ? 大小写。 ? 原始素材全小写+下划线 ? 加工过的素材, Prefab等, 大小写 ? 文本需求文档...
? 文本需求文档(小团队任务管理)。 代码规范 ? 类命名:大小写。例如:EnemyAI.cs。 ? 类变量命名:首字母小写。或者m开头。例如:mPoints。 ? 函数内变量命名:全小写+下划线,或者下划线开头。例如:new_amount。
代码功能结构规范 ?
/*==================================================================== BSD 2-Clause License Copyright (c) 2020, Ruler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
UNet常见概念简介 Spawn:简单来说,把服务器上的GameObject,根据上面的NetworkIdentity组件找到对应监视连接,在监视连接里生成相应的GameObject.
Command:客户端调用,服务器执行,这样客户端调用的参数必需要UNet可以序列化,这样服务器在执行时才能把参数反序列化。需要注意,在客户端需要有权限的NetworkIdentity组件才能调用Command命令。
ClientRpc:服务端调用,客户端执行,同上,服务端的参数序列化到客户端执行,一般来说,服务端会找到上面的NetworkIdentity组件,确定那些客户端在监视这个NetworkIdentity,Rpc命令会发送给所有的监视客户端。
Server/ServerCallback:只在服务器端运行,Callback是Unity内部函数。
Client/ClientCallback:同上,只在客户端运行,Callback是Unity内部函数。
SyncVar:服务器的值能自动同步到客户端,保持客户端的值与服务器一样。客户端值改变并不会影响服务器的值。
上面的大部分特性都会转化成相应的MsgType,其中服务器调用,客户端执行对应MsgType有如Spawn,ClientRpc,SyncVar对应的MsgType分别为ObjectSpawn,Rpc,UpdateVars,这些都是NetworkServer调用,客户端得到相应消息,执行相应方法。客户端调用,服务器执行的MsgType有如Command,客户端发送,服务器检测到相应消息后执行。
UNet主要类介绍 NetworkIdentity组件介绍:网络物体最基本的组件,客户端与服务器确认是否是一个物体(netID),也用来表示各个状态,如是否是服务器,是否是客户端,是否有权限,是否是本地玩家等。一个简单例子,A是Host(又是服务器,又是客户端),B是一个Client,A与B分别有一个玩家PlayA与PlayB.在机器A上,playA与playB isServer为true,isClent为true,其中playA有权限,是本地玩家,B没权限,也不是本地玩家。在机器B上,playA与playB isServer为false,isClent为true,其中playB有权限,是本地玩家,A没权限,也不是本地玩家。A与B上的PlayA的netID相同,A与B上的PlayB的netID也相同,其中netID用来表示他们是同一网络物体在不同的机器上。 在下面用网络物体来表示带有NetworkIdentity组件的GameObject.
NetworkConnection:定义一个客户端与服务器的连接,包含当前客户端监视那些服务器上的网络物体,以及封装发送和接收到服务器的消息。
NetworkClient:主要持有当前NetworkConnection对象与所有NetworkClient列表的静态对象,处理一些默认客户端的消息。
网络物体上的监视者就是一个或多个NetworkConnection,用来表示一个或多个客户端对这个网络物体保持监视,那么当这个网络物体在服务器上更新后,会自动更新对所有监视者的对应的网络物体。
NetworkScene:简单来说,1Server与Client需要维护一个网络物体列表,Server可以遍历所有网络物体发送消息等,并且维持Server与Client上的网络物体保持同步,并且客户端记录需要注册的prefab列表.其中NetworkServer与ClientScene都包含一个NetworkScene对象,引用网络物体列表。
NetworkServer:主要持有一个NetworkScene并且做一些只有在服务器上才能对网络服务做的事,如spawn, destory等。以及维护所有客户端连接。
ClientScene:主要持有一个静态NetworkScene对象,用于注册网络物体的prefab列表,以及客户端场景上已经有的网络物体列表,处理SyncVar,Rpc,SyncEvent特性等,还有以及ObjectSpawn,objectDestroy,objectHide消息等。
UNet用时想到的问题 问题1 spawn发生了什么,客户端为什么要注册相应的prefab. 当服务器spawn一个网络物体时,网络物体调用OnStartServer,分配netID.并注册到相应服务器上的的NetworkScene的网络物体列表中,更新如isServer为true等信息。
查找所有客户端连接,查看每个客户端连接是否需要监视这个网络物体,如果为true,那么给这个客户端上一个消息MsgType.ObjectSpawn或是MsgType.ObjectSpawnScene(这种一般是服务场景变换后自动调用),并传递上面的netID.
当客户端接受到ObjectSpawn消息,会在注册的prefab里查找,查找到后Instantiate个网络物体,当接受到ObjectSpawnScene时,会在场景里查找这个网络物体,然后都注册到ClientScene里的NetworkScene的网络物体列表中,并更新netID与服务器的一样。更新如isClent为true等信息。
我们手动spawn一个物体时,调用的是ObjectSpawn消息,客户端接到这个消息处理得到一个assetID,我们要根据prefabe实例一个新对象,只有客户端注册了相应的prefabe信息才能根据对应的assetID找到prefabe.
问题2 NetworkIdentity的netID表示什么,那个时候分配。 当服务器与客户端的netID相同,表示他们是同一物体,相应标示如SyncVar,服务器变了,对应客户端上相同的netID的网络物体,更新成服务器上的数据,Rpc,Commandg 一般也是相同的netID之间调用。
分配一般发生在服务器spawn一个网络物体时,网络物体调用OnStartServer时发生产生netID。
在客户端接受相应的ObjectSpawn消息,会把服务器上的对应物体的netID传递过来,产生新的网络物体并赋这个netID。
问题3 NetworkIdentity的sceneID是什么,在场景里已经有NetworkIdentity组件的物体是如何在客户端与服务器联系的。 当网络物体并不是spawn产生在服务器与客户端,而是在服务器与客户端场景本身就有时,我们也需要在服务器与客户端之间建立联系,这种物体会有一个sceneID来标示,这种模型一般是服务器场景变换完成后,NetworkServer调用spawnObjects会把这种网络物体与所有客户端同步,当spawn完成后过后,相应客户端会产生一个和服务端相同的netID。
问题4 服务器场景切换后,各个NetworkIdentity组件的物体如何与客户端联系。 如下顺序因为有异步操作,并不能确定,如下顺序只是一般可能的顺序。
服务器异步调用场景,发送给所有客户端开始切换场景。MsgType.Scene
客户端接受MsgType.Scene,开始切换场景。
服务器场景完成,会查找所有的网络物体,然后spawn这些网络物体,这样各个网络物体通过相同的netID联系起来。
客户端场景完成后,再次调用OnClientConnect,一般来说,不执行任何操作。
问题5 客户端为什么要网络物体的权限,它有了权限能做什么。 一般来说,当spawn某个服务器上的网络物体后,服务器有它的权限,客户端并不能更改这个网络物体,或是说更改这个网络物体相应的属性后并不能同步到服务器和别的客户端上,只是本机上能看到改变。
那么我如果需要能改变这个网络物体上的状态,并能同步到所有别的客户端上,我们需要拥有这个网络物体的权限,因为这样才能在本机上发送Command命令,才能告诉服务器我改变了状态,服务器也才能告诉所有客户端这个网络物体改变了状态。
其中本地player在创建时,当前客户端对本地player有权限。客户端上有权限的网络物体上的SyncVar改变后,也并不会能同步到服务器,服务器根本没有注册UpdateVars消息,这种还是需要客户端自己调用Command命令。
问题6 UNet常见的封装状态同步处理有那些,其中NetworkTransform与NetworkAnimator分别怎样通信,如果是客户端权限的网络物体又是怎么通信的了。 UNet常见的封装状态同步状态方法有二种。
一是通过ClientRpc与Command是封装发送消息。客户端与服务端一方调用,然后序列化相应的参数,然后到服务器与客户端反序列化参数执行。
二是网络内置的序列化与反序列化,序列化服务器的状态,然后客户端反序列化相应的值,如SyncVar通过相应的OnSerialize,OnDeserialize.这种只能同步服务器到客户端。
这二种本质都是客户端与服务器互相发送MsgType消息,对应的服务器与客户端注册相应消息处理。NetworkAnimator 服务器上的动画改变,会发消息通知所有客户端相应状态改变了,如Rpc。NetworkTransform 服务器通过OnSerialize序列化相应的值,然后客户端反序列化相应的值。
如果客户端有对应NetworkTransform与NetworkAnimator网络物体的权限。NetworkAnimator 相应客户端提交状态到服务器上,然后分发到所有客户端,相当于调用了Command,并在Command里调用了Rpc方法。NetworkTransform 相应客户端发送消息到服务器上,服务器更新相应位置,方向。然后通过反序列化到所有客户端。
所以如果客户端有授权,那么NetworkAnimator与NetworkTransform在服务器或是有授权的客户端的状态改变都能更新到所有客户端,注意这二个组件对localPlayerAuthority的处理不同,在NetworkTransform中,localPlayerAuthority为false时,客户端不能更新到所有客户端,在NetworkAnimator中,localPlayerAuthority为true时,服务器不能更新到客户端上。
其中注意SyncVar特性,就算客户端授权,客户端改变后,也不会同步到别的机器上。
所以如果我们自己设计类似的网络组件,需要考虑客户端授权的相应处理,就是差不多添加一个Command命令。
问题7 客户端授权与本地player授权有什么区别。 一般物体的权限都在服务器上,如果要对网络物体授权给客户端,一般通过SpawnWithClientAuthority实现,这样在相应客户端上的hasAuthority为true,其中相应的playerControllerID为-1。
而本地player授权localPlayerAuthority,在相应的网络物体上的Local Player Authority勾选上,在对这个网络物体的所有监视客户端上,本地player授权都是true,这种一般用于玩家,或是玩家控制位移的物体,playerControllerID大于等于0。
所以客户端授权针对是某个客户端,在这个客户端上的这个网络物体的hasAuthority为true,而本地player针对是某个网络物体,在所有客户端上的这个网络物体的localPlayerAuthority都为true.
写了一个Geo position的小demo,放在arm上试试,于是用了手边的树莓派2。准备放在Ubuntu主机上编译。
1.安装交叉编译环境: sudo apt-get install gcc-arm-linux-gnueabihf
2.编译:arm-linux-gnueabihf-gcc test.c -o test
3.编译后传输到树莓派(必须指定:/home/pi或其他目录):scp test pi@192.168.3.3:/home/pi
4.登陆到树莓派:ssh pi@192.168.3.3(密码是raspberry),查看:ls,运行:./test 了解一下树莓派2:
Broadcom BCM2836 900MHz的四核SoC,1GB内存
而在git clone raspberrypi/tools后就会发现,下面的文件夹是:arm-bcm2708hardfp-linux-gnueabi,这个2708是什么意思?
BCM2708/9 属于处理器的家族BCM2835/6 属于处理的具体型号,对应关系:
BCM2708/BCM2709BCM2835/BCM2836 BCM2709 和 BCM2836的区别详见:http://bbs.21ic.com/forum.php?mod=viewthread&tid=1180900
对于opencv,需要先在树莓派上安装opencv,再将opencv用rsync同步到本地,然后按照下帖执行交叉编译:
http://stackoverflow.com/questions/19162072/installing-raspberry-pi-cross-compiler
会遇到undefined reference to '__fdelt_chk@GLIBC_2.15'的问题(非常奇怪,因为用ldd看树莓派和ubuntu,其GLIBC都是2.19版本的),但没关系,下帖给出了解决方案:
http://stackoverflow.com/questions/40905654/cross-compile-for-arm-undefined-reference-to-fdelt-chkglibc-2-15
亲测成功
Settings > More > Mobile networks > Access Point Names
在此选项中, 我手中的平台,目前是没有任何选项显示的.
代码:
packages/apps/Settings/src/com/android/settings/ApnSettings.java
//以下代码用于构建一个列表, 从数据库中读取数据并填充到表中.
//注意下面的代码有一些过滤条件
private void fillList() {
String where = "numeric=\""
+ android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")
+ "\"";
String operatorDongle = SystemProperties.get("gsm.dongle.operator");
Log.d(TAG,"fillList:operatorDongle:"+operatorDongle);
if(operatorDongle != null) {
if(!operatorDongle.equals("llll") && false)
where = "numeric=\""+operatorDongle+"\"";
}
//从数据库获取, 下面代码会说明数据库是如何创建及始化的.
Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
"_id", "name", "apn", "type"}, null, null,
Telephony.Carriers.DEFAULT_SORT_ORDER);
PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
apnList.removeAll();
ArrayList<Preference> mmsApnList = new ArrayList<Preference>();
mSelectedKey = getSelectedApnKey();
cursor.
转载文章请标示出处:http://write.blog.csdn.net/mdeditor#!postId=53503018 前言: 作为谷歌在2013年为开发者提供的IDE环境工具Android Studio,从几次更新之后Android Studio已经成为了非常强大的IDE开发环境。谷歌也宣布Android Studio将取代Eclipse 。而使用as进行开发,已经倍受移动开发者的喜爱。废话我们这里就不再多说,不用不知道,谁用吓一跳。本文主要讲到是开发过程中经常需要用到的。如何使用as生成签名文件,配置gradle让APP自动签名以及如何生成SHA1和MD5值。
一、生成签名文件 1. 在as菜单栏中找到“bulid”这一栏,选择“Generate Signed APK” 2. 这里选择新建一个文件。
”Create new…”新建一个签名文件”Choose existing…”选择一个已经存在的签名文件 3. 填写完整的签名信息。这里密码统一填写“android”,别名写个“key”即可。其他的信息根据实际情况和需求填写,并不很重要。
Key store path : 签名文件路径Password : 签名密码Confirm : 确认密码Alias : 别名Validity ( years ) : 有限期 (年)First and Last Name : 全名Organizational Unit : 组织单位Organization : 组织City or Locality : 城市或地方State or Province : 州或省Country Code(XX) : 国家代码 4. 填写完成选择OK。来到以下这个页面 5. 猛击下一步。在Build Type选择构建类型release。选择Finish这样就生成了签名文件。
APK Destination Folder : apk目标文件夹Build Type : 构建类型release是发布版本用的签名文件debug是debug用的签名文件 二、配置gradle让APP自动签名 1 .
背景:项目需要使用京东的物流服务,中间各种交流、签合同过程不做赘述,作为程序员,凭什么总要依靠代码实现能力来判断,鬼知道自己哪天是什么样子,以后不做程序猿,也是一条好汉!可惜,口水吐完还得老老实实来搬砖。
其实,很不喜欢泛泛而谈,以下是实现授权的操作流程,仅做参考。
1.平台配置信息 (1).首先创建应用,然后进行授权12345...在新建的应用下配置回调路径,以方便测试。
(2).建议熟悉京东云宙斯的技术开发文档
(3).在回调函数设置正确的前提下,点击测试按钮,然后进行账户密码的登录授权
(4).此时很有可能报出页面失效等提示,后面提供了简单的测试代码
2.提示: (1).注意回调Url的唯一性
(2).回调Url会返回不同情况下的信息,注意GET或POST的不同。
(3).因为根据应用的状态,access_token的时效性是不同的,有24小时的、有1年的。所以,可以将获得的access_token 以及账号公用信息存储到数据库中,以备后面的使用,等到下次时效到期,重新存储就好。
3.使用JOS所提供的php-sdk (简单举例:获取京东物流订单信息--此处使用的是京东物流) (1).注意:此处我使用的是ThinkPHP框架,所以在实例化类的时候,需要使用类似如下的代码:
Vendor('Jos.jd.JdClient'); (2).开发文档中有明确指出
——正式环境授权地址:https://oauth.jd.com/oauth/authorize? (需要拼接参数,无法直接访问)
——Https调用入口地址:https://api.jd.com/routerjson 参考代码如下:
$this->server_url = "https://api.jd.com/routerjson"; 4.附录代码文件: <?php namespace M\Controller; use Common\Model\JosModel; use Think\Controller; /* 红酒奖励 控制器 */ class JosController extends Controller { private $app_key;//应用的app_key private $app_secret;//即创建应用时的Appsecret(从JOS控制台->管理应用中获取) private $expires_in;//失效时间(从当前时间算起,单位:秒) private $access_token;//JOS 所回传的access_token值 private $refresh_token;//即授权时获取的刷新令牌 private $time;//授权的时间点(UNIX时间戳,单位:毫秒) private $jd_client ; private $server_url; public function __construct() { Vendor('Jos.jd.JdClient'); $model = new JosModel(); $res = $model->getData(); $info = $res[0]; $this->app_key = $info['app_key']; $this->app_secret = $info['app_secret']; $this->expires_in = $info['expires_in']; $this->access_token = $info['access_token']; $this->refresh_token = $info['refresh_token']; $this->time = $info['time']; $this->jd_client = new \JdClient(); $this->server_url = "
问题 A 有 n 个硬币,B 有 n+1 个硬币,谁丢的正面多谁赢,问 A 不输的概率? 注意:不输二字
解法 我看了一些网上的答案,大多数写的不是很流畅,所以我尝试写一个清晰易懂的解法,相信小白也可以看懂。 首先考察另一个问题:我们分两个阶段来扔硬币,假设在第一阶段A扔了 n 枚硬币,B扔了 n 枚硬币。并且我们设 P(A>B) 是这个阶段A扔出的硬币出现正面的次数 > B扔出的硬币出现正面的次数。我们不妨设 P(A > B) = x P(A == B) = y 又由对称性有 P(A < B) = x 那么 --> 2x + y = 1 现在考察第二个阶段 B扔最后一个硬币,也就是第 n+1 个硬币,这个硬币是正面的概率是 0.5。 现在我们分类讨论,做一个总结(所有的硬币扔完): 1.P1(A不输)= x * (0.5+0.5), x表示第一阶段的x,什么意思呢?其实是这样的,如果第一阶段A > B,那么第二阶段不管是反面还是正面,A都不会输。 2.P2(A不输) = y×0.5。如果第一阶段A==B,那么第二阶段B是反面A A不输 • 假如之前A>B,则无论怎么扔,A都不会输,最多平 • 如果A==B,则B扔了正面,A才会输,这是0.5y • 如果A<B,则无论B怎么扔,A都输,所以是x 所以A输的概率是:x + 0.
GCC进行编译的大概步骤:
词法分析 --> 语法分析 --> 生成语法树 --> 高级gimple --> 低级gimple --> cfg --> ssa -->RTL -->目标代码(汇编代码)
在gcc实际的编译过程中,词法分析是在语法分析的驱动下进行的,也即是语法分析在什么时候需要下一个符号,就在词法分析识别下一个符号
函数声明的作用是,函数定义未出现时,一旦这个函数被调用,可以通过声明来确定函数信息,所以他是一种辅助信息,不参与执行,所以,不需要转换为中间代码
main函数转变为高端gimple的过程:
1 以函数为单位进行转化,并且将函数内部的所有变量以及编译器为方便生成运行时结构所创建的临时变量都提高到函数最开始的位置,为计算栈空间和使用寄存器提供依据
2 将函数执行语句集中到一起,并且其顺序与语法树种所表现的顺序一致,为配合运行时结构会增减一些语句
gimple语句:
1 ## 赋值语句用gimple_assign来表示,该节点主要内容的含义如下:
gimple_assign
subcode : 操作码
num_ops:操作数的个数,可以为2 (一元表达式),3 (二元表达式),4(三元表达式)
op[0]: 操作数0
op[1]: 操作数1
op[2]:操作数2
2 ## 函数调用语句 gimple_call gimple_assign
num_ops(unsigned int)[5]:操作数的个数,可以为2 (一元表达式),3 (二元表达式),4(三元表达式)
op[0]: 函数返回值 m.0
op[1]: 被调用函数 fun
op[3]:第一个参数 i
op[4]:第二个参数 j
3 ## 函数返回值语句 gimple_return num_ops[1]
op[0]:变量D.1380
"return D.1380;" 语法树到高端gimple的转化是以语法树的节点为单位进行遍历的
高端gimple到低端gimple主要完成数据合并,代码合并和返回语句合并,有利于最后生成更规整的后端代码
主要是将高端gimple结构中的所有gimple_bind节点拆开,所有gimple_bind变量都放到一起,并记录在local_decls中,
#include <opencv2/video/video.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <iostream> #include <cstdio> using namespace std; using namespace cv; void tracking(Mat &frame, Mat &output); bool addNewPoints(); bool acceptTrackedPoint(int i); //-----------------------------------【全局变量声明】----------------------------------------- // 描述:声明全局变量 //------------------------------------------------------------------------------------------------- string window_name = "optical flow tracking"; Mat gray; // 当前图片 Mat gray_prev; // 预测图片 vector<Point2f> points[2]; // point0为特征点的原来位置,point1为特征点的新位置 vector<Point2f> initial; // 初始化跟踪点的位置 vector<Point2f> features; // 检测的特征 int maxCount = 500; // 检测的最大特征数 double qLevel = 0.01; // 特征检测的等级 double minDist = 10.
1、HS算法
#include "cv.h" #include "highgui.h" #include <math.h> #include <stdio.h> #include "opencv2/legacy/legacy.hpp" #define CVX_GRAY50 cvScalar(100) #define CVX_WHITE cvScalar(255) int main(int argc, char** argv) { // Initialize, load two images from the file system, and // allocate the images and other structures we will need for // results. // exit if no input images IplImage *imgA = 0, *imgB = 0; //imgA = cvLoadImage("OpticalFlow0.jpg",0); //imgB = cvLoadImage("OpticalFlow1.jpg",0); //if(!(imgA)||!(imgB)){ printf("One of OpticalFlow0.jpg and/or OpticalFlow1.
process.cwd() 当前执行程序的路径(执行命令行时候的路径,不是代码路径 例如 在根目录下执行 node ./xxx/xxx/a.js 则 cwd 返回的是 根目录地址 )
__dirname: 代码存放的位置
process.execPath: 当前执行的node路径(如:/bin/node)
DEMO:
console.log(process.execPath) console.log(__dirname) console.log(process.cwd())