地图两点间距离算法 - tangrongyue - 博客园

mikel阅读(1151)

来源: 地图两点间距离算法 – tangrongyue – 博客园

原文地址:http://blog.chinaunix.net/space.php?uid=22363424&do=blog&cuid=2108521

2009-02-13 11:14:40 发表于电子技术 本文链接: 通过经纬度计算距离的公式

在去年cosbeta曾经发布了一个网页计算工具,这个作用就是根据地球上两点之间的经纬度计算两点之间的直线距离。经纬度到距离的计算在通信工程中应用比较广泛,所以cosbeta通过搜索找到了一个js的计算脚本(其实是google map的计算脚本,应该算是比较准确了),做成了这个经纬度算距离的工具

今天有人给cosbeta发邮件,询问计算的公式是什么样的。其实,若是把地球当作一个正常的球体(其实它是椭球)来说,球面两点之间的距离计算并不复杂,运用球坐标很容易就能计算出两点之间的弧长。当然这都是高中的知识,我和你一样,也没有那个耐心来将其推导,所以我就利用google map的经纬度到距离计算的js脚本,将球面弧长的公式给还原出来(估计这个公式是经过部分修正的),还原出来的公式如下:

对上面的公式解释如下:

公式中经纬度均用弧度表示,角度到弧度的转化应该是很简单的了吧,若不会,依然请参考这个这个经纬度算距离的工具

Lat1 Lung1 表示A点经纬度,Lat2 Lung2 表示B点经纬度;

a=Lat1 – Lat2 为两点纬度之差  b=Lung1 -Lung2 为两点经度之差;

6378.137为地球半径,单位为公里;

计算出来的结果单位为公里;

http://www.storyday.com/wp-content/uploads/2008/09/latlung_dis.html

从google maps的脚本里扒了段代码,没准啥时会用上。大家一块看看是怎么算的。
private const double EARTH_RADIUS = 6378.137;
private static double rad(double d)
{
return d * Math.PI / 180.0;
}

public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 – radLat2;
double b = rad(lng1) – rad(lng2);
double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a/2),2) +
Math.Cos(radLat1)*Math.Cos(radLat2)*Math.Pow(Math.Sin(b/2),2)));
s = s * EARTH_RADIUS;
s = Math.Round(s * 10000) / 10000;
return s;
}

整理好后的完整程序如下:

#include <stdio.h>
#include <math.h>
#define EARTH_RADIUS  6378.137
#define PI 3.1415926
double rad(double d)
{
return d * PI / 180.0;
}
double dis(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 – radLat2;
double b = rad(lng1) – rad(lng2);
double s = 2 * asin(sqrt(pow(sin(a/2),2) + cos(radLat1)*cos(radLat2)*pow(sin(b/2),2)));
s = s * EARTH_RADIUS;
return s;
}

int main()
{
double lat1,lng1,lat2,lng2,distance;
printf(“please input lat1:\n”);
scanf(“%lf:”,&lat1);
printf(“please input lng1:\n”);
scanf(“%lf:”,&lng1);
printf(“please input lat2:\n”);
scanf(“%lf:”,&lat2);
printf(“please input lng2:\n”);
scanf(“%lf:”,&lng2);
distance=dis(lat1,lng1,lat2,lng2);
printf(“the distance is %f Km\n:”,distance);

return 0;

}

dede修改描述description限制字数长度 - 努力的小笨 - CSDN博客

mikel阅读(1060)

来源: dede修改描述description限制字数长度 – 努力的小笨 – CSDN博客

修改了好几个地方:

1、在dede文件夹下面article_description_main.php页面,找到“if($dsize>250) $dsize = 250;”语句把250修改为500。

2、dede 文件下的 article_edit.php(这里5.7以后不用改)和 article_edit.php 修改 $description = cn_substrR($description,250); 为 $description = cn_substrR($description,500);

3、登录后台,在系统-系统基本参数-其它选项中,自动摘要长度,改成500。

4、登录后台,执行语句:alter table `dede_archives` change `description` `description` varchar( 500 ) 或者 直接登录主机数据库后台修改表dede_archives

5、调用:{dede:field.description function=’cn_substr(@me,500)’ /}。

[转载]php发送get、post请求的6种方法简明总结

mikel阅读(1557)

方法1: 用file_get_contents 以get方式获取内容:

1
2
3
4
5
<?php
$html = file_get_contents($url);
echo $html;
?>

方法2: 用fopen打开url, 以get方式获取内容:

1
2
3
4
5
6
7
8
9
<?php
$fp = fopen($url, ‘r');
stream_get_meta_data($fp);
while(!feof($fp)) {
$result .= fgets($fp, 1024);
}
echo “url body: $result”;
fclose($fp);
?>

方法3:用file_get_contents函数,以post方式获取url

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$data = array (‘foo' => ‘bar');
$data = http_build_query($data);
$opts = array (
‘http' => array (
‘method' => ‘POST',
‘header'=> “Content-type: application/x-www-form-urlencodedrn” .
“Content-Length: ” . strlen($data) . “rn”,
‘content' => $data
)
);
$context = stream_context_create($opts);
$html = file_get_contents(‘http://localhost/e/admin/test.html', false, $context);
echo $html;
?>

方法4:用fsockopen函数打开url,以get方式获取完整的数据,包括header和body,fsockopen需要 PHP.ini 中 allow_url_fopen 选项开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
function get_url ($url,$cookie=false)
{
$url = parse_url($url);
$query = $url[path].”?”.$url[query];
echo “Query:”.$query;
$fp = fsockopen( $url[host], $url[port]?$url[port]:80 , $errno, $errstr, 30);
if (!$fp) {
return false;
} else {
$request = “GET $query HTTP/1.1rn”;
$request .= “Host: $url[host]rn”;
$request .= “Connection: Closern”;
if($cookie) $request.=”Cookie:  $cookien”;
$request.=”rn”;
fwrite($fp,$request);
while(!@feof($fp)) {
$result .= @fgets($fp, 1024);
}
fclose($fp);
return $result;
}
}
//获取url的html部分,去掉header
function GetUrlHTML($url,$cookie=false)
{
$rowdata = get_url($url,$cookie);
if($rowdata)
{
$body= stristr($rowdata,”rnrn”);
$body=substr($body,4,strlen($body));
return $body;
}
return false;
}
?>

方法5:用fsockopen函数打开url,以POST方式获取完整的数据,包括header和body

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
function HTTP_Post($URL,$data,$cookie, $referrer=”")
{
// parsing the given URL
$URL_Info=parse_url($URL);
// Building referrer
if($referrer==”") // if not given use this script as referrer
$referrer=”111″;
// making string from $data
foreach($data as $key=>$value)
$values[]=”$key=”.urlencode($value);
$data_string=implode(“&”,$values);
// Find out which port is needed – if not given use standard (=80)
if(!isset($URL_Info["port"]))
$URL_Info["port"]=80;
// building POST-request:
$request.=”POST “.$URL_Info["path"].” HTTP/1.1n”;
$request.=”Host: “.$URL_Info["host"].”n”;
$request.=”Referer: $referern”;
$request.=”Content-type: application/x-www-form-urlencodedn”;
$request.=”Content-length: “.strlen($data_string).”n”;
$request.=”Connection: closen”;
$request.=”Cookie:  $cookien”;
$request.=”n”;
$request.=$data_string.”n”;
$fp = fsockopen($URL_Info["host"],$URL_Info["port"]);
fputs($fp, $request);
while(!feof($fp)) {
$result .= fgets($fp, 1024);
}
fclose($fp);
return $result;
}
?>

方法6:使用curl库,使用curl库之前,可能需要查看一下php.ini是否已经打开了curl扩展

1
2
3
4
5
6
7
8
9
10
11
<?php
$ch = curl_init();
$timeout = 5;
curl_setopt ($ch, CURLOPT_URL, ‘http://www.jb51.net/');
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$file_contents = curl_exec($ch);
curl_close($ch);
echo $file_contents;
?>

AlexNet原理及Tensorflow实现 - CSDN博客

mikel阅读(1317)

来源: AlexNet原理及Tensorflow实现 – CSDN博客

AlexNet的出现点燃了深度学习的热潮,下面对其进行介绍,并使用tensorflow实现.

1. AlexNet网络结构

这里写图片描述

图片来源:AlexNet的论文

整个网络有8个需要训练的层,前5个为卷积层,最后3层为全连接层.

第一个卷积层

  1. 输入的图片大小为:224*224*3
  2. 第一个卷积层为:11*11*96即尺寸为11*11,有96个卷积核,步长为4,卷积层后跟ReLU,因此输出的尺寸为 224/4=56,去掉边缘为55,因此其输出的每个feature map 为 55*55*96,同时后面跟LRN层,尺寸不变.
  3. 最大池化层,核大小为3*3,步长为2,因此feature map的大小为:27*27*96.

第二层卷积层

  1. 输入的tensor为27*27*96
  2. 卷积和的大小为: 5*5*256,步长为1,尺寸不会改变,同样紧跟ReLU,和LRN层.
  3. 最大池化层,和大小为3*3,步长为2,因此feature map为:13*13*256

第三层至第五层卷积层

  1. 输入的tensor为13*13*256
  2. 第三层卷积为 3*3*384,步长为1,加上ReLU
  3. 第四层卷积为 3*3*384,步长为1,加上ReLU
  4. 第五层卷积为 3*3*256,步长为1,加上ReLU
  5. 第五层后跟最大池化层,核大小3*3,步长为2,因此feature map:6*6*256

第六层至第八层全连接层

接下来的三层为全连接层,分别为:
1. FC : 4096 + ReLU
2. FC:4096 + ReLU
3. FC: 1000
最后一层为softmax为1000类的概率值.

2. AlexNet中的trick

AlexNet将CNN用到了更深更宽的网络中,其效果分类的精度更高相比于以前的LeNet,其中有一些trick是必须要知道的.

ReLU的应用

AlexNet使用ReLU代替了Sigmoid,其能更快的训练,同时解决sigmoid在训练较深的网络中出现的梯度消失,或者说梯度弥散的问题.

Dropout随机失活

随机忽略一些神经元,以避免过拟合,

重叠的最大池化层

在以前的CNN中普遍使用平均池化层,AlexNet全部使用最大池化层,避免了平均池化层的模糊化的效果,并且步长比池化的核的尺寸小,这样池化层的输出之间有重叠,提升了特征的丰富性.

提出了LRN层

局部响应归一化,对局部神经元创建了竞争的机制,使得其中响应小打的值变得更大,并抑制反馈较小的.

使用了GPU加速计算

使用了gpu加速神经网络的训练

数据增强

使用数据增强的方法缓解过拟合现象.

3. Tensorflow实现AlexNet

下面是tensorflow的开源实现:https://github.com/tensorflow/models

AlexNet训练非常耗时,因此只定义网络结构,并进行前向后向的测试.这里自己使用的是CPU运行的…

首先定义一个接口,输入为图像,输出为第五个卷积层最后的池化层的数据,和每一个层的参数信息.都很简单,如果不懂可以参考tensorflow实战这本书或者共同交流.

def print_activations(t):
  print(t.op.name, ' ', t.get_shape().as_list())
  • 1
  • 2

上面的函数为输出当前层的参数的信息.下面是我对开源实现做了一些参数上的修改,代码如下:

def inference(images):
  """Build the AlexNet model.
  Args:
    images: Images Tensor
  Returns:
    pool5: the last Tensor in the convolutional component of AlexNet.
    parameters: a list of Tensors corresponding to the weights and biases of the
        AlexNet model.
  """
  parameters = []
  # conv1
  with tf.name_scope('conv1') as scope:
    kernel = tf.Variable(tf.truncated_normal([11, 11, 3, 96], dtype=tf.float32,
                                             stddev=1e-1), name='weights')
    conv = tf.nn.conv2d(images, kernel, [1, 4, 4, 1], padding='SAME')
    biases = tf.Variable(tf.constant(0.0, shape=[96], dtype=tf.float32),
                         trainable=True, name='biases')
    bias = tf.nn.bias_add(conv, biases)
    conv1 = tf.nn.relu(bias, name=scope)
    print_activations(conv1)
    parameters += [kernel, biases]

  # lrn1
  # TODO(shlens, jiayq): Add a GPU version of local response normalization.

  # pool1
  pool1 = tf.nn.max_pool(conv1,
                         ksize=[1, 3, 3, 1],
                         strides=[1, 2, 2, 1],
                         padding='VALID',
                         name='pool1')
  print_activations(pool1)

  # conv2
  with tf.name_scope('conv2') as scope:
    kernel = tf.Variable(tf.truncated_normal([5, 5, 96, 256], dtype=tf.float32,
                                             stddev=1e-1), name='weights')
    conv = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME')
    biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
                         trainable=True, name='biases')
    bias = tf.nn.bias_add(conv, biases)
    conv2 = tf.nn.relu(bias, name=scope)
    parameters += [kernel, biases]
  print_activations(conv2)

  # pool2
  pool2 = tf.nn.max_pool(conv2,
                         ksize=[1, 3, 3, 1],
                         strides=[1, 2, 2, 1],
                         padding='VALID',
                         name='pool2')
  print_activations(pool2)

  # conv3
  with tf.name_scope('conv3') as scope:
    kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 384],
                                             dtype=tf.float32,
                                             stddev=1e-1), name='weights')
    conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
    biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
                         trainable=True, name='biases')
    bias = tf.nn.bias_add(conv, biases)
    conv3 = tf.nn.relu(bias, name=scope)
    parameters += [kernel, biases]
    print_activations(conv3)

  # conv4
  with tf.name_scope('conv4') as scope:
    kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 384],
                                             dtype=tf.float32,
                                             stddev=1e-1), name='weights')
    conv = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME')
    biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
                         trainable=True, name='biases')
    bias = tf.nn.bias_add(conv, biases)
    conv4 = tf.nn.relu(bias, name=scope)
    parameters += [kernel, biases]
    print_activations(conv4)

  # conv5
  with tf.name_scope('conv5') as scope:
    kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256],
                                             dtype=tf.float32,
                                             stddev=1e-1), name='weights')
    conv = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME')
    biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
                         trainable=True, name='biases')
    bias = tf.nn.bias_add(conv, biases)
    conv5 = tf.nn.relu(bias, name=scope)
    parameters += [kernel, biases]
    print_activations(conv5)

  # pool5
  pool5 = tf.nn.max_pool(conv5,
                         ksize=[1, 3, 3, 1],
                         strides=[1, 2, 2, 1],
                         padding='VALID',
                         name='pool5')
  print_activations(pool5)

  return pool5, parameters

测试的函数:
image是随机生成的数据,不是真实的数据

def run_benchmark():
  """Run the benchmark on AlexNet."""
  with tf.Graph().as_default():
    # Generate some dummy images.
    image_size = 224
    # Note that our padding definition is slightly different the cuda-convnet.
    # In order to force the model to start with the same activations sizes,
    # we add 3 to the image_size and employ VALID padding above.
    images = tf.Variable(tf.random_normal([FLAGS.batch_size,
                                           image_size,
                                           image_size, 3],
                                          dtype=tf.float32,
                                          stddev=1e-1))

    # Build a Graph that computes the logits predictions from the
    # inference model.
    pool5, parameters = inference(images)

    # Build an initialization operation.
    init = tf.global_variables_initializer()

    # Start running operations on the Graph.
    config = tf.ConfigProto()
    config.gpu_options.allocator_type = 'BFC'
    sess = tf.Session(config=config)
    sess.run(init)

    # Run the forward benchmark.
    time_tensorflow_run(sess, pool5, "Forward")

    # Add a simple objective so we can calculate the backward pass.
    objective = tf.nn.l2_loss(pool5)
    # Compute the gradient with respect to all the parameters.
    grad = tf.gradients(objective, parameters)
    # Run the backward benchmark.
    time_tensorflow_run(sess, grad, "Forward-backward")

输出的结果为:
下面为输出的尺寸,具体的分析过程上面已经说的很详细了.

conv1   [128, 56, 56, 96]
pool1   [128, 27, 27, 96]
conv2   [128, 27, 27, 256]
pool2   [128, 13, 13, 256]
conv3   [128, 13, 13, 384]
conv4   [128, 13, 13, 384]
conv5   [128, 13, 13, 256]
pool5   [128, 6, 6, 256]

下面是训练的前后向耗时,可以看到后向传播比前向要慢3倍.

2017-05-02 15:40:53.118788: step 0, duration = 3.969
2017-05-02 15:41:30.003927: step 10, duration = 3.550
2017-05-02 15:42:07.242987: step 20, duration = 3.797
2017-05-02 15:42:44.610630: step 30, duration = 3.487
2017-05-02 15:43:20.021931: step 40, duration = 3.535
2017-05-02 15:43:55.832460: step 50, duration = 3.687
2017-05-02 15:44:31.803954: step 60, duration = 3.567
2017-05-02 15:45:08.156715: step 70, duration = 3.803
2017-05-02 15:45:44.739322: step 80, duration = 3.584
2017-05-02 15:46:20.349876: step 90, duration = 3.569
2017-05-02 15:46:53.242329: Forward across 100 steps, 3.641 +/- 0.130 sec / batch
2017-05-02 15:49:01.054495: step 0, duration = 11.493
2017-05-02 15:50:55.424543: step 10, duration = 10.905
2017-05-02 15:52:47.021526: step 20, duration = 11.797
2017-05-02 15:54:42.965286: step 30, duration = 11.559
2017-05-02 15:56:36.329784: step 40, duration = 11.185
2017-05-02 15:58:32.146361: step 50, duration = 11.945
2017-05-02 16:00:21.971351: step 60, duration = 10.887
2017-05-02 16:02:10.775796: step 70, duration = 10.914
2017-05-02 16:04:07.438658: step 80, duration = 11.409
2017-05-02 16:05:56.403530: step 90, duration = 10.915
2017-05-02 16:07:34.297486: Forward-backward across 100 steps, 11.247 +/- 0.448 sec / batch

完整的代码和测试在我的github:https://github.com/yqtaowhu/MachineLearning

参考资料

  1. ImageNet Classification with Deep Convolutional Neural Networks
  2. https://github.com/tensorflow/models
  3. tensorflow实战
  4. http://www.cnblogs.com/yymn/p/4553839.html

十图详解tensorflow数据读取机制(附代码)

mikel阅读(1184)

来源: 十图详解tensorflow数据读取机制(附代码)

在学习tensorflow的过程中,有很多小伙伴反映读取数据这一块很难理解。确实这一块官方的教程比较简略,网上也找不到什么合适的学习材料。今天这篇文章就以图片的形式,用最简单的语言,为大家详细解释一下tensorflow的数据读取机制,文章的最后还会给出实战代码以供参考。

一、tensorflow读取机制图解

首先需要思考的一个问题是,什么是数据读取?以图像数据为例,读取数据的过程可以用下图来表示:

假设我们的硬盘中有一个图片数据集0001.jpg,0002.jpg,0003.jpg……我们只需要把它们读取到内存中,然后提供给GPU或是CPU进行计算就可以了。这听起来很容易,但事实远没有那么简单。事实上,我们必须要把数据先读入后才能进行计算,假设读入用时0.1s,计算用时0.9s,那么就意味着每过1s,GPU都会有0.1s无事可做,这就大大降低了运算的效率。

如何解决这个问题?方法就是将读入数据和计算分别放在两个线程中,将数据读入内存的一个队列,如下图所示:

读取线程源源不断地将文件系统中的图片读入到一个内存的队列中,而负责计算的是另一个线程,计算需要数据时,直接从内存队列中取就可以了。这样就可以解决GPU因为IO而空闲的问题!

而在tensorflow中,为了方便管理,在内存队列前又添加了一层所谓的“文件名队列”

为什么要添加这一层文件名队列?我们首先得了解机器学习中的一个概念:epoch。对于一个数据集来讲,运行一个epoch就是将这个数据集中的图片全部计算一遍。如一个数据集中有三张图片A.jpg、B.jpg、C.jpg,那么跑一个epoch就是指对A、B、C三张图片都计算了一遍。两个epoch就是指先对A、B、C各计算一遍,然后再全部计算一遍,也就是说每张图片都计算了两遍。

tensorflow使用文件名队列+内存队列双队列的形式读入文件,可以很好地管理epoch。下面我们用图片的形式来说明这个机制的运行方式。如下图,还是以数据集A.jpg, B.jpg, C.jpg为例,假定我们要跑一个epoch,那么我们就在文件名队列中把A、B、C各放入一次,并在之后标注队列结束。

程序运行后,内存队列首先读入A(此时A从文件名队列中出队):

再依次读入B和C:

此时,如果再尝试读入,系统由于检测到了“结束”,就会自动抛出一个异常(OutOfRange)。外部捕捉到这个异常后就可以结束程序了。这就是tensorflow中读取数据的基本机制。如果我们要跑2个epoch而不是1个epoch,那只要在文件名队列中将A、B、C依次放入两次再标记结束就可以了。

二、tensorflow读取数据机制的对应函数

如何在tensorflow中创建上述的两个队列呢?

对于文件名队列,我们使用tf.train.string_input_producer函数。这个函数需要传入一个文件名list,系统会自动将它转为一个文件名队列。

此外tf.train.string_input_producer还有两个重要的参数,一个是num_epochs,它就是我们上文中提到的epoch数。另外一个就是shuffle,shuffle是指在一个epoch内文件的顺序是否被打乱。若设置shuffle=False,如下图,每个epoch内,数据还是按照A、B、C的顺序进入文件名队列,这个顺序不会改变:

如果设置shuffle=True,那么在一个epoch内,数据的前后顺序就会被打乱,如下图所示:

在tensorflow中,内存队列不需要我们自己建立,我们只需要使用reader对象从文件名队列中读取数据就可以了,具体实现可以参考下面的实战代码。

除了tf.train.string_input_producer外,我们还要额外介绍一个函数:tf.train.start_queue_runners。初学者会经常在代码中看到这个函数,但往往很难理解它的用处,在这里,有了上面的铺垫后,我们就可以解释这个函数的作用了。

在我们使用tf.train.string_input_producer创建文件名队列后,整个系统其实还是处于“停滞状态”的,也就是说,我们文件名并没有真正被加入到队列中(如下图所示)。此时如果我们开始计算,因为内存队列中什么也没有,计算单元就会一直等待,导致整个系统被阻塞。

而使用tf.train.start_queue_runners之后,才会启动填充队列的线程,这时系统就不再“停滞”。此后计算单元就可以拿到数据并进行计算,整个程序也就跑起来了,这就是函数tf.train.start_queue_runners的用处。

三、实战代码

我们用一个具体的例子感受tensorflow中的数据读取。如图,假设我们在当前文件夹中已经有A.jpg、B.jpg、C.jpg三张图片,我们希望读取这三张图片5个epoch并且把读取的结果重新存到read文件夹中。

对应的代码如下:

# 导入tensorflow
import tensorflow as tf 

# 新建一个Session
with tf.Session() as sess:
    # 我们要读三幅图片A.jpg, B.jpg, C.jpg
    filename = ['A.jpg', 'B.jpg', 'C.jpg']
    # string_input_producer会产生一个文件名队列
    filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)
    # reader从文件名队列中读数据。对应的方法是reader.read
    reader = tf.WholeFileReader()
    key, value = reader.read(filename_queue)
    # tf.train.string_input_producer定义了一个epoch变量,要对它进行初始化
    tf.local_variables_initializer().run()
    # 使用start_queue_runners之后,才会开始填充队列
    threads = tf.train.start_queue_runners(sess=sess)
    i = 0
    while True:
        i += 1
        # 获取图片数据并保存
        image_data = sess.run(value)
        with open('read/test_%d.jpg' % i, 'wb') as f:
            f.write(image_data)

我们这里使用filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)建立了一个会跑5个epoch的文件名队列。并使用reader读取,reader每次读取一张图片并保存。

运行代码后,我们得到就可以看到read文件夹中的图片,正好是按顺序的5个epoch:

如果我们设置filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)中的shuffle=True,那么在每个epoch内图像就会被打乱,如图所示:

我们这里只是用三张图片举例,实际应用中一个数据集肯定不止3张图片,不过涉及到的原理都是共通的。

四、总结

这篇文章主要用图解的方式详细介绍了tensorflow读取数据的机制,最后还给出了对应的实战代码,希望能够给大家学习tensorflow带来一些实质性的帮助。如果各位小伙伴还有什么疑问,欢迎评论或私信告诉我,谢谢~

Django开发小型站之前期准备(一) - LOVESTYUDY - 博客园

mikel阅读(1060)

来源: Django开发小型站之前期准备(一) – LOVESTYUDY – 博客园

语言:python3.5

工具:JetBrains PyCharm

virtualenvwrapper优点:

1、使不同的应用开发环境独立

2、环境升级不影响其他应用,也不会影响全局的python环境

3、它可以防止系统中出现包管理混乱和版本的冲突

1、安装virtualenvwrapper

pip3 install virtualenvwrapper-win

2、新建虚拟环境

mkvirtualenv testvir2

3、查看当前虚拟环境安装了哪些库

pip3 list –format=columns

4、安装django

pip3 install django

5、安装mySQL

pip3 intstall pymySQL

Django 在Python3.5 下报 没有模块MySQLdb

解决方法:

在整个项目站点下的__init__.py 文件里(即和setting.py在同一个文件下)写入以下代码:

import pymysql
pymysql.install_as_MySQLdb()

需要提前安装pymysql模块,相当于Python2中的MySQLdb模块。

即可解决问题。

6、退出当前虚拟环境

deactivate

Angular 2 WhatsApp clone with Meteor & Ionic

mikel阅读(1388)

来源: Angular 2 WhatsApp clone with Meteor & Ionic

Angular-Meteor & Ionic 2

Your next project

Facing your next app project, web, mobile or both, you want to choose the best solutions to start fast while also solutions that will stay relevant when your project grows and scales.

Angular, Meteor and Ionic are all platforms that aim to supply everything you need to write when creating an app.

Angular – Angular is a frontend platform that tried to include everything you need in order to build the frontend part of your Angular. Angular also has their own CLI that is based on Webpack.

Ionic – Ionic is based on Angular. it has become one of the most popular solutions to develop hybrid mobile apps fast across different platform.

The Ionic platform includes solutions for prototyping, build, testing, deploying apps, a market of starter apps, plugins and themes, CLI integration and push notifications service. (Further writing by an Ionic person)

Meteor – But your app needs a full stack solution.

Meteor has become the only open source JavaScript platform that supply the complete set of solutions you need to create a real time mobile connected apps.

The Meteor platform is reliable, fast and easy to develop and deploy and it will also handle all the complexities of your app when it grows and scales with time.

How to choose?

Angular Meteor

Your best option is to use all of them together! With angular-meteor, Meteor became the best backend for Angular and Ionic apps.

So now you can use the strengthnesses of each of those platform combined the create the ultimate stack for your mobile apps.

The Angular Meteor project’s goal is to make the process of creating apps as easy and fast as possible. I do that by keeping track of the latest releases and libraries and comparing them with each other on top of a real apps that our community developers and we support.

But I also believe that education and resources is a crucial part of having a great platform so that’s why I’ve created the tutorial and the tutorial infrastructure that are based on the real WhatsApp and Slack clone app that I use myself and in our community team.

In this tutorial we will create a full WhatsApp and Slack clone, using Angular and the Ionic Framework, using Meteor’s realtime collections for the chat and Meteor’s simple Authentication packages for SMS based authentication.

But which CLI tool should you choose?
Each platform has it’s own CLI and build process solutions. You can choose the CLI and build process that you prefer.

But which one is best for you? Meteor CLI, Ionic CLI or Angular CLI?

So I’ve decided to create to two versions of the tutorial, one, using the Ionic CLI and one, using the Meteor CLI and build process.

The goal of the tutorial is to learn Angular but we are using Ionic because it’s just an addition on top of Angular and it doesn’t require to learn a lot of different concepts then just Angular. Also, the steps that require in order to use the Ionic CLI with Meteor are almost identical to the steps that require in order to use the Angular CLI.

The tutorial is completely based on git and that means that we can compare tools like Ionic, Webpack, Meteor and Angular with an actual git diff between the same app written with each of these flavors. So just go in the tutorial and click between the different versions to compare the difference.

Are we missing a flavor you want? open an issue and help us out

Please send feedback and requests about this tutorial with opening issues on the Angular Meteor Github repository.

Ionic-wechat项目边开发边学(四):可伸缩输入框,下拉刷新, 置顶删除 - Frogmarch - 博客园

mikel阅读(1329)

来源: Ionic-wechat项目边开发边学(四):可伸缩输入框,下拉刷新, 置顶删除 – Frogmarch – 博客园

摘要

上一篇文章主要介绍了ion-list的使用, ion-popup的使用, 通过sass自定义样式, localStorage的使用, 自定义指令和服务. 这篇文章实现的功能有消息的置顶与删除, 了聊天详情页面, 可伸缩输入框, 下拉刷新聊天记录, 要介绍的知识点有:

  1. filter orderBy的使用
  2. 引入angular-elastic模块
  3. 下拉刷新
  4. keyboard插件的使用
  5. 如何在真机中调试

先看效果图(键盘弹起会覆盖聊天记录, 已修复):

清晰效果见视频

filter orderBy的应用

聊天列表需要按时间顺序排列, 同时点击置顶后, 置顶的记录需要排在最上面, 这个效果就使用angularJS内置的过滤器
orderBy来排序, 使用方式

ng-repeat="item in items | orderBy : expression : reverse

这里的expression可以是functionangular expressionArray, 当为数组的时候, 首先按第一个排, 当相等的时候再按第二个排, 以此类推
reverse布尔值, 表示正序还是反序

所以我们只需要设置两个变量, 一个最后一条消息时间, 一个设置置顶的时间就可以实现置顶:

ng-repeat="message in messages | orderBy:['isTop', 'lastMessage.timeFrome1970']:true

可伸缩输入框

细心的人可能会发现, 微信的输入框超过一行后, 高度会变大的, 所以我们也来做一个可伸缩的输入框
Angular Elastic这个是一个autosize textareas的
angularJS插件, 我们需要融入到Ionic中, 首先把该插件源码放到js/目录下, 并在app.js中注入

angular.module('wechat', ['ionic', 'wechat.controllers', 'wechat.routes',
     'wechat.services', 'wechat.directives', 'monospaced.elastic'
      ])//注入monospaced.elastic

然后在textarea中添加msd-elastic指令

<textarea msd-elastic ng-model="foo">
  ...
</textarea>

做到这里, textare还是不能伸缩的, 因为ion-footer-bar的高度是固定的, 所以我们需要先动态调整ion-footer-bar
的高度, 在elastic.js中向上传播taResize事件, 这个名字可以自己定义

if (taHeight !== mirrorHeight) {
     scope.$emit('elastic:resize', $ta, taHeight, mirrorHeight);
     ta.style.height = mirrorHeight + 'px';
}   
 
scope.$emit('taResize', $ta); //添加此行
// small delay to prevent an infinite loop
$timeout(function() {
     active = false;
}, 1, false);

再在directives.js中创建一个指令:

     .directive('resizeFootBar', ['$ionicScrollDelegate', function($ionicScrollDelegate){
         // Runs during compile
         return {
             replace: false,
             link: function(scope, iElm, iAttrs, controller) {
                 //绑定taResize事件
                 scope.$on("taResize", function(e, ta) {
                     if (!ta) return;
                     var scroll = document.body.querySelector("#message-detail-content");
                     var scrollBar = $ionicScrollDelegate.$getByHandle('messageDetailsScroll');
                     var taHeight = ta[0].offsetHeight;
                     var newFooterHeight = taHeight + 10;
                     newFooterHeight = (newFooterHeight > 44) ? newFooterHeight : 44;
 
                     //调整ion-footer-bar高度
                     iElm[0].style.height = newFooterHeight + 'px';
                     //下面两行代码, 是解决键盘弹出覆盖聊天内容的bug
                     //第一行增加内容区高度
                     //第二行滑动到底部
                     scroll.style.bottom = newFooterHeight + 'px';
                     scrollBar.scrollBottom();
                 });
             }
         };
     }]);

最后再在ion-footer-bar中添加这个指令就行拉, 别忘了把左右图标固定到底部哦~

keyboard插件的使用

ionic-plugin-keyboard插件可以让你更轻松的处理键盘相关的事件
细心的人会发现, 上面的输入框在弹出键盘后会覆盖聊天记录的内容, 所以我们需要引入这个插件, 当弹出键盘的时候, 需要把scroll
滑到底部, 在项目目录下输入下面命令安装插件:

cordova plugin add ionic-plugin-keyboard

然后就可以注册键盘相关消息

window.addEventListener("native.keyboardshow", function(e){
               viewScroll.scrollBottom();
           });

这样的话, 就不会遮住聊天记录啦, 注意刚刚那个指令中的两行代码哦~

如何在真机中调试

调试键盘消息时, 电脑上不会弹出键盘, 就需要在手机上调试, 但是手机上的打印消息看不到, 如何调试呢?
相信大家跟我一样迫切需要这个功能, 给大家介绍一下利用chrome调试, 很强大哦~
首先手机连上电脑ionic run Android安装好应用
再在chrome地址栏中输入chrome://inspect/#devices
然后点击inspect就行拉, 就跟调试网页一样哦, 很方便~

最后

到这里message这块就差不多了, 还有些细节我没写出来, 大家有疑问可以在下面评论哦, 或者直接查看代码, 下一章将开始联系人列表模块.
最近公司开始新项目, 比较忙, 更新有点慢, 但我会坚持下去!

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

mikel阅读(1307)

来源: 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,这篇就写到这里,下一篇项目正式开始