Ionic-wechat项目边开发边学(二):目录结构,header标签与路由 - Frogmarch - 博客园

mikel阅读(1308)

来源: Ionic-wechat项目边开发边学(二):目录结构,header标签与路由 – Frogmarch – 博客园

之前一直跟Linux驱动打交道,上层应用几乎为零,业余时间也不是很多,所以博客也不会写的非常详细,大家有问题尽管评论哦, 我有空会及时回复!

摘要

上一篇文章主要介绍了ionic的开发环境配置, 以及如何创建运行一个app。这篇文章主要搭建wechat的外壳,介绍一个ionic项目的标准目录结构,header标签的使用,以及页面之间的切换。先看完成的效果

强烈建议,做ionic之前把angularJS入门过一遍, 还有ui-router, 至少要了解个大概, 不然真做不下去

项目的目录结构

当我们创建一个blank项目的时候,目录结构是下面这个样子:

├── bower.json
├── config.xml
├── gulpfile.js
├── hooks
├── ionic.project
├── package.json
├── plugins
├── README.md
├── scss
└── www

那我们的工作目录,就主要集中在www目录中,相信大家看到cssjsindex.html都比较熟悉,这里不准备详细介绍目录结构,只说一下一个AngularJs项目的常用的目录结构吧。

大部分情况下,我们会把一个应用的控制器,指令,路由,服务分别放在独立文件中,然后在app.js中注入.

所以创建一个blank项目后,先在www/js目录下创建四个文件controllers.js,directives.js,routes.js,services.js,并在www/js/app.js中引用进来

<script src="js/controllers.js"></script>
<script src="js/routes.js"></script>
<script src="js/services.js"></script>
<script src="js/directives.js"></script>

最后我们还需要在www下创建一个目录templates,用来存放各个模板,模板简单点说,就是把我们看到的界面拆开,分成一小个一小个的view,方便我们管理和复用

所以最后我们项目的目录结构看起来应该是这样的:

├── css
│   └── style.css
├── img
│   └── ionic.png
├── index.html
├── js
│   ├── app.js
│   ├── controllers.js
│   ├── directives.js
│   ├── routes.js
│   └── services.js
├── lib
│   └── ionic
└── templates

页面头部

其实创建ionic的应用,界面部分有两种模式,可以使用纯CSS创建,也可以使用AnjularJS指令模式创建.

当然还是推荐大家使用指令模式,AngularJS的优点和学习路线可以参考这篇文章

ionic中创建一个头部非常简单

<ion-header-bar align-title="center" class="bar-dark">
  <h1 class="title">Title!</h1>
</ion-header-bar>

AngularJS一个神奇的地方就是,可以在html中使用自己定义的标签,这里的ion-header-bar就是一个官方定义好的指令,表示这是一个header,同时指令也可以有自己的属性,bar-dark表示一个黑色的header,另外官方还有其它八种颜色,可以点这里

可以看到这已经跟微信的header很像了,还需要两个图标,我们可以放两个button图标

<ion-header-bar align-title="left" class="bar-dark">
        <div class="h1 title">微信(16)</div>
        <div class="buttons">
            <button class="button no-animation button-icon icon ion-android-search">
            </button>
            <button class="button no-animation button-icon icon ion-android-add">
            </button>
        </div>
</ion-header-bar>

这里的ion-Android-searchion-Android-add其实是两个icon font,官方还有更多的图标,点这里

到这里header就有模有样了,看到这,相信大家已经跃跃欲试了,其它组件的使用大同小异,把官方docs过一遍,很快就会了

不过我得吐槽一句,官方的文档写的太粗糙了,像这里的<div class="button">官方就没有介绍,大家可以去掉看看,界面变成啥样了- -!!

模板和路由

首先我们先在templates目录下创建三个文件tabs.htmltab-message.htmltab-frends.html

//tabs.html
<ion-tabs class="tabs-icon-top tabs-color-active-balanced">
    <ion-tab title="微信" icon-on="ion-ios-chatbubble" icon-off="ion-ios-chatbubble-outline" ui-sref="tab.message">
        <ion-nav-view animation="slide-left-right" name="tab-message"></ion-nav-view>
    </ion-tab>
    <ion-tab title="通讯录" icon-on="ion-ios-people" icon-off="ion-ios-people-outline" ui-sref="tab.friends">
        <ion-nav-view animation="slide-left-right" name="tab-friends"></ion-nav-view>
    </ion-tab>
    <ion-tab title="发现" icon-on="ion-ios-paperplane" icon-off="ion-ios-paperplane-outline" ui-sref="tab.find">
        <ion-nav-view animation="slide-left-right" name="tab-find"></ion-nav-view>
    </ion-tab>
    <ion-tab title="我" icon-off="ion-ios-person-outline" icon-on="ion-ios-person" href="#/tab/setting">
        <ion-nav-view animation="slide-left-right" name="tab-setting"></ion-nav-view>
    </ion-tab>
</ion-tabs>

//tab-message.html
<ion-view>
    <ion-content>
        <h1>消息页面</h1>
    </ion-content>
</ion-view>

//tab-friends.html
<ion-view>
    <ion-content>
        <h1>通讯录页面</h1>
    </ion-content>
</ion-view>

这三个模板一看就知道,一个是底部导航tabs,一个是消息界面,一个是通讯录界面,那他们应该如何放到界面中?如何实现跳转?

我觉得有必要先理一下他们三者的关系,tabs模板应该是直接放置在index.html中的,消息界面和通讯录应该放置在tabs模板中的。

所以剩下的就是通过某种方式,按他们的关系,把他们安置好,并能实现页面切换。主角来了ui-routerui-router是一个AngularJS的路由框架,它通过状态机制来组织你项目的各个部分,比自带$route service好用多了,更多介绍请点这里

下面来看看,ionic中ui-router是如何使用的

首先模板是通过ion-nav-view来嵌入到界面中的, 也就是说有这个标签的地方,ui-router就会根据状态把对应的模板放置到这个标签中. 可以看到index.htmltabs.html中都有这个标签. 到时候对应的模板就要放置到这些位置.

模板位置安排好了, 再来看看如何放置和跳转的. 先在js/routes.js文件中添加这些代码:

//这里声明了一个模块, 名字叫wechat.routes, 等会要在app.js中注入这个模块, 才会生效
angular.module('wechat.routes', [])
.config(function($stateProvider, $urlRouterProvider) {
    //默认状态是tab.message
    $urlRouterProvider.otherwise("/tab/message");
    $stateProvider
        //如果是tab状态被激活, 加载tabs.html模板, 注意这里的abstract: true, 表示tab只有在子状态显示的时候, 它才显示, 它本身是无法主动被激活的
        .state("tab", {
            url: "/tab",
            abstract: true,
            templateUrl: "templates/tabs.html",
        })
        //tab.message状态被激活,会显示tab-message.html模板, tab.message状态是在tabs.html中的ui-sref中设置的. 同时注意views中的tab-message名字, 这个也需要跟tabs.html中的ion-nav-view中的name一致哦
        .state('tab.message', {
            url: '/message',
            views: {
                'tab-message': {
                    templateUrl: 'templates/tab-message.html',
                }
            }
        })
        .state('tab.friends', {
            url: '/friends',
            views: {
                'tab-friends': {
                    templateUrl: 'templates/tab-friends.html',
                }
            }
        })

还有tab-friends.htmltab-setting.html大家自己加一下. 最后别忘了在app.js中注入这个模块:

angular.module('wechat', ['ionic', 'wechat.routes'])
//这个地方的config不能少哦, 不然安卓平台的tabs会跑到顶部的
.config(['$ionicConfigProvider', function($ionicConfigProvider) {

    $ionicConfigProvider.tabs.position('bottom'); // other values: top

}])

ok, 赶紧运行ionic serve在电脑上欣赏一下吧~

最后

其实这个功能看起来很简单, 但还有很多细节我没说, 比如如何添加滑动切换? 比如安装到手机, tabs跟浏览器上效果不一样, 有个黑边…大家可以尝试改改, 有问题, 尽管评论, 我有时间会及时回答的~

Git项目代码

Ionic-wechat项目边开发边学(一):环境搭建和创建一个项目 - Frogmarch - 博客园

mikel阅读(1111)

来源: Ionic-wechat项目边开发边学(一):环境搭建和创建一个项目 – Frogmarch – 博客园

之前学AngularJS,教程过了一遍觉得很简单,但真正写几个Demo就错误百出,一个小小的功能要折腾很久。所以这次学Ionic,准备以开发一个项目为切入点去学,那么问题来了,开发什么项目呢?

纠结了10秒,还是模仿微信吧^_^,大体列一下要实现的功能:

  1. 界面要像,呵呵
  2. 聊天消息列表,查看对话内容,来了消息推送提醒
  3. 通讯录展示,好友搜索,右侧字母快速索引
  4. 朋友圈展示,发朋友圈消息
  5. 扫一扫, 摇一摇功能
  6. 设置功能,设置消息提醒方式,设置聊天背景,关于等

之前根本没接触过上层应用这块,这些功能有点够呛,希望能坚持下去,把这个项目完成好,把博客写好,与各位共勉,加油!

摘要

本篇文章主要介绍一下Ionic,开发环境的配置,以及创建并运行一个官方的example
项目地址

Ionic介绍

Ionic是一个基于Cordova漂亮,开源的前端SDK,用web技术就可以开发跨平台移动app,它支持在线拖拽生成界面(ionic creator),并可以免费下载生成的代码。更多介绍
开始之前我觉得最好具备以下几点知识:

  1. HTML5,CSS3和JavaScript三剑客
  2. AngularJS
  3. NodeJS
  4. 响应式布局
  5. Linux(我是ubuntu14.04)

环境搭建

安装NodeJS

  1. 直接在官网下载二进制包,并解压
    $ tar -xvf node-v4.0.0-linux-x64.tar.gz
  2. 增加软连接
    $ sudo ln -s ./node-v4.0.0-linux-x64/bin/node /usr/bin/node
    $ sudo ln -s ./node-v4.0.0-linux-x64/bin/npm /usr/bin/npm
  3. 测试
    $ npm -v
    $ node -v

安装Android开发环境

  1. 安装JDK
  2. 安装Android SDK,当然要FQ啦~
    $ tar -xvf Android-sdk_r24.4.1-linux.tgz
    $ cd android-sdk-linux && tools && ./android
    下载API22和默认勾选的项目(下载这个貌似不要FQ,我关掉这个能全速下载)
  3. 添加ANDROID_HOME和adb路径, 打开~/.profile,添加两行:
    export ANDROID_HOME=~/usr/android-sdk-linux
    export PATH=$PATH:${ANDROID_HOME}/platform-tools
  4. 创建一个AVD(建议使用Genymotion,原装的太太太卡),运行./android-sdk-linux/tools/monitor
  5. 安装Ant
  6. 给大家看一下我最后的~/.profile文件

安装cordova和Ionic

安装Cordova

$ npm install -g cordova

安装Ionic

$ sudo npm install -g ionic

创建一个项目

$ ionic start myApp tabs
创建了一个myApp项目,使用了tabs模板,另外还有两个模板blanksidemenu

添加平台并编译(要添加ios,直接add ios)

$ cd myApp
$ ionic platform add android
$ ionic build android

在本地浏览器测试

$ ionic serve
打开http://localhost:8100/

在手机测试,连上adb(或者运行Genymotion),再运行下面命令

$ ionic run android

在模拟器测试(不建议使用,AVD太太太卡)

$ ionic emulate android

ok,这篇就写到这里,下一篇项目正式开始

Ionic-wechat项目边开发边学(三):自定义样式,指令,服务 - Frogmarch - 博客园

mikel阅读(1209)

来源: Ionic-wechat项目边开发边学(三):自定义样式,指令,服务 – Frogmarch – 博客园

摘要

上一篇文章主要介绍了一个ionic项目的标准目录结构,header标签的使用,以及页面之间的切换。这篇文章实现的功能有: 消息数据的获取, 消息列表的展示, 消息标为已读/未读, 主要涉及的到的知识点有:

  1. ion-list的使用
  2. ion-popup的使用
  3. 通过sass自定义样式
  4. localStorage的使用
  5. 自定义指令和服务

先看效果图:

功能分析

在开始之前, 最好先思考一下消息页面的主要功能, 和大概如何实现. 这样后面写程序才不会乱. 我大体列了一下

消息的数据暂时用localStorage存储, 但这不是好的方式, localStorage可能会被文件清理掉, 后面会换SQLite存储

页面布局

首先在’tab-message.html’中添加聊天消息的布局

<ion-view>
    <ion-content on-swipe-left="onSwipeLeft()">
        <!--这里的rj-close-back-drop是自定义指令, 后面会讲是干嘛的-->
        <ion-list rj-close-back-drop>
          <ion-item class="item-avatar" on-hold="popupMessageOpthins($index)" rj-hold-active ng-repeat="message in messages">
              <img ng-src="{{message.pic}}">
              <!--这个就是来了新消息, 头像上的小红数字-->
              <span class="rj-sm-red-icon" ng-show="message.showHints"><p ng-bind="message.noReadMessages"></p></span>
              <h2 ng-bind="message.name"></h2>
              <p class="rj-list-p" ng-bind="message.lastMessage.content"></p>
              <span class="rj-push-right" ng-bind="message.lastMessage.time"></span>
          </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

大家在试这个的时候, 由于’messages’还未定义, 先不绑定, 用实际的值代替,像这样

<img src="img/ben.png">
<span class="rj-sm-red-icon"><p>1</p></span>
<h2>小王</h2>
<p class="rj-list-p">你在干什么?</p>
<span class="rj-push-right">12:30</span>

这样就能看到效果了

自定义样式

可以看到上图有点丑, 需要我们自己修改样式, 可以自己添加css文件link进来, 但官方推荐使用sass的方式修改, 关于sass的语法, 可以看这个, 看完就差不多可以了.

首先在项目目录下,运行命令

$ionic setup sass
$ionic serve

运行以后, 就会对scss/ionic.app.scss文件监控, 有修改, 会自动编译该文件, 输出到css/ionic.app.css

所以你每次修改保存scss文件后, 浏览器会看到实时的效果, 非常方便.

打开scss/ionic.app.scss文件, 如下

/*
To customize the look and feel of Ionic, you can override the variables
in ionic's _variables.scss file.

For example, you might change some of the default colors:

$light:                           #fff !default;
$stable:                          #f8f8f8 !default;
$positive:                        #387ef5 !default;
$calm:                            #11c1f3 !default;
$balanced:                        #33cd5f !default;
$energized:                       #ffc900 !default;
$assertive:                       #ef473a !default;
$royal:                           #886aea !default;
$dark:                            #444 !default;
*/

// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/fonts" !default;

可以看到官方预定义的颜色几个颜色, 如果要修改预定义的颜色, 直接修改这里就可以了.

我们自己的样式, 直接在后面添加. 我们在后面添加

$item-avatar-border-radius: 0;

可以发现头像变成方的了, 那怎么知道修改这个变量呢?

打开www/lib/ionic/scss/目录, 可以看到很多scss文件

├── _action-sheet.scss
├── _animations.scss
├── _backdrop.scss
├── _badge.scss
├── _bar.scss
├── _button-bar.scss
├── _button.scss
├── _checkbox.scss
├── _form.scss
├── _grid.scss
├── ionicons
├── ionic.scss
├── _items.scss
├── _list.scss
├── _loading.scss
├── _menu.scss
├── _mixins.scss
├── _modal.scss
...

这些都是官方的样式文件, 找到items.scss文件, 这个就是ion-item相关的样式, 再搜border-radius很快就能找到啦

具体的细节我就不说啦, 其它的修改都类似, 可以参考我的代码

popup的使用

关于$ionicPopup的详细使用, 可以参考官网

首先在controllers.js文件中添加一个controller:

.controller('messageCtrl', function($scope, $state, $ionicPopup, localStorageService, messageService) {
    $scope.popup = {
        isPopup: false,
        index: 0
    };
    $scope.onSwipeLeft = function() {
        $state.go("tab.friends");
    };
    $scope.popupMessageOpthins = function($index) {
        $scope.popup.index = $index;
        //这里通过$ionicPopup.show()方法创建了一个自定义的popup
        $scope.popup.optionsPopup = $ionicPopup.show({
            templateUrl: "templates/popup.html",
            scope: $scope,
        });
        $scope.popup.isPopup = true;
    };
    //实现标为已读/未读, 注意$scope.popup.optionsPopup.close()方法
    //用来关闭弹窗, 我竟然找了很久才发现这个接口
    $scope.markMessage = function() {
        var index = $scope.popup.index;
        var message = $scope.messages[index];
        if (message.showHints) {
            message.showHints = false;
            message.noReadMessages = 0;
        }else{
            message.showHints = true;
            message.noReadMessages = 1;
        }
        $scope.popup.optionsPopup.close();
        $scope.popup.isPopup = false;
        messageService.updateMessage(message);
    };

这里要注意两点

  1. 要在routes.js中将该controll传进去
  2. 需要通过自定义样式, 去掉自带的标题和按钮
    //routes.js
    .state('tab.message', {
    url: '/message',
    views: {
        'tab-message': {
            templateUrl: 'templates/tab-message.html',
            controller: "messageCtrl"
        }
    }
    })

自定义指令

细心的人会发现两个问题:

  1. 弹出popup时, 联系人列表没有动画效果
  2. 弹出popup后, 点击popup以外的地方, popup不能消失, 这两个问题, 就通过自定义指令来解决

首先在directives.js文件中添加rjCloseBackDrop指令, 用来解决上面第二个问题

.directive('rjCloseBackDrop', [function() {
        return {
            scope: false,//共享父scope
            restrict: 'A',
            replace: false,
            link: function(scope, iElm, iAttrs, controller) {
                //要在html上添加点击事件, 试了很久- -!
                var htmlEl = angular.element(document.querySelector('html'));
                htmlEl.on("click", function(event) {
                    if (event.target.nodeName === "HTML" &&
                        scope.popup.optionsPopup &&
                        scope.popup.isPopup) {
                        scope.popup.optionsPopup.close();
                        scope.popup.isPopup = false;
                    }
                });
            }
        };
    }])

再创建rjHoldActive指令, 用来解决第一个问题

.directive('rjHoldActive', ['$ionicGesture', '$timeout',
        function($ionicGesture, $timeout, $ionicBackdrop) {
            return {
                scope: false,
                restrict: 'A',
                replace: false,
                link: function(scope, iElm, iAttrs, controller) {
                    $ionicGesture.on("hold", function() {
                        iElm.addClass('active');
                        //300ms后恢复
                        $timeout(function() {
                            iElm.removeClass('active');
                        }, 300);
                    }, iElm);
                }
            };
        }
    ])

最后分别在ion-listion-item上添加指令

<ion-list rj-close-back-drop>
    <ion-item class="item-avatar"rj-hold-active ng-repeat="message in messages">

ok, 问题解决, 有点小激动~

自定义服务

前面讲的都是界面的东西, 那聊天记录的数据哪里来?
这里我们自定义一个假json数据, 用来模拟, 在www目录下创建文件data/json/messages.json

"messages": [{
        "id": 0,
        "name": "李明",
        "pic": "img/adam.jpg",
        "lastMessage": {
            "time": "2015-10-12 15:34:55",
            "content": "你在干什么?",
            "isFromeMe": false
        },
        "noReadMessages": 2,
        "showHints": true
    },...

目前用到的数据都定义在这, 后面还需要什么数据再添加
我们把数据存到localstorage中, 大家都知道localstorage是基于keyvalue存储的
总不能把所以人的消息都存在一条key中, 所以我定义两个服务

  1. 把整个json数据拆成单独的message, 把独立的message合并成一个对象
  2. 封装setItem, 基本数据的存储获取

具体我就不贴代码了, 讲下服务定义好了, 怎么使用, 比如定义了一个test服务:

.factory('test', ['', function(){
    return{
        dosomething: function(){
            return 0;
        }
    };
}])

用的时候直接把test注入, test.dosomething()调用:

.controller('someCtrl', function($scope, test) {
    test.dosomething();
    ...
}

是不是很简单?

最后

这篇写的很长, 其实实现的功能很简单, 主要是要学会如何定义样式, 自定义指令, 自定义服务
这样在后面实现更复杂的功能时, 不至于纠结这些细节.

我发现一个人自学, 确实有些困难, 一些小问题百度根本搜不到, google上才比较靠谱

所以小伙伴们遇到困难, 不妨google一下, 基本都有答案的哦
有问题欢迎大家评论, 我会的会及时回复~

Git代码

我推荐的 Java Web 学习路线 - l4y - 博客园

mikel阅读(1423)

来源: 我推荐的 Java Web 学习路线 – l4y – 博客园

晚上在 V2 的 Java 的节点看到有人问 Java Web 书籍推荐。我这半年多的时间,也从别的方向开始转向 Java 服务端开发,所以,我来说下我的学习路线,帮助有需要的朋友把半只脚踏进 Spring 大门。

本文所描述的路线,适合有其他面向对象语言编程经验,具备数据结构、算法、网络、数据库、设计模式、Linux 使用经验的人,如果你没有基础,这篇文章可能不适合你。

工欲善其事必先利其器

电脑系统推荐使用 *nix ,不论是 Linux 还是 macOS 都有强大的工具能让你学习的过程得心应手,Windows 系统也不是不可以,但 Windows 系统的终端个人很不喜欢。

IDE 推荐 IntelliJ IDEA,使用 Eclipse 也是可以的,不过现在越来越多的人开始使用 IntelliJ IDEA。

学习的过程中你会遇到各种各样的问题,无脑推荐 Google,鉴于目前国内的网络环境,你需要有利器能够访问 Google(比如 AT&T 漫游,误)。

Java SE

Java 基础有 Java编程思想Java核心技术Head First Java 等,我选择的是 Java编程思想(第4版),第 22 章是讲 GUI 的,可以不看。

现在你有 Java 基础了,但是现在 Java 发展到 1.9 的版本了,怎么办?

Java编程思想(第4版) 基本覆盖了 1.5 版本的内容,1.6、1.7 版本的更新,可以通过网上查资料来学习。1.8 版本有比较大的更新,建议买本书系统学习,我使用的是 Java 8 实战

好了,现在你会写 Java 代码了,但是 .java 文件如何成了 .class 文件,.class 文件长成什么样,又如何被加载到虚拟机中执行等等若干问题,难道你不好奇。这里推荐深入理解Java虚拟机(第2版)

随着时间流逝,你写了不少代码。但条条大路通罗马、再加上语言本身的语言负担,你或许会写出不那么优雅的代码,你需要前辈的经验来写清晰、健壮、高效的代码。Effective Java 就是这么一本书。当然,还有重构代码整洁之道这样的书,但这里只讨论 Java 。

Web

强烈不推荐上来直接上框架,你需要先了解 JSP、Servlet。这里我使用的是 Head First Servlets & JSPServlet与JSP核心编程这本书网上评价也不错。

好了,现在来说企业中的框架该怎么学。最最最重要的是,学的过程中一定要动手。

万事开头难。我最开始接触的时候,也是不知道如何开始框架的学习,在网络找了很多方法,浪费了不少时间,记住只有适合自己的才是最好的。在开始介绍前,再重复一遍,一动手尝试,二大胆猜测并验证。

1. Spring

在我刚开始的时候,很多人推荐直接读官方文档,经过验证,这种方法不适合初学者,或者说不适合我。

这里我使用的是Spring实战,学 Spring 一定要理解依赖注入(你说控制反转也行)和 AOP,跟着这本书敲,书中关于配置的东西一定要看仔细、理解好,不然配错了,自己找起来可能很麻烦。

2. Spring 与 MyBatis、Redis 等其他框架的整合。

MyBatis 推荐官方文档,然后找个 demo 做一下,自己再练习练习就可以了。

与 Spring 整合的时候参考文档,可以很简单的完成。

Redis 等其他框架的整合参考 Spring 实战,或者找资料都是可以的。

其他

要不要看视频这个事,我的观点是能不看就不看,但不要因噎废食。慕课网上有 SSM 框架的视频,对于这个路径,我的经验是直接跳过前两个,即战斗伊始–Spring转战阵地–SpringMVC,这两部分看 Spring实战就可以了,后边两个可以看看。

注意,针对这个慕课网这个视频我这里解释的是上文的你都做了,且自己写的服务能够正常运行。

刚接触框架配置很容易出错,出错的时候一定要耐心看输出的信息,有的很简单可能是手误,有的可能可能需要你对框架有些理解,所以 Just Google It

手动倒入 jar 包费时费力,上 maven 啊。

好了,你的服务跑起来了,你的半只脚已经进入了 Spring 的大门,请继续加油。


我在 Github 上有一个基于 SSM(Spring、Spring MVC、MyBatis)的小项目,部分学习内容会在该项目中使用。

该项目 Spring 相关配置,完全使用基于注解的方式。博主在刚接触各种配置的时候,绕了一些弯路。

对于刚接触这些框架的朋友,该项目或许会有些许帮助。如果在理解该项目时或参考时遇到任何问题,欢迎通过你能找到的任何方式联系我,非常乐意共同学习。

项目地址为:spittr 。

文中提高了慕课网,如果你喜欢 xml 配置的方式,可参考另外一个项目 seckill 。该项目是博主在慕课网上学习该课程的源代码,项目中没有完全采用基于注解的方式,相比而言,该项目在配置方面更加老道。

我写完了,如果你有什么不明白的可以发邮件给我。如果文中有不合适的地方,也请指正。我的邮箱地址是:shixj.cs@foxmail.com

如果针对文章内容有什么建议,可以在评论中回复。

远程调试(Remote Debugging) - mygrilzhuyulin的专栏 - CSDN博客

mikel阅读(1745)

当运行的程序出现问题时,我们通常通过调试来追踪和定位问题。但是,当运行错误的机器上没有调试工具,我们就需要实现远程调试。简单地说,就是要调试的程序和调试器不在一台机器上。移动端web调试,alert虽然是个土方法,但也是万能的,不过这样会中断程序的执行,效率也比较低下。后来大家开始尝试使用模拟器调试,如chrome自带的设备模拟器,可以帮助我们测试网页在不同设备、不同分辨率的情况下的显示情

来源: 远程调试(Remote Debugging) – mygrilzhuyulin的专栏 – CSDN博客

remote_debugging

当运行的程序出现问题时,我们通常通过调试来追踪和定位问题。但是,当运行错误的机器上没有调试工具,我们就需要实现远程调试。简单地说,就是要调试的程序和调试器不在一台机器上。

移动端web调试,alert虽然是个土方法,但也是万能的,不过这样会中断程序的执行,效率也比较低下。后来大家开始尝试使用模拟器调试,如chrome自带的设备模拟器,可以帮助我们测试网页在不同设备、不同分辨率的情况下的显示情况。其原理就是通过伪装User-Agent将浏览器模拟成相应设备,所以我们也不能太依赖模拟的结果,最终还是得使用真机调试。移动设备上没有调试工具?那你可以尝试一下远程调试,使用你的电脑来调试移动设备上的web页面。其实该类文章在网上也不少,有些介绍较为零散,有些由于软件升级等原因已不适用。本人经实践后,整理如下。

此处附送电梯:
1.iOS (web检查器)
2.Android (Android Chrome)
3.Weinre
4.Adobe Edge Inspect CC
5.MIHTool

  • iOS

Prepare: iOS6+, Mac, USB数据线
Setting:
1. 【iOS终端】设置→ Safari → 高级 → Web 检查器 → 开
ios-1
2.【OS X】Safari → 偏好设置 → 高级 → 启用“开发菜单”
ios-2
Running:
1. 使用iOS设备的Safari打开你想要调试的页面
2. 通过USB数据线连接iOS设备与Mac
3. 在Mac中启动Safari,从“开发”菜单下找到你的iOS设备
4. 子菜单项为移动设备上Safari的所有标签页,选择需要调试的页面。
ios-3
在这个调试器里,我们可以像使用桌面操作系统的 Safari 的调试器一样,做各种调试工作,譬如HTML 元素、CSS 及盒模型等的查看和即时编辑、JavaScript 调试器、网页元素时间轴、DOM 元素查看器等各种功能。
ios-4ios-5
Tips:
1. 如果在开发菜单中没显示你所连接的iOS设备,或是没有显示你打开的页面,在Mac上重启Safari。
2. Windows 版本的 Safari 暂无此功能。

  • Andriod

Prepare:
1. 一个Android手机或平板电脑与Chrome For Android32或更高版本,或者从GooglePlay上直接安装
2. 一条USB数据线
Windows用户还需要安装相应的USB驱动,下载地址:http://developer.android.com/tools/extras/oem-usb.html
3. 在您的开发机器安装了Chrome32或更高的版本
Running:
1. 在您的设备上启用USB调试
在Android 4.0及4.1,它是在设置>开发人员选项
在Android 4.2及更高版本中,开发人员选项默认是隐藏的,为了使其可用,进入设置>关于手机,点击版本号7次,返回到前一个页面,就可以找到开发人员选项。android-1
2. 设置Discover USB Devices
访问about:inspect,确保选中Discover USB Devices
android-2
3. 通过USB数据线连接你的设备和开发机器
当你的设备连接你的开发机器时,你可能会在你的设备上看到一个弹框请求允许使用这台计算机通过usb调试设备。如果你不想每次调试都看到这弹框,选中一律允许使用这台计算机进行调试并点击确定。
android-4
现在,你可以在该页面上看到所有你连接的设备和你打开的标签页。找到你需要调试的页面,点击inpect打开DevTools。你也可以重新加载这个页面,标签页置顶或者关闭它。更可以通过在输入框中键入网址新开一个页面。
android-5
4. 调试
android-7

例如,查看所选中页面中的元素,在移动设备上的Chrome中这个元素对应的页面结构会立即高亮显示。
同样,在DevTools的控制台中编写脚本或者执行命令,都会影响移动设备中检查的页面。也可以使用所有其他面板,例如Timeline和Profiles。

Tips:
1. DevTools现在对连接的设备支持 native USB Debugging。不再需要通过配置ADB或ADB plugin查看移动设备上的Chrome和WebView连接实例。
2. 如果已启用USB调试,但about:inspect页面并没有显示你的设备
检查设备上已有开发者选项可用并开启USB调试
确保你正在使用Chrome for Android 32或更高版本
检查Discover USB devices是否已被选中。如果有勾选,请拔出设备,并尝试撤消USB authorizations的开发人员选项,并重试。
如果是Windows用户,检查是否已安装驱动。建议使用第三方软件,如应用宝、豌豆荚等手机助手。
3. 如果打开DevTools只出现一个空白的页面,你可能需要
翻墙后再试试
把开发机器和移动设备上的Chrome都更新到最新版本
4.调试Android webviews,需要Android4.4或更高版本,更多详情请看https://developer.chrome.com/devtools/docs/remote-Debugging#Debugging-webviews

  • Weinre

Weinre的全称是 Web Inspector Remote,功能与Firebug、Web Inspector类似,可用于远程调试运行在移动设备上的Web页面。

Weinre的通信过程是这样的:
weinre01

Weinre 为了能够同步桌面的调试客户端和移动设备上的调试目标,需要你搭建一个调试服务器(Debug Server)。因此,在使用 Weinre 进行远程设备调试时,包含了上面的三种元素:
调试服务器:调试服务器起到代理的作用,为调试目标和调试客户端建立通信;
调试客户端:这是 Web Inspector 界面,即开发者在浏览器中进行调试的界面;
调试目标:需要调试的页面,也指用于运行被调试 Web 内容的的浏览器所在的移动设备。

平台支持:
调试服务器支持的平台
-任何支持node.js的平台
调试客户端支持的平台(运行调试界面的浏览器)
-Google Chrome
-Apple Safari
-其它基于 WebKit 的浏览器
调试目标支持的平台(需要调试的页面)
-Android 浏览器应用
-iOS Mobile Safari 应用
-PhoneGap/Cordova
-其它
调试目标不支持的平台
-iOS 3.1.3或更早
-webOS 1.45或更早

Install:
1. 安装Node运行环境
2.通过Node包管理工具安装weinre
npm –g install weinre
Running:
1. 启动weinre
Weinre 提供了6个可选的启动参数,其中下面两个参数一般会修改,其它的用默认值就可以了。
–httpPort 调试服务器运行的端口,默认的 8080,如果这个端口有在用,可以改为其它端口;
–boundHost 调试服务器绑定的 IP 地址,也可以是域名,默认是 localhost,还可以设置为 -all-,表示绑定到所有当前机器可以访问的接口。
如本人机器IP地址为192.168.2.1,则在控制台输入weinre –boundHost 192.168.2.1
2. 目标页面引入js
<script src=””http://a.b.c.d:8080/target/target-script-min.js#anonymous “></script><br “=””>    其中a.b.c.d为调试服务器IP地址
3. 在Chrome或Safari浏览器中打开http://a.b.c.d:8080/client/#anonymous
4. 使用你的移动设备访问目标页面
远程面版中将会显示连接到调试服务器的页面,连接到调试服务器的客户端,还有调试服务器的属性。
weinre02
除远程面板以外,还有元素面板,资源面板,网络面板,时间线面板和控制台,这些相信用过Chrome或Safari开发者工具的你应该都不会感到陌生了,我就不在此介绍了。weinre03 weinre04 weinre05 weinre06 weinre07
Tips:
1. 移动设备和电脑最好在同一网段,如果不在,需要保证能ping成功。
2. 网络面板不像chrme浏览器开发者工具那么强大,因为weinre是基于XMLHttpRequest进行监听的,所以只会显示通过XMLHttpRequest加载的网络数据,简单说就是通过ajax加载的页面或图片等。
3. 经本人亲测,Timeline面板一直没显示出任何数据,具体原因暂未知。
4. 暂不支持断点调试

  • Adobe Edge Inspect CC

Adobe公司推出的一个跨PC和各个移动平台的调试工具。
Prepare:
1. 将Edge Inspect下载到您的电脑
adobe01
在Creative Cloud中安装Edge Inspect CC,需要注册一个Adobe ID
2.安装扩展程序
adobe02
3. 在移动设备上安装App(支持iOS,Android,Kindle Fire)
adobe03
4. 安装Bonjour(Windows用户)
Bonjour安装程序在你的Edge Inspect安装目录下。
Win32: \Program Files\Adobe\Adobe Edge Inspect\BonjourPSSetup.exe
Win64: \Program Files (x86)\Adobe\Adobe Edge Inspect\BonjourPSSetup.exe
Running:
1. 在电脑打开Edge Inspect程序,所有移动设备打开Edge Inspect App
2. 通过Bonjour连接设备与电脑,或者手动输入IP地址连接
adobe04adobe05
3. 在Edge Inspect 扩展中输入每个移动设备的passcode
adobe06
4. 在电脑Chrome浏览器内打开需要调试的网页,此时移动设备Edge Inspect App内将会同步显示电脑浏览器里的内容。
adobe07
5. 点击“<>”开始调试
adobe08
adobe09
adobe10

Tips:
1. 确保你的电脑和你的设备在同一无线网络内
2. 基于Apache开源的weinre,不支持断点调试。

  • MIHTool

MIHTool 是前端工程师在iOS设备上调试和优化页面的得力助手。
Prepare: iOS设备,MIHTool(在App Store里下载安装),开发机器上已安装Chrome或Safari浏览器
Running:
1. 打开MIHTool,在地址栏输入你要调试的网页地址即可。
iPad版支持内嵌Web Inspector、模拟iPhone、编辑源码、查看当前页面的HAR、显示页面合成渲染层、显示元素的重绘渲染数等功能。
mihtool01 mihtool02
iPhone版同样支持远程打开Web inspector调试等多项功能。
mihtool03

Tips:
1. 基于Apache开源的weinre,不支持断点调试。

ionic开发篇之那些年我们踩过的坑 - mygrilzhuyulin的专栏 - CSDN博客

mikel阅读(1084)

版权声明:本文为博主原创文章,未经博主允许不得转载。目录(?)[+]一、API开发篇1.接口无法访问百度地图、自定义API无法访问,远程调试结果显示404 原因是cordova 5.x的版本增加了“Content-Security-Policy”用于解决安全访问的问题。默认情况下,只能访问本机资源。解决方法:  1.添加白名单插件

来源: ionic开发篇之那些年我们踩过的坑 – mygrilzhuyulin的专栏 – CSDN博客

一、API开发篇

1.接口无法访问

百度地图、自定义API无法访问,远程调试结果显示404
原因是cordova 5.x的版本增加了“Content-Security-Policy”用于解决安全访问的问题。默认情况下,只能访问本机资源。

解决方法:
1.添加白名单插件,在项目目录下执行

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">ionic plugin add cordova<span class="hljs-attribute" style="box-sizing: border-box;">-plugin</span><span class="hljs-attribute" style="box-sizing: border-box;">-whitelist</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

2.在index.html头部增加

<code class="hljs scilab has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><meta http-equiv=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Content-Security-Policy"</span> content=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"script-src * '</span>unsafe-<span class="hljs-transposed_variable" style="box-sizing: border-box;">eval'</span>; connect-src * <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'unsafe-eval'</span>; object-src <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'self'</span>; style-src * <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'unsafe-inline'</span>; img-src *<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" ></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

2.无法跨域访问

服务端设置

PHP代码

<code class="hljs scss has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;">header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Access-Control-Allow-Origin: *'</span>)</span>; <span class="hljs-function" style="box-sizing: border-box;">header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Access-Control-Allow-Credentials:true'</span>)</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

3.POST请求提交自动变成Options请求

当我们使用浏览器调试的时候,发现POST请求会自动变成Options请求,然后调用任意接口都提示不能跨域访问,即使服务端已经设置允许跨域访问。

解决方法:

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">.config(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">( <span class="hljs-variable" style="box-sizing: border-box;">$stateProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$urlRouterProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$ionicConfigProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$httpProvider</span>)</span> {</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Use x-www-form-urlencoded Content-Type</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$httpProvider</span>.defaults.headers.post[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Content-Type'</span>] = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'application/x-www-form-urlencoded;charset=utf-8'</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

这个问题只出现在浏览器调试中,实际在手机里运行不需要这个配置。

二、调试篇

1.本地调试

电脑上本地调试,用ionic serve即可在浏览器中调试

2.远程调试

1.在手机上运行Debug版软件,在电脑上调试程序
2.在启动手机上的APP后,在谷歌浏览器(其实360也行)上输入chrome://inspect/#devices,可以进入调试界面(如果出不来,请翻墙)
调试界面
3.单击inspect,可以进入当前显示的页面调试,调试方法和和在浏览器上一致。

远程调试可以快速定位,在浏览器上没有发现的问题,方便调试手机API接口

三.应用开发篇

1.导航置底设置

好不容易按教程一步步建立了tabs样例工程,却发现安卓机上这个tab导航在顶部,浏览器和iOS这个导航在顶部。

解决方法:在app.js里添加以下代码

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">.config(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(<span class="hljs-variable" style="box-sizing: border-box;">$stateProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$urlRouterProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$ionicConfigProvider</span>)</span> {</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.tabs.style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'standard'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.tabs.position(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'bottom'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.tabs.style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'standard'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.tabs.position(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'bottom'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.navBar.alignTitle(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'center'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.navBar.alignTitle(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'center'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.backButton.previousTitleText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>).icon(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ion-ios-arrow-thin-left'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.backButton.previousTitleText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>).icon(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ion-android-arrow-back'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.views.transition(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ios'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.views.transition(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'android'</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

2.百度地图开发

坑1:使用了插件angular-BMap

这个插件功能并不完善,好多功能都没有,如果要使用需要继续开发(如果你有时间,有兴趣,有能力可以fork后继续开发)

坑2:使用了百度地图实例代码,地图不显示

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> BMap<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Map</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"container"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建地图实例 </span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> point <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> BMap<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>Point(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">116.404</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">39.915</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建点坐标 </span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>centerAndZoom(point, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 初始化地图,设置中心点坐标和地图级别 </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

其实只是在模拟手机的浏览器下不显示,在浏览器上不要选择任何手机型号,就能显示,而实际我在自己的手机上build后,也是能正常显示的。具体原因没有深究,如果有知道的朋友欢迎来信。

坑3:GPS位置偏移

使用$cordovaGeolocation.getCurrentPosition()获得的坐标,在百度地图上位置偏移。原因是GPS坐标和百度地图坐标并不是完全对应的,需要使用百度地图提供的GPS坐标转换接口进行转换

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">posToAddrByBaidu</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(lat, long)</span>{</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> Ak = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'yourAK'</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//你应用的AK</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> getUrl = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'http://api.map.baidu.com/geocoder/v2/?'</span>+ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ak='</span> + Ak +<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'&location='</span> +lat+ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">','</span> + long + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'&output=json&pois=0'</span>; <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$http</span>.get(getUrl) .success(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(data)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (data[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'status'</span>] == <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'0'</span>) { <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$scope</span>.appeal.location = data.result.formatted_address; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'定位失败'</span>; } }).error(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> alert(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"网络问题"</span>); }); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>

坑4 infowindow里面的a链接只能跳转一次

BMap中创建的infowindow,如果里面带有a链接,第一次跳转后,第二次进去就无法跳转了。这个问题目前不知道怎么解决,如果有人知道请告诉我,谢谢。

(不断收集中……)

ionic常用的命令行 - mygrilzhuyulin的专栏 - CSDN博客

mikel阅读(1114)

1、安装cordovasudo npm -g install cordova2、安装ionicsudo npm -g install ionic3、卸载cordovasudo npm -g uinstall cordova4、卸载ionicsudo npm -g uinstall ionic5、安装plat

来源: ionic常用的命令行 – mygrilzhuyulin的专栏 – CSDN博客

1、安装cordova

sudo npm -g install cordova

2、安装ionic

sudo npm -g install ionic

3、卸载cordova

sudo npm -g uinstall cordova

4、卸载ionic

sudo npm -g uinstall ionic

5、安装plateform

ionic add platform ios/android

6、卸载plateform

ionic platform rm ios/android

7、bower[可参考http://www.biaodianfu.com/bower.html]

Bower 是 twitter 推出的一款包管理工具,基于nodejs的模块化思想,把功能分散到各个模块中,让模块和模块之间存在联系,通过 Bower 来管理模块间的这种联系。

一旦你已经安装了上面所说的所有必要文件,键入以下命令安装Bower:

这行命令是Bower的全局安装,-g 操作表示全局。

8、下载angularjs [cd到指定目录]

npm install angular

Ionic CLI 升级到最新版本 - tomKart - 博客园

mikel阅读(1035)

来源: Ionic CLI 升级到最新版本 – tomKart – 博客园

由于Ionic 自身也在不停的更新当中,

所以开发者经常会遇到从官方的CLI 命令,在命令行窗口中执行出错的情况。

就比如我一个月之前安装的ionic 2.2.2版本,已不能使用最新的3.2.0 CLI命令。

(其实困扰也没有那么大,cmd会有提示信息,告诉你command为什么无法执行,选择相应的策略去解决就行了。)

不过这里还是简要介绍一下如何升级Ionic CLI,算是留个小笔记。

npm update -g cordova ionic

执行完成后可以看到cordova和ionic更新后的版本号:

当然最原始的方式 npm uninstall ,然后npm clean,再npm install 也是可以的。

mac终端切换用户

mikel阅读(1245)

mac终端切换用户(做个小笔记)

1、mac终端切换用户到root

sudo -i即可

2、mac终端切换成普通用户

su – test(test为用户名)即可

3、mac可以设置命令别名

如ll,正常情况下,mac终端不识别ll命令,但是alias 命令设置别名后,终端即可以设别ll命令:alias ll=’ls -la’;但是没有修改系统文件,则该命令只能临时生效,下次再打开终端,还是不能识别ll命令,永久生效办法,请修改系统文件,方法有多种,请自行百度(如果不是ll命令,其他命令同理)

深度学习入门篇--手把手教你用 TensorFlow 训练模型 - 腾讯云技术社区 - 博客园

mikel阅读(1510)

来源: 深度学习入门篇–手把手教你用 TensorFlow 训练模型 – 腾讯云技术社区 – 博客园

导语

Tensorflow在更新1.0版本之后多了很多新功能,其中放出了很多用tf框架写的深度网络结构(https://github.com/tensorflow/models ),大大降低了开发难度,利用现成的网络结构,无论fine-tuning还是重新训练方便了不少。最近笔者终于跑通TensorFlow Object Detection API的ssd_mobilenet_v1模型,这里记录下如何完整跑通数据准备到模型使用的整个过程,相信对自己和一些同学能有所帮助。

Object Detection API提供了5种网络结构的预训练的权重,全部是用COCO数据集进行训练,这五种模型分别是SSD+mobilenet、SSD+inception_v2、R-FCN+resnet101、faster RCNN+resnet101、faster RCNN+inception+resnet101。各个模型的精度和计算所需时间如下。下面及介绍下如何使用Object Detection去训练自己的模型。

这里TensorFlow的安装就不再说明了,网上的教程一大把,大家可以找到很详尽的安装TensorFlow的文档。

训练前准备:

使用protobuf来配置模型和训练参数,所以API正常使用必须先编译protobuf库,这里可以下载直接编译好的pb库(https://github.com/google/protobuf/releases ),解压压缩包后,把protoc加入到环境变量中:

$ cd tensorflow/models

$ protoc object_detection/protos/*.proto --python_out=.

 

(我是把protoc加到环境变量中,遇到找不到*.proto文件的报错,后来把protoc.exe放到models/object_detection目录下,重新执行才可以)

然后将models和slim(tf高级框架)加入python环境变量:

PYTHONPATH=$PYTHONPATH:/your/path/to/tensorflow/models:/your/path/to/tensorflow/models/slim

 

数据准备:

数据集需要转化成PASCAL VOC结构,API提供了create_pascal_tf_record.py,把VOC结构数据集转换成.record格式。不过我们发现更简单的方式,Datitran提供一种更简单生产.record格式的方法。

首先需要先要标注图像相应标签,这里可以使用labelImg工具。每标注一张样本,即生成一个xml的标注文件。然后,把这些标注的xml文件,按训练集与验证集分别放置到两个目录下,在Datitran提供了xml_to_csv.py脚本。这里只要指定标注的目录名即可。接下来,然后需要我们把对应的csv格式转换成.record格式。

def main():
    # image_path = os.path.join(os.getcwd(), 'annotations')
    image_path = r'D:\training-sets\object-detection\sunglasses\label\test'
    xml_df = xml_to_csv(image_path)
    xml_df.to_csv('sunglasses_test_labels.csv', index=None)
    print('Successfully converted xml to csv.')

 

调用generate_tfrecord.py,注意要指定–csv_input与–output_path这两个参数。执行下面命令:

python generate_tfrecord.py --csv_input=sunglasses_test_labels.csv --output_path=sunglass_test.record

 

这样就生成了训练及验证用的train.record与test.record。接下来指定标签名称,仿照models/ object_detection/data/ pet_label_map.pbtxt,重新创建一个文件,指定标签名。

item {
  id: 1
  name: 'sunglasses'
}

 

训练:

根据自己的需要,选择一款用coco数据集预训练的模型,把前缀model.ckpt放置在待训练的目录,这里meta文件保存了graph和metadata,ckpt保存了网络的weights,这几个文件表示预训练模型的初始状态。

打开ssd_mobilenet_v1_pets.config文件,并做如下修改:

  1. num_classes:修改为自己的classes num

  1. 将所有PATH_TO_BE_CONFIGURED的地方修改为自己之前设置的路径(共5处)

其他参数均保持默认参数。

准备好上述文件后就可以直接调用train文件进行训练。

python object_detection/train.py \
--logtostderr \
--pipeline_config_path= D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config \
--train_dir=D:/training-sets/data-translate/training

 

TensorBoard监控:

通过tensorboard工具,可以监控训练过程,输入西面指令后,在浏览器输入localhost:6006(默认)即可。

tensorboard --logdir= D:/training-sets/data-translate/training

 

这里面有很多指标曲线,甚至有模型网络架构,笔者对于这里面很多指标含义还没有弄明白,不过感觉出TensorBoard这个工具应该是极其强大。不过我们可以通过Total_Loss来看整体训练的情况。

从整体上看,loss曲线确实是收敛的,整体的训练效果还是满意的。另外,TensorFlow还提供了训练过程中利用验证集验证准确性的能力,但是笔者在调用时,仍有些问题,这里暂时就不详细说明了。

Freeze Model模型导出:

查看模型实际的效果前,我们需要把训练的过程文件导出,生产.pb的模型文件。本来,tensorflow/python/tools/freeze_graph.py提供了freeze model的api,但是需要提供输出的final node names(一般是softmax之类的最后一层的激活函数命名),而object detection api提供提供了预训练好的网络,final node name并不好找,所以object_detection目录下还提供了export_inference_graph.py。

复制代码
python export_inference_graph.py \
--input_type image_tensor
--pipeline_config_path D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config \
--trained_checkpoint_prefix D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config /model.ckpt-* \
--output_directory D:/training-sets /data-translate/training/result
复制代码

 

导出完成后,在output_directory下,会生成frozen_inference_graph.pb、model.ckpt.data-00000-of-00001、model.ckpt.meta、model.ckpt.data文件。

调用生成模型:

目录下本身有一个调用的例子,稍微改造如下:

复制代码
import cv2
import numpy as np
import tensorflow as tf
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util


class TOD(object):
    def __init__(self):
        self.PATH_TO_CKPT = r'D:\lib\tf-model\models-master\object_detection\training\frozen_inference_graph.pb'
        self.PATH_TO_LABELS = r'D:\lib\tf-model\models-master\object_detection\training\sunglasses_label_map.pbtxt'
        self.NUM_CLASSES = 1
        self.detection_graph = self._load_model()
        self.category_index = self._load_label_map()

    def _load_model(self):
        detection_graph = tf.Graph()
        with detection_graph.as_default():
            od_graph_def = tf.GraphDef()
            with tf.gfile.GFile(self.PATH_TO_CKPT, 'rb') as fid:
                serialized_graph = fid.read()
                od_graph_def.ParseFromString(serialized_graph)
                tf.import_graph_def(od_graph_def, name='')
        return detection_graph

    def _load_label_map(self):
        label_map = label_map_util.load_labelmap(self.PATH_TO_LABELS)
        categories = label_map_util.convert_label_map_to_categories(label_map,
                                                                    max_num_classes=self.NUM_CLASSES,
                                                                    use_display_name=True)
        category_index = label_map_util.create_category_index(categories)
        return category_index

    def detect(self, image):
        with self.detection_graph.as_default():
            with tf.Session(graph=self.detection_graph) as sess:
                # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
                image_np_expanded = np.expand_dims(image, axis=0)
                image_tensor = self.detection_graph.get_tensor_by_name('image_tensor:0')
                boxes = self.detection_graph.get_tensor_by_name('detection_boxes:0')
                scores = self.detection_graph.get_tensor_by_name('detection_scores:0')
                classes = self.detection_graph.get_tensor_by_name('detection_classes:0')
                num_detections = self.detection_graph.get_tensor_by_name('num_detections:0')
                # Actual detection.
                (boxes, scores, classes, num_detections) = sess.run(
                    [boxes, scores, classes, num_detections],
                    feed_dict={image_tensor: image_np_expanded})
                # Visualization of the results of a detection.
                vis_util.visualize_boxes_and_labels_on_image_array(
                    image,
                    np.squeeze(boxes),
                    np.squeeze(classes).astype(np.int32),
                    np.squeeze(scores),
                    self.category_index,
                    use_normalized_coordinates=True,
                    line_thickness=8)

        cv2.namedWindow("detection", cv2.WINDOW_NORMAL)
        cv2.imshow("detection", image)
        cv2.waitKey(0)

if __name__ == '__main__':
    image = cv2.imread('image.jpg')
    detecotr = TOD()
    detecotr.detect(image)
复制代码

 

下面是一些图片的识别效果:

相关阅读

当强化学习遇见泛函分析

google cloud :穷人也能玩深度学习

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

此文已由作者授权腾讯云技术社区发布,转载请注明文章出处
原文链接:https://cloud.tencent.com/community/article/351424