第6章
第3步：
1、在布局中放置JavaCameraView，用来预览
2、完善MainActivity行动器类，实现CameraBridgeViewBase.CvCameraViewListener2接口

第4步：加载分类器
1、声明数据成员
private CascadeClassifier mCascadeClassifier;   //层叠分类器

2、实现loadCascade()方法，加载分类器

3、完善MainActivity行动器，调用loadCascade()方法
在onCreate方法中调用loadCascade()
loadCascade();

第5步：加载分类器
1、声明数据成员
private Mat mGray;                     // 灰度图像矩阵
private MatOfRect mObjectDetected; //检测到的对象矩形矩阵

2、完善MainActivity行动器，调用loadCascade()方法
在onCreate方法中初始化mGray和mObjectDetected
mGray = new Mat();
mObjectDetected = new MatOfRect();

3、完善onCameraFrame()方法

第6步：训练自己的分类器
1、下载OpenCV
地址：http://opencv.org/downloads.html

2、确定要识别的物体
如：笔、打火机、篮球、足球、小轿车、手机、台灯、碗、水杯、红枣、核桃等等

3、采集要识别的物体的照片，数量越多越好。包含识别物体的照片叫做正样本。

4、裁剪正样本，剪除识别物体之外的画面

5、创建正样本描述文件（如：positive.info），内容如下：
positveImages/image1.jpg 1 90 100 45 45
positveImages/image2.jpg 2 200 300 50 50 100 30 25 25
....
表明正样本位置为positveImages子目录中
第一个正样本为image1.jpg，包含一个要识别的物体，物体左上角坐标为90，100；
物体的宽度为45，高度为45
...

6、生成正样本训练数据集，命令如下：
opencv_createsamples -info positive.info -num 550 -w 25 -h 25 -vec positive.vec

其中：
opencv_createsamples为OpenCV命令行工具
-info positive.info指定了正样本描述文件
-num 550指定了正样本的数量
-w 25 -h 25指定了正样本中物体的最小宽度和高度
-vec positive.vec指定了上下左右样本训练数据集输出文件名

7、采集和正样本数量相当的负样本照片，这些负样本照片不包含要识别的物体

==============================
第7周
第1步：App项目设置
1、创建Andriod Studio项目，名字为：LocationGooglePlayService，创建行动器模板Empty Activity
2􀌵strings.xml
3􀌵colors.xml
4设置AndroidManifest.xml文件
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
5编写布局文件
第2步：启动定位更新
1􀌵􀥍􀸁􀷄􀴝􀱮􀞧
private LocationManager mLocationManager;
2􀌵􀨫􁈿startLocationUpdate()
// 􀞐􀛖􀨧􀖖􀹅􀷛
private void startLocationUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, this);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 2000, 0, this);
}
}
3􀌵􀣁onResume()􀷜􁀩􀓾􁧣􁊠startLocationUpdate()
@Override
protected void onResume() {
super.onResume();
startLocationUpdate();
}
4􀌵􀣁onCreate()􀷜􁀩􀓾􀚡􀦤􀛸mLocationManager
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

第3步：停止定位更新
1􀌵􀨫􁈿stopLocationUpdate()􀷜􁀩
// 􀘊􀾊􀨧􀖖􀹅􀷛
private void stopLocationUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
mLocationManager.removeUpdates(this);
}
}
2􀌵􀣁onDestroy()􀷜􁀩􀓾􁧣􁊠stopLocationUpdate()
@Override
protected void onDestroy() {
super.onDestroy();
stopLocationUpdate();
}

第4步：检查两个位置提供者是否相同
/**
* 􀼄􀺱􀓷􀖖􁗝􀵉􀗀􁘏􀸎􀞈􁍘􀝶
*/
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}

第5步：检查两个位置信息前者是否更优
1􀌵􀥍􀸁􀷄􀴝􀱮􀞧
private static final int TWO_MINUTES = 1000 * 60 * 2;
2􀌵􀨫􁈿isBetterLocation()􀷜􁀩
// 􀼄􀺱􀷛􁞴􀝐􁌱􀖖􁗝􀗞􀯳􀸎􀞈􀹅􀕽
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// 􀷛􀖖􁗝􀗞􀯳􀯛􀾲􁀌􀹍􀖖􁗝􀗞􀯳􁥝􀦅
return true;
}
// 􀼄􀺱􀓷􀓻􀖖􁗝􁌱􀷛􀷯
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// 􀦇􀺎􀷛􀖖􁗝􁌱􁞴􀝐􀷸􁳵􀾲􀓤􀽺􀖖􁗝􁌱􁞴􀝐􀷸􁳵􀷛􁬦2􀚓􁰦,􀬫􀭮􀖵􁊠􀷛􀖖􁗝
if (isSignificantlyNewer) {
return true;
// 􀦇􀺎􀷛􀖖􁗝􁌱􁞴􀝐􀷸􁳵􀾲􀓤􀽺􀖖􁗝􁌱􁞴􀝐􀷸􁳵􀷯􁬦2􀚓􁰦,􀓞􀨧􀸎􁬦􀷸􁌱
} else if (isSignificantlyOlder) {
return false;
}
// 􀼄􀺱􀓷􀓻􀖖􁗝􁌱􁔜􀬶
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// 􀼄􀺱􀓷􀓻􀖖􁗝􀸎􀞈􀹶􁛔􀝶􀓞􁐿􀵉􀗀􁘏
boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider());
// 􁕟􀝳􀼄􀺱
if (isMoreAccurate) {
return true;
第6步：在用户界面显示位置信息
1􀌵􀥍􀸁􀷄􀴝􀱮􀞧
private Location mPreviousBestLocation = null;
private TextView mPosition;
private TextView mProvider;
2􀌵􀣁onCreate()􀷜􁀩􁞴􀝐􀩒UI􁥤􀢶􁌱􀭚􁊠
mPosition = (TextView) findViewById(R.id.lblLocation);
mProvider = (TextView) findViewById(R.id.provider);
2􀌵􀨫􁈿displayLocation()􀷜􁀩
/**
* 􀣁􁊠􀲁􁊴􁶎􀸔􁐏􀖖􁗝􀗞􀯳
*/
private void displayLocation() {
if (mPreviousBestLocation != null) {
double latitude = mPreviousBestLocation.getLatitude();
double longitude = mPreviousBestLocation.getLongitude();
mPosition.setText(latitude + ", " + longitude);
mProvider.setText(mPreviousBestLocation.getProvider());
} else {
mPosition.setText("􀷫􁀩􁞴􀝐􀖖􁗝􀗞􀯳");
mProvider.setText("");
}
}
第7步：实现LocationListener接口

第8步：用SQLite数据库保存运动轨迹信息
1、创建DatabaseManager类
2、声明数据成员
private DatabaseManager mDatabaseManager;
3、在onCreate()方法中初始化数据库管理器
mDatabaseManager = DatabaseManager.getInstance(this);
4、在onLocationChanged()方法中向数据库添加位置记录
第9步：用列表视图展示运动轨迹数据
1、在主布局文件中添加按钮
2、创建列表项布局文件item.xml
3、创建布局文件list.xml
4、创建TrackListActivity行动器
5、在主行动器中实现按钮事件回调
（1）声明数据成员
private Button mShowLocationRecord;
（2）在onCreate()方法中实现按钮事件回调
mShowLocationRecord = (Button) findViewById(R.id.showList);
mShowLocationRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TrackListActivity.class);
startActivity(intent);
}
});
第10步：绘制运动轨迹
你自己再创建 一个新的行动器及其对应的布局文件，将存储在数据库中的轨迹数据绘制成图形。

===================================
第8章
第0步、下载高德SDK

第1步、创建App

第2步、配置高德SDK

第3步、申请高德API Key

第4步、编辑AndroidManifest.xml文件

第5步、编辑界面布局

第6步、创建语音合成类

第7步、设置App运行的目标SDK版本

第8步、主行动器实现AMapNaviListener, AMapNaviViewListener接口

第9步、设置起点和终点

第10步、获取当前位置坐标

第11步、GPS、WGS84坐标转火星坐标(高德、腾讯地图)

第12步、利用高德Web服务API和云图API标注POI

第13步、选择目的地

第14步、添加开始导航按钮
















