美文网首页Collection第三方扩展其他
Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之

Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之

作者: zhh_happig | 来源:发表于2017-07-05 18:01 被阅读5142次

转载、引用请标明出处
http://www.jianshu.com/p/3c3d9e92739d
本文出自zhh_happig的简书博客,谢谢

Android百度地图(一):百度地图定位sdk 类方法参数、定位原理详细介绍
Android百度地图(二):百度地图sdk显示位置点、图层绘制
Android百度地图(三):百度地图画运动轨迹及图层点击事件处理
Android百度地图(五):百度地图鹰眼sdk监控进出地理围栏(区域)
Android百度地图(六):百度地图POI检索,行政区边界、公交、线路规划查询,地理编码介绍

上一篇文章介绍了地图画轨迹的基本原理和实现。不难发现,当位置处于建筑物密集区、桥梁、高架桥下,gps信号较差时,画出来的轨迹效果会比较差。即使是在空旷地带,也难免会出现gps漂移的情况而造成轨迹的偏差。这时就需要我们对位置点进行纠偏、去噪、抽稀、绑路操作。百度鹰眼sdk则提供了相应的api,本篇文章将介绍如何使用百度鹰眼sdk画出效果相对较好的轨迹。

先来看看效果图
1.百度地图(三)文章中demo取得原始位置点画出来的轨迹图:


原始位置轨迹图a

可以发现轨迹大致能反应用户所经过的路劲,效果还是不错的,说明gps信号较好,精度较高。但是除了西边的轨迹较为平滑之外,其他方位的轨迹都出现了锯齿形状,原因是gps位置有一定精度差,所以不一定会准确的定位到所行走的路劲上。如果运动范围较大(需缩小地图显示整个轨迹,轨迹将在视觉上变得平滑),而且轨迹精度要求不高,能确定用户在户外,个人觉得图a就能满足要求了

2.使用百度鹰眼sdk处理后的轨迹图:


经处理后的轨迹图

可以发现经处理的轨迹已经没有锯齿形状了,位置都落到了路劲上,这就是我们想要的效果。如果无法确定用户gps信号的优良,可能会进行网络定位,并且轨迹的精度要求很高,那么位置必须通过百度鹰眼sdk处理后再画出运动轨迹,这样才能达到图b的效果。

下面将介绍如何使用百度鹰眼sdk画出效果相对较好的轨迹,包括驾车、骑行、步行。

一 配置工程

1.申请key
2.创建鹰眼轨迹服务空间并获取 service_id
3.在Application标签中声明SERVICE组件,每个APP拥有自己独立的鹰眼追踪service

<service
     android:name="com.baidu.trace.LBSTraceService"
     android:enabled="true"
     android:exported="true"
     android:process=":remote" />

二 百度鹰眼sdk关键api介绍

1.轨迹数据处理流程图


流程图

2.初始化

//以下都是伪代码
/**
*  轨迹服务:通过serviceId对应服务端创建的鹰眼sdk服务,用于存储、访问和管理自己的终端和轨迹。注:个人最多创建10个鹰眼sdk服务。
   serviceId:轨迹服务id,这就是配置工程申请的service_id
   entityName:服务监控的对象的标识,最好是手机设备唯一标识。一个轨迹服务可监控最多100万个对象。
   isNeedObjectStorage:是否需要对象存储服务,比如在某个点存一个图层图片,显示这里有超速摄像头,
                        获取轨迹的时候,也可以获取这个图层图片显示在轨迹的相应位置上.
                        这里默认为:一般为false,关闭对象存储服务。
                        注:鹰眼 Android SDK v3.0以上版本支持随轨迹上传图像等对象数据,
                        若需使用此功能,该参数需设为 true,且需导入bos-android-sdk-1.0.2.jar。
*/
Trace mTrace = new Trace(serviceId, entityName,isNeedObjectStorage);

/**
*  轨迹客户端LBSTraceClient,主要功能:
   (1)内部具有定位功能,能采集定位位置点,百度定位sdk不清楚的可以阅读篇头百度文章(一)
   (2)将采集数据打包发给服务端
   (3)请求服务端,查询经过轨迹、位置、围栏、图像等信息
*/
LBSTraceClient mClient = new LBSTraceClient(mContext);

3.定位当前位置显示在地图上

//定位请求参数类
LocRequest locRequest = new LocRequest(serviceId);
//时时定位设备当前位置,定位信息不会存储在轨迹服务端,即不会形成轨迹信息,只用于在MapView显示当前位置
mClient.queryRealTimeLoc(locRequest, entityListener);//这里只会一次定位,多次定位使Handler.postDelayed(Runnable, interval)实现;

//Entity监听器(用于接收实时定位回调)
private OnEntityListener entityListener = new OnEntityListener() {
     @Override
     public void onReceiveLocation(TraceLocation location) {
          //将回调的当前位置location显示在地图MapView上,地图显示位置不清楚的可以篇头阅读百度文章(二)
          //这里位置点的返回间隔时间为Handler.postDelayed的延时时间
     }   
};

/**
* 当轨迹服务开启,且采集数据开启之后,显示在地图上的位置点可以用服务端纠偏后的最新点,
  因为通过mClient.queryRealTimeLoc获取的点可能不精确,出现漂移等情况。
*/
//查询服务端纠偏后的最新轨迹点请求参数类
LatestPointRequest request = new LatestPointRequest(getTag(), serviceId, entityName);
ProcessOption processOption = new ProcessOption();//纠偏选项
processOption.setRadiusThreshold(50);//设置精度过滤,0为不需要;精度大于50米的位置点过滤掉
processOption.setTransportMode(TransportMode.walking);
processOption.setNeedDenoise(true);//去噪处理
processOption.setNeedMapMatch(true);//绑路处理
request.setProcessOption(processOption);//设置参数
mClient.queryLatestPoint(request, trackListener);//请求纠偏后的最新点

//轨迹监听器(用于接收纠偏后实时位置回调)
private OnTrackListener trackListener = new OnTrackListener() {
     @Override
     public void onLatestPointCallback(LatestPointResponse response) {
          //将纠偏后实时位置显示在地图MapView上
          //这里位置点的返回间隔时间为数据打包上传的频率;数据发送到服务端,才会更新最新的纠偏位置
     }
};

4.开启服务,开始采集数据

//设置定位模式
mClient.setLocationMode(LocationMode.High_Accuracy);

/**
* 设置采集频率:这里的采集频率指的是轨迹数据的采集频率,和上面显示当前位置的定位频率要区分开
  最小为2秒,最大为5分钟,否则设置不成功,默认值为5s
* 打包上传频率:mClient每隔packInterval时间会自动打包上传
* 打包时间间隔必须为采集时间间隔的整数倍,且最大不能超过5分钟,否则设置不成功,默认为30s
*/
mClient.setInterval(gatherInterval, packInterval);

/**
* 开启轨迹服务
*/
mClient.startTrace(mTrace, traceListener);
//开启位置点采集
mClient.startGather(traceListener);
startTime = System.currentTimeMillis()/1000;//记录开始采集时间

//轨迹服务监听器
private OnTraceListener traceListener = new OnTraceListener() {

    /**
    * 绑定com.baidu.trace.LBSTraceService服务回调接口
    * @param errorNo  状态码,0:成功,1:失败
    * @param message 消息
    */
    @Override
    public void onBindServiceCallback(int errorNo, String message) {

    }

    /**
    * 开启服务回调接口
    * @param errorNo 状态码
    * 0:成功,10000:请求发送失败,10001:服务开启失败,10002:参数错误,10003:网络连接失败
      10004:网络未开启,10005:服务正在开启,10006:服务已开启
    * @param message 消息
    */
    @Override
    public void onStartTraceCallback(int errorNo, String message) {

    }

     /**
     * 停止服务回调接口
     * @param errorNo 状态码
     * 0:成功,11000:请求发送失败,11001:服务停止失败,11002:服务未开启,11003:服务正在停止
     * @param message 消息
     */
     @Override
     public void onStopTraceCallback(int errorNo, String message) {

     }

     /**
     * 开启采集回调接口
     * @param errorNo 状态码
     * 0:成功,12000:请求发送失败,12001:采集开启失败,12002:服务未开启
     * @param message 消息             
     */
     @Override
     public void onStartGatherCallback(int errorNo, String message) {

     }

     /**
     * 停止采集回调接口
     * @param errorNo 状态码
     * 0:成功,13000:请求发送失败,13001:采集停止失败,13002:服务未开启
     * @param message 消息              
     */
     @Override
     public void onStopGatherCallback(int errorNo, String message) {

     }

     /**
     * 推送消息回调接口
     * @param messageType 状态码
     * 0x01:配置下发,0x02:语音消息,0x03:服务端围栏报警消息,0x04:本地围栏报警消息    
     */
     @Override
     public void onPushCallback(byte messageType, PushMessage pushMessage) {
        //这个回调其实是比较重要的,本篇主要讲的是画轨迹,所以就不详细讲了
        /**
        * 那么这里能实现什么功能呢,我想到的两个例子
        * 1.到达目的地提示用户,在目的地画个圈,进入提醒
           实现:CreateFenceRequest创建围栏:圆形围栏、多边形围栏、线型围栏、行政区围栏,一旦进出则推送报警,
           pushMessage.getFenceAlarmPushInfo().getMonitoredAction()可以知道进或出,
           MonitoredAction.enter:进围栏,MonitoredAction.exit:出围栏
        * 2.用户出一定区域发出提醒,在当前位置地画个圈,出去了则提醒
        *  比如孩子在小区玩,拿着手机和小伙伴在树底下玩王者农药,我们为了孩子的安全,
           只允许他在小区范围内活动,一旦离开了小区的范围就给大人发个短信什么的,哈哈
        */
     }
};  

5.停止服务,停止采集数据

mClient.stopGather(traceListener);
endTime = System.currentTimeMillis()/1000;//记录停止采集时间
mClient.stopTrace(mTrace, traceListener);

6.请求服务端处理后的位置数据

/**
 * 历史轨迹请求类
 */
HistoryTrackRequest historyTrackRequest = new HistoryTrackRequest();
ProcessOption processOption = new ProcessOption();//纠偏选项
processOption.setRadiusThreshold(50);//精度过滤
processOption.setTransportMode(TransportMode.walking);//交通方式,默认为驾车
processOption.setNeedDenoise(true);//去噪处理,默认为false,不处理
processOption.setNeedVacuate(true);//设置抽稀,仅在查询历史轨迹时有效,默认需要false
processOption.setNeedMapMatch(true);//绑路处理,将点移到路径上,默认不需要false
historyTrackRequest.setProcessOption(processOption);

/**
* 设置里程补偿方式,当轨迹中断5分钟以上,会被认为是一段中断轨迹,默认不补充
* 比如某些原因造成两点之间的距离过大,相距100米,那么在这两点之间的轨迹如何补偿
  SupplementMode.driving:补偿轨迹为两点之间最短驾车路线
  SupplementMode.riding:补偿轨迹为两点之间最短骑车路线
  SupplementMode.walking:补偿轨迹为两点之间最短步行路线
  SupplementMode.straight:补偿轨迹为两点之间直线
*/
historyTrackRequest.setSupplementMode(SupplementMode.no_supplement);
historyTrackRequest.setSortType(SortType.asc);//设置返回结果的排序规则,默认升序排序;升序:集合中index=0代表起始点;降序:结合中index=0代表终点。
historyTrackRequest.setCoordTypeOutput(CoordType.bd09ll);//设置返回结果的坐标类型,默认为百度经纬度

/**
*设置是否返回纠偏后轨迹,默认不纠偏
 true:打开轨迹纠偏,返回纠偏后轨迹;
 false:关闭轨迹纠偏,返回原始轨迹。
 打开纠偏时,请求时间段内轨迹点数量不能超过2万,否则将返回错误。
*/
historyTrackRequest.setProcessed(true);

//请求历史轨迹
((BaseRequest)historyTrackRequest).setTag(tag);//设置请求标识,用于唯一标记本次请求,在响应结果中会返回该标识
historyTrackRequest.setServiceId(serviceId);//设置轨迹服务id,Trace中的id
historyTrackRequest.setEntityName(entityName);//Trace中的entityName

/**
* 设置startTime和endTime,会请求这段时间内的轨迹数据;
* 这里查询采集开始到采集结束之间的轨迹数据
*/
historyTrackRequest.setStartTime(startTime);
historyTrackRequest.setEndTime(endTime);

mClient.queryHistoryTrack(historyTrackRequest, mTrackListener);//发起请求,设置回调监听

7.历史轨迹数据回调
注:当我们记录采集的起始时间,然后在查询这段时间内的点,画在地图上,可以实现用户运动结束后,一次性画出整个运动轨迹的功能

//伪代码
 private List<LatLng> trackPoints = new ArrayList<>();//轨迹点集合

/**
* 轨迹监听器(用于接收历史轨迹回调)
*/
private OnTrackListener mTrackListener = new OnTrackListener() {
            
     @Override
     public void onHistoryTrackCallback(HistoryTrackResponse response) {
        //如果觉得轨迹点可能过多,可以多次分页查询,详细代码参见源码
        List<TrackPoint> points = response.getTrackPoints();//获取轨迹点
        for (TrackPoint trackPoint : points) {
               //将轨迹点转化为地图画图层的LatLng类
               trackPoints.add(MapUtil.convertTrace2Map(trackPoint.getLocation()));
        }
        //MapUtil封装了百度地图MapView和BaidumMap中的一些api
        mapUtil.drawHistoryTrack(trackPoints, sortType);//将轨迹点画在地图上,对百度地图画图层不清楚的可以阅读偏头百度地图(三)文章
     }

};

8.里程计算

DistanceRequest distanceRequest = new DistanceRequest(tag, serviceId, entityName);
distanceRequest.setStartTime(startTime);// 设置开始时间
distanceRequest.setEndTime(endTime);// 设置结束时间
distanceRequest.setProcessed(true);// 纠偏
ProcessOption processOption = new ProcessOption();// 创建纠偏选项实例
processOption.setNeedDenoise(true);// 去噪
processOption.setNeedMapMatch(true);// 绑路
processOption.setTransportMode(TransportMode.walking);// 交通方式为步行
distanceRequest.setProcessOption(processOption);// 设置纠偏选项
distanceRequest.setSupplementMode(SupplementMode.no_supplement);// 里程填充方式为无
mTraceClient.queryDistance(distanceRequest, mTrackListener);// 查询里程

// 初始化轨迹监听器
OnTrackListener mTrackListener = new OnTrackListener() {
    // 里程回调
    @Override
    public void onDistanceCallback(DistanceResponse response) {
         double distance = response.getDistance()//里程,单位:米
         double speed = distance/(endTime-startTime);//速度:m/s
    }
};

三 动态时时画运动轨迹

//伪代码
/**
* 使用LatestPointRequest实现:查询服务端纠偏后的最新的点,在3中已经介绍了
* onLatestPointCallback此回调方法不仅可以画出当前的位置点,还可以将每一个最新纠偏后的点加入到位置点集合中,
  每返回一个点,就刷新一次轨迹图,这样就能动态画出轨迹了。
*/

//接收纠偏后最新位置回调
private OnTrackListener trackListener = new OnTrackListener() {
     @Override
     public void onLatestPointCallback(LatestPointResponse response) {
          
         if(first){//返回的第一个点是上一次采集的最后一个点,可能和当前位置距离很大,应该弃用
             first = false;
             return;
         }
         //位置点的返回间隔时间为数据打包上传的频率 
         LatestPoint point = response.getLatestPoint();
         LatLng currentLatLng = mapUtil.convertTrace2Map(point.getLocation());
         trackPoints.add(currentLatLng);
         mapUtil.drawHistoryTrack(trackPoints,false,mCurrentDirection);//显示当前位置,并时时动态的画出运动轨迹
     }
};

动态轨迹效果图


效果图

四 查询被监控者轨迹

现实也很简单,被监控者手机开始采集数据

//开启轨迹服务,注意被监控者与监控者中的serviceId必须一致,mTrace的entityname为被监控手机的deviceId
mClient.startTrace(mTrace, traceListener);
//开启位置点采集
mClient.startGather(traceListener);

监控者查询数据

//查询数据,historyTrackRequest的entityname为被监控手机的deviceId
mClient.queryHistoryTrack(historyTrackRequest, mTrackListener);

好啦,到此,运动轨迹的纠偏、绑路等处理就讲完了,详细实现请参照源码。

如果各位看官觉得文章不错,别忘了点个喜欢。
源码下载地址 https://github.com/zhuhaoHappig/BaiduMapTrace

以上文章内容,是本人工作中的总结,供大家参考,有误的地方还请指正。

相关文章

网友评论

  • 微微心凉L:大佬 ,我输入我的appid 运行你项目 还是key验证出错,我这个要怎么搞
  • 2947019608cb:为什么进入地图只能定位默认的北京市呢?
  • c9c0a9a079ec:问问怎么将实时运动的路程显示出来呢
  • 2a6dd70a8068:你好,我运行你的github源码到手机上,一直显示在搜索gps,动态实时绘画轨迹那个Demo,实现不了,一直在搜索信号
    zhh_happig:@LeeOoOoO 显示的是“gps一直搜索”,还是“gps信号弱”
    2a6dd70a8068:@zhh_happig 这些都试过了,还是一直在搜索,无论走到哪里
    zhh_happig:@LeeOoOoO gps搜索,说明在搜索gps信号,去室外空旷地带试试,或重启手机
  • 陈科比大宝贝儿:大佬,百度鹰眼支持动画播放走过的轨迹吗?
  • 3866b3f2e166:大神,想问一下,历史轨迹查询选项设置那一块,除了纠偏,去噪,抽稀等,还有一项精度过滤,这一项筛选的是什么?麻烦讲解以下,谢谢!
    3866b3f2e166:@zhh_happig 了解了,谢谢!
    zhh_happig: @月影唯殇 就是你获取的每个位置点都有自己的精度,也就是误差半径,半径越大,这个位置点越不精确,越不可信,精度过滤就是把那些大于你设置的精度值的点去掉
  • 5837da444429:大神,为什么我开启服务并开启采集,为啥没有纠偏数据返回呢?
    zhh_happig: @zgq_aed0 百度服务管理后台能看到你的轨迹吗,查询要设定起始时间的,你看看查询返回的状态码是多少
    5837da444429:没配置错吧,百度服务管理后台可以看见我的设备,而且开启服务和采集,回调都返回成功。然后查数据就没有返回。大神帮帮忙
    zhh_happig: @zgq_aed0 配置都没问题吗,开启采集等待一会,大概30秒再看看
  • 5837da444429:用了demo报Fatal signal 11 (SIGSEGV), code 1, fault addr 0x8dd00000 in tid 6664 (Thread)错误
    5837da444429:@zhh_happig TracingActivity这个。。能加一下QQ么,方便联系。1085751441.多谢
    zhh_happig:哪个activity出现的?
  • 183a50918e8a:ios 百度鹰眼要不要合成真机对应CPU架构的SDK呢?
    5c6e2dc0a022:需要的,他给的framework是 真机和模拟器合成的,需要使用lipo命令导出 ,arm64、armv7、armv7s的处理器
    zhh_happig:@梦幻紫藤 ios我没研究过:joy: ,你可以去百度鹰眼论坛咨询http://bbs.lbsyun.baidu.com/forum.php?mod=forumdisplay&fid=26,有百度工程师解答
  • 文文要坚强坚持坚硬:我设置了去躁和绑定路,但是依然很乱的,为啥楼主这个是这么整齐的路线图?
    zhh_happig:@文文要坚强坚持坚硬 我看到了,确实对角线很多,你下我的demo跑一下试试
    文文要坚强坚持坚硬:@zhh_happig 是我啊。。不沿着道路。。各种对角线。。。
    zhh_happig:你的图是锯齿状多,还是说不沿着道路?在百度地图社区发帖询问的是你吗?
  • bf86c828bef1:大神,我现在在写 //轨迹监听器(用于接收纠偏后实时位置回调) 的onLatestPointCallback方法
    这是方法里面部分代码
    LatestPoint point = response.getLatestPoint();
    Log.i("自定义","运行到这1");
    LatLng location = point.getLocation();
    Log.i("自定义","运行到这2");
    double latitude = location.getLatitude();
    double longitude = location.getLongitude();
    com.baidu.mapapi.model.LatLng latLng = new com.baidu.mapapi.model.LatLng(latitude,longitude);


    现在我运行时报错,日志显示的是自定义: 运行到这1
    也就是 LatLng location = point.getLocation(); 没执行了


    报的错误是E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.administrator.myone, PID: 15254
    java.lang.NullPointerException: Attempt to invoke virtual method 'com.baidu.trace.model.LatLng com.baidu.trace.api.track.LatestPoint.getLocation()' on a null object reference
    at com.example.administrator.myone.MapActivity$2.onLatestPointCallback(MapActivity.java:156)


    156行就是 LatLng location = point.getLocation(); 这一行


    请问这个是什么情况,我自己猜测是没有获取到respone 但我在方法里加了个
    if(response == null){
    Log.i("自定义","空的response");
    }
    他确没有输出,说明应该不是没有获取到respone吧


    而且我看大神的demo里,你获取到的point.getLocation();是一个TraceLocation对象
    我的怎么是一个LatLng对象
    zhh_happig:@一个很OK的男人_7edf response不为空不代表point就不为空,你判断加个判断吧,不会每次得到的point都为空吧?:sweat:
    bf86c828bef1:@zhh_happig 是的,LatLng location = point.getLocation()这句中point是null,这是怎么回事呢,明明response 不是null
    zhh_happig:你看看LatLng location = point.getLocation()这句中point这个是不是null,在代码里面判断一下吧,然后注意point.getLocation()得到的是com.baidu.trace.model.LatLng类,而地图画轨迹用到的是这个类com.baidu.mapapi.model.LatLng类,注意一下。
  • bf86c828bef1:楼主,能不能帮我整理下思路。
    1.这个鹰眼sdk支持 中文地址转成经纬度吗,因为我要根据用户输入的地点,与数据库中已有的配送员的地点(经纬度)进行对比,然后找出合适的人配送
    2.如何将配送员的路径显示在用户手机上。
    3.如果我用这个鹰眼sdk的话,还需要接入百度地图本身的sdk吗
    4.新手,麻烦说的通俗详细下,万分感谢
    zhh_happig:问题3:用这个鹰眼sdk就不要再接入百度定位sdk了,因为鹰眼sdk也能获取位置,但是百度地图sdk还是要的,申请秘钥时,那些没用上的功能就不用启用了,比如全景,导航,ip定位等
    zhh_happig:@一个很OK的男人_7edf
    问题1:看看这个官方的文档http://lbsyun.baidu.com/index.php?title=androidsdk/guide/retrieval,找到 检索功能,下面的地址编码。里面有你想要的将地址转换为坐标。这个正式我下片文章要写的,现在还在准备中。
    bf86c828bef1:还有,如果要实现这些功能在申请密钥时需要启用哪些服务
  • 444106d75a56:谢谢分享,有个问题请教一下:我的华为手机每次定位都在大西洋,我同事的vivo手机就没问题,请问你有遇到过吗?
    444106d75a56:还有就是,我坐着没动,它自己在绘制轨迹,点飘来飘去的
    444106d75a56:@zhh_happig 感谢您的回复,这个问题解决了,是忘了开权限。还有个问题,地图一直闪烁,有遇到过吗?
    zhh_happig: @CodeisPoisonous 你是在室外gps定位,还是室内的网络定位呢
  • 笔头:正在开发相关的业务,先给楼主点个赞
  • 773e36d35f14:哎呦,上个月开发完了,你该早点发出来呀,踩了不少坑。
    zhh_happig:@谁铃浪子心_ea9f 可以下载源码,文章末尾有连接
    ed425ae78c05:可以给个Demo研究一下吗
    zhh_happig:@远房表舅家的二叔家的七舅老爷 :smile:
  • 45a75e771244:谢谢分享,正好用上,赞

本文标题:Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之

本文链接:https://www.haomeiwen.com/subject/kmczcxtx.html