编辑 Crontab 文件: crontab -e

查看 Crontab 日志: tail -100f /var/log/cron

基本格式 :

Crontab

*  *  *  *  *  command

分 时 日 月 周 命令

第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令

Crontab文件的一些例子:

30 21 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每晚的21:30重启apache

45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每月1、10、22日的4 : 45重启apache

10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每周六、周日的1 : 10重启apache

0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示在每天18 : 00至23 : 00之间每隔30分钟重启apache

0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每星期六的11 : 00 pm重启apache

* */1 * * * /usr/local/etc/rc.d/lighttpd restart
每一小时重启apache

* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
晚上11点到早上7点之间,每隔一小时重启apache

0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
每月的4号与每周一到周三的11点重启apache

0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
一月一号的4点重启apache

遇到的坑

* 1 * * * 这样写的话会每天1点的每分钟执行一次,需要写成 0 1 * * * 这样的形式

框架

原始图像

四层

  • WEB框架(处理器、模板、数据库连接、认证、本地化等)
  • HTTP/HTTPS层(基于HTTP协议实现了HTTP服务器和客户端)
  • TCP层(TCP服务器,负责数据传输)
  • EVENT层(处理IO事件)

============================================================

基础用法学习

请求处理程序和请求参数

程序将URL映射到tornado.web.RequestHandler的子类上去。

1
2
3
4
5
6
7
8
9
10
11
12
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("You requested the main page")

class StoryHandler(tornado.web.RequestHandler):
def get(self, story_id):
self.write("You requested the story " + story_id)

application = tornado.web.Application([
(r"/", MainHandler),
(r"/story/([0-9]+)", StoryHandler),
])

get_argument() 方法获取查询字符串参数。
self.request.files 可以访问上传文件。
原始图像

在继承类中通过 self.request.arguments.items() 方法获取所有返回对象。

重写RequestHandler的方法函数

程序调用 initialize() 函数,这个函数的参数是 Application 配置中的关键字 参数定义。initialize 方法一般只是把传入的参数存 到成员变量中,而不会产生一些输出或者调用像 send_error 之类的方法。
程序调用 prepare()。无论使用了哪种 HTTP 方法,prepare 都会被调用到,因此 这个方法通常会被定义在一个基类中,然后在子类中重用。prepare可以产生输出 信息。如果它调用了finish(或send_error` 等函数),那么整个处理流程 就此结束。
程序调用某个 HTTP 方法:例如 get()、post()、put() 等。如果 URL 的正则表达式模式中有分组匹配,那么相关匹配会作为参数传入方法,见下图:
原始图像

见 code 1,RequestHandler中一些方法函数需要在其子类中重新定义handler\base.py
原始图像

get_current_user() 处理获得当前用户

重定向

通过 self.redirectRedirectHandler

1
2
3
4
5
application = tornado.wsgi.WSGIApplication([
(r"/([a-z]*)", ContentHandler),
(r"/static/tornado-0.2.tar.gz", tornado.web.RedirectHandler,
dict(url="http://github.com/downloads/facebook/tornado/tornado-0.2.tar.gz")),
], **settings)

模板

模板支持 { % 控制语句 % }{ { 表达式 } }
可以通过 extends 和 block 实现模板继承。

Cookie和Cookie安全

通过下面方式加强安全性

1
2
3
4
5
6
7
8
9
10
11
class MainHandler(tornado.web.RequestHandler):
def get(self):
if not self.get_secure_cookie("mycookie"):
self.set_secure_cookie("mycookie", "myvalue")
self.write("Your cookie was not set yet!")
else:
self.write("Your cookie was set!")

application = tornado.web.Application([
(r"/", MainHandler),
], cookie_secret="61oaBcAaaXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")

另一种配置写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MainHandler(BaseHandler):
@tornado.web.authenticated
def get(self):
name = tornado.escape.xhtml_escape(self.current_user)
self.write("Hello, " + name)

settings = {
"cookie_secret": "61oaBcAaaXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
"login_url": "/login",
}
application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
], **settings)

@tornado.web.authenticated 用于用户认证
cookie_secret用于加密cookie
login_url 记录重定向地址
xsrf_cookies 开关XSRF防范机制
原始图像

静态文件和主动式文件缓存

"static_path": os.path.join(os.path.dirname(__file__), "static")
static_url() 函数会将相对地址转成一个类似于 /static/images/logo.png?v=aae54 的 URI,v 参数是 logo.png 文件的散列值, Tornado 服务器会把它发给浏览器,并以此为依据让浏览器对相关内容做永久缓存。
由于 v 的值是基于文件的内容计算出来的,如果你更新了文件,或者重启了服务器 ,那么就会得到一个新的 v 值,这样浏览器就会请求服务器以获取新的文件内容。 如果文件的内容没有改变,浏览器就会一直使用本地缓存的文件,这样可以显著提高页 面的渲染速度。

本地化

UI模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class HomeHandler(tornado.web.RequestHandler):
def get(self):
entries = self.db.query("SELECT * FROM entries ORDER BY date DESC")
self.render("home.html", entries=entries)

class EntryHandler(tornado.web.RequestHandler):
def get(self, entry_id):
entry = self.db.get("SELECT * FROM entries WHERE id = %s", entry_id)
if not entry: raise tornado.web.HTTPError(404)
self.render("entry.html", entry=entry)

settings = {
"ui_modules": uimodules,
}
application = tornado.web.Application([
(r"/", HomeHandler),
(r"/entry/([0-9]+)", EntryHandler),
], **settings)
{% module Entry(entry, show_comments=True) %}

非阻塞式异步请求

Tornado 当中使用了 一种非阻塞式的 I/O 模型,所以你可以改变这种默认的处理行为——让一个请求一直保持 连接状态,而不是马上返回,直到一个主处理行为返回。要实现这种处理方式,只需要 使用 tornado.web.asynchronous 装饰器就可以了。

调试模式和自动重载

如果你将 debug=True 传递给 Application 构造器,该 app 将以调试模式 运行。在调试模式下,模板将不会被缓存,而这个 app 会监视代码文件的修改, 如果发现修改动作,这个 app 就会被重新加载。在开发过程中,这会大大减少 手动重启服务的次数。然而有些问题(例如 import 时的语法错误)还是会让服务器 下线,目前的 debug 模式还无法避免这些情况。

参考地址

  1. 最简单直接的是暴利遍历数组可求得最大子数组,时间复杂度为O(n^2)
  2. 采用分治策略将数组分为两个子数组去求解右如下三种情况:
    • 最大子数组在左子数组中。
    • 最大子数组在右子数组中。
    • 最大子数组跨越两个子数组中。

重点在于求最大子数组跨越两个子数组的情况。
从数组的中间点为一定点向左和向右遍历分别求得最大子数组。
然后相加得跨越两个子数组的最大子数组。

然后采用递归的方法将左子数组和右子数组继续拆分,最后当左右子数组为一个元素时结束返回。

在递归的每一层中计算完三种情况后选取当下的最大子数组情况返回。

最后得到的结果便是连续最大子数组。

采用分治策略的时间复杂度为O(nlogn)

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import random


def find_max_crossing_subarray(A, low, mid, high):
"""
求跨越两个数组的最大字数组
:param A:
:param low:
:param mid:
:param high:
:return:
"""
left_sum = A[mid]
left_index = mid
sum = 0
for left in range(mid, low - 1, -1):
sum = sum + A[left]
if sum > left_sum:
left_sum = sum
left_index = left

right_sum = A[mid + 1]
right_index = mid + 1
sum = 0
for right in range(mid + 1, high + 1):
sum = sum + A[right]
if sum > right_sum:
right_sum = sum
right_index = right
return left_index, right_index, left_sum + right_sum


def find_max_subarray(A, low, high):
"""
寻找数组中的最大子数组
:param A:
:param low:
:param high:
:return:
"""
if low == high:
return low, high, A[low]
else:
# 求中值
mid = (low + high) / 2
# 求左子数组最大子数组
left_low, left_high, left_sum = find_max_subarray(A, low, mid)
# 求右子数组最大子数组
right_low, right_high, right_sum = find_max_subarray(A, mid + 1, high)
# 求跨两个子数组的最大子数组
cross_low, cross_high, cross_sum = find_max_crossing_subarray(A, low, mid, high)
# 选出最大子数组
if left_sum >= right_sum and left_sum >= cross_sum:
return left_low, left_high, left_sum
elif right_sum >= left_sum and right_sum >= cross_sum:
return right_low, right_high, right_sum
elif cross_sum >= left_sum and cross_sum >= right_sum:
return cross_low, cross_high, cross_sum


if __name__ == "__main__":
random_list = [random.randint(-100, 100) for _ in range(100)]
print random_list
alow, ahigh, asum = find_max_subarray(random_list, 0, len(random_list) - 1)
print random_list[alow: ahigh + 1], asum

利用Python自带的包可以建立简单的web服务器。在DOS里cd到准备做服务器根目录的路径下,输入命令:
python -m Web服务器模块 [端口号,默认8000]
例如:
python -m SimpleHTTPServer 8080
然后就可以在浏览器中输入
http://localhost:端口号/路径
来访问服务器资源。
例如:
http://localhost:8080/index.htm(当然index.htm文件得自己创建)
其他机器也可以通过服务器的IP地址来访问。

这里的“Web服务器模块”有如下三种:

  • BaseHTTPServer: 提供基本的Web服务和处理器类,分别是HTTPServer和BaseHTTPRequestHandler。
  • SimpleHTTPServer: 包含执行GET和HEAD请求的SimpleHTTPRequestHandler类。
  • CGIHTTPServer: 包含处理POST请求和执行CGIHTTPRequestHandler类。

平均时间复杂度均为O(n^2)的排序算法:

插入排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# -*- coding:utf-8 -*-
# 插入排序,两层遍历,以一个位置为基准,不断向前遍历,将比基准位置大的数调整到基准位置。
def insertion_sort(sort_list):
iter_len = len(sort_list)
if iter_len < 2:
return sort_list
for i in range(1, iter_len):
key = sort_list[i]
j = i - 1
while j>=0 and sort_list[j]>key:
sort_list[j+1] = sort_list[j]
j -= 1
sort_list[j+1] = key
return sort_list
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
print insertion_sort(sort_list)

冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
def bubble_sort(sort_list):
iter_len = len(sort_list)
if iter_len < 2:
return sort_list
for i in range(iter_len-1):
for j in range(iter_len-i-1):
if sort_list[j] > sort_list[j+1]:
sort_list[j], sort_list[j+1] = sort_list[j+1], sort_list[j]
return sort_list
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
print bubble_sort(sort_list)

选择排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding:utf-8 -*-
# 向后遍历,选择最小值进行交换。
def selection_sort(sort_list):
iter_len = len(sort_list)
if iter_len < 2:
return sort_list
for i in range(iter_len-1):
smallest = sort_list[i]
location = i
for j in range(i, iter_len):
if sort_list[j] < smallest:
smallest = sort_list[j]
location = j
if i != location:
sort_list[i], sort_list[location] = sort_list[location], sort_list[i]
return sort_list
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
print selection_sort(sort_list)

归并排序

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
class Merge_sort(object):
def _merge(self, alist, p, q, r):
left = alist[p:q+1]
right = alist[q+1:r+1]
for i in range(p, r+1):
if len(left)>0 and len(right)>0:
if left[0]<=right[0]:
alist[i] = left.pop(0)
else:
alist[i] = right.pop(0)
elif len(right)==0:
alist[i] = left.pop(0)
elif len(left)==0:
alist[i] = right.pop(0)

def _merge_sort(self, alist, p, r):
if p<r:
q = int((p+r)/2)
self._merge_sort(alist, p, q)
self._merge_sort(alist, q+1, r)
self._merge(alist, p, q, r)

def __call__(self, sort_list):
self._merge_sort(sort_list, 0, len(sort_list)-1)
return sort_list
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
merge = Merge_sort()
print merge(sort_list)

堆排序

堆排序,是建立在数据结构——堆上的。关于堆的基本概念、以及堆的存储方式这里不作介绍。这里用一个列表来存储堆(和用数组存储类似),对于处在i位置的元素,2i+1位置上的是其左孩子,2i+2是其右孩子,类似得可以得出该元素的父元素。
首先我们写一个函数,对于某个子树,从根节点开始,如果其值小于子节点的值,就交换其值。用此方法来递归其子树。接着,我们对于堆的所有非叶节点,自下而上调用先前所述的函数,得到一个树,对于每个节点(非叶节点),它都大于其子节点。(其实这是建立最大堆的过程)在完成之后,将列表的头元素和尾元素调换顺序,这样列表的最后一位就是最大的数,接着在对列表的0到n-1部分再调用以上建立最大堆的过程。最后得到堆排序完成的列表。

快速排序

首先要用到的是分区工具函数(partition),对于给定的列表(数组),我们首先选择基准元素(这里我选择最后一个元素),通过比较,最后使得该元素的位置,使得这个运行结束的新列表(就地运行)所有在基准元素左边的数都小于基准元素,而右边的数都大于它。然后我们对于待排的列表,用分区函数求得位置,将列表分为左右两个列表(理想情况下),然后对其递归调用分区函数,直到子序列的长度小于等于1。

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
class Quick_sort(object):
def _partition(self, alist, p, r):
i = p-1
x = alist[r]
for j in range(p, r):
if alist[j]<=x:
i += 1
alist[i], alist[j] = alist[j], alist[i]
alist[i+1], alist[r] = alist[r], alist[i+1]
return i+1

def _quicksort(self, alist, p, r):
if p<r:
q = self._partition(alist, p, r)
self._quicksort(alist, p, q-1)
self._quicksort(alist, q+1, r)

def __call__(self, sort_list):
self._quicksort(sort_list, 0, len(sort_list)-1)
return sort_list
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
quick = Quick_sort()
print quick(sort_list)

Python对于递归深度做了限制,默认值为1000,可以通过设置修改深度。

1
2
import sys
sys.setrecursionlimit(99999)

另外一种是随机化分区函数。由于之前我们的选择都是子序列的最后一个数,因此对于特殊情况的健壮性就差了许多。现在我们随机从子序列选择基准元素,这样可以减少对特殊情况的差错率。

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
import random
class Random_quick_sort(object):

def _randomized_partition(self, alist, p, r):
i = random.randint(p, r)
alist[i], alist[r] = alist[r], alist[i]
return self._partition(alist, p, r)
def _partition(self, alist, p, r):
i = p-1
x = alist[r]
for j in range(p, r):
if alist[j]<=x:
i += 1
alist[i], alist[j] = alist[j], alist[i]
alist[i+1], alist[r] = alist[r], alist[i+1]
return i+1
def _quicksort(self, alist, p, r):
if p<r:
q = self._randomized_partition(alist, p, r)
self._quicksort(alist, p, q-1)
self._quicksort(alist, q+1, r)

def __call__(self, sort_list):
self._quicksort(sort_list, 0, len(sort_list)-1)
return sort_list
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
random_quick = Random_quick_sort()
print random_quick(sort_list)

Python风格快速排序算法

1
2
3
4
5
6
7
8
9
10
def quick_sort_2(sort_list):
if len(sort_list)<=1:
return sort_list
return quick_sort_2([lt for lt in sort_list[1:] if lt<sort_list[0]]) + \
sort_list[0:1] + \
quick_sort_2([ge for ge in sort_list[1:] if ge>=sort_list[0]])
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
print quick_sort_2(sort_list)

计数排序

计数排序的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改。
假设输入的线性表L的长度为n,L=L1,L2,..,Ln;线性表的元素属于有限偏序集S,|S|=k且k=O(n),S={S1,S2,..Sk};则计数排序可以描述如下:
1、扫描整个集合S,对每一个Si∈S,找到在线性表L中小于等于Si的元素的个数T(Si);
2、扫描整个线性表L,对L中的每一个元素Li,将Li放在输出线性表的第T(Li)个位置上,并将T(Li)减1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Counting_sort(object):
def _counting_sort(self, alist, k):
alist3 = [0 for i in range(k)]
alist2 = [0 for i in range(len(alist))]
for j in alist:
alist3[j] += 1
for i in range(1, k):
alist3[i] = alist3[i-1] + alist3[i]
for l in alist[::-1]:
alist2[alist3[l]-1] = l
alist3[l] -= 1
return alist2

def __call__(self, sort_list, k=None):
if k is None:
import heapq
k = heapq.nlargest(1, sort_list)[0] + 1
return self._counting_sort(sort_list, k)
if __name__ == "__main__":
sort_list = [4,2,7,3,1,9,33,25,46,21,45,22]
print sort_list
counting = Counting_sort()
print counting(sort_list)

排序算法用于研究其思想,具体的应用需要根据实际环境进行修改,但是要遵循以下规则。
当需要排序的时候,尽量设法使用内建Python列表的sort方法。
当需要搜索的时候,尽量设法使用内建的字典。

装饰器模式定义:动态地给一个对象添加一些额外的职责。

在 Python 中 Decorator Mode 可以按照像其它编程语言如 C++、Java 等的样子来实现,但是 Python 在应用装饰概念方面的能力上远不止于此, Python 提供了一个语法和一个编程特性来加强这方面的功能。

首先需要了解一下 Python 中闭包的概念:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

dec1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def makeblod(fn):
def wrapped():
return '<b>'+fn()+'</b>'
return wrapped

def makeitalic(fn):
def wrapped():
return '<i>'+fn()+'</i>'
return wrapped

@makeblod
@makeitalic
def hello():
return 'hello world'

print hello()

dec2

1
2
3
4
5
6
7
8
9
10
11
12
13
def deco(arg):
def _deco(func):
def __deco():
print "before %s called [%s]." % (func.__name__, arg)
func()
print "after %s called [%s]." % (func.__name__, arg)
return __deco
return _deco

@deco("mymodule")
def myfunc():
print "myfunc() called."
myfunc()

闭包学习:

http://blog.csdn.net/marty_fu/article/details/7679297

接收参数的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import time

def decorator(run_count):
def _decorator(fun):
def wrapper(*args, **kwargs):
start = time.time()
for i in xrange(run_count):
fun(*args, **kwargs)
runtime = time.time() - start
print runtime
return wrapper
return _decorator

@decorator(2)
def do_something(name):
time.sleep(0.1)
print "play game " + name

do_something("san guo sha")

装饰器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time

class decorator(object):
def __init__(self, count):
self._count = count

def __call__(self, fun):
self.fun = fun
return self.call_fun

def call_fun(self, *args, **kwargs):
start = time.time()
for _ in range(self._count):
self.fun(*args, **kwargs)
runtime = time.time() - start
print runtime

@decorator(2)
def do_something():
time.sleep(0.1)
print "play game"

do_something()

SQL连接可以分为内连接、外连接、交叉连接。

数据库数据:
book表
stu表

内连接

  • 等值连接:在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列。
  • 不等值连接:在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括>、>=、<=、<、!>、!<和<>。
  • 自然连接:在连接条件中使用等于(=)运算符比较被连接列的列值,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。

内连接:内连接查询操作列出与连接条件匹配的数据行,它使用比较运算符比较被连接列的列值。
select * from book as a,stu as b where a.sutid = b.stuidselect * from book as a inner join stu as b on a.sutid = b.stuid

内连接可以使用上面两种方式,其中第二种方式的inner可以省略。

stu表

其连接结果如上图,是按照a.stuid = b.stuid进行连接。

外连接

  • 左联接:是以左表为基准,将a.stuid = b.stuid的数据进行连接,然后将左表没有的对应项显示,右表的列为NULL
    select * from book as a left join stu as b on a.sutid = b.stuid

stu表

  • 右连接:是以右表为基准,将a.stuid = b.stuid的数据进行连接,然以将右表没有的对应项显示,左表的列为NULL
    select * from book as a right join stu as b on a.sutid = b.stuid

stu表

  • 全连接:完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。
    select * from book as a full outer join stu as b on a.sutid = b.stuid

stu表

交叉连接

交叉连接:交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。
select * from book as a cross join stu as b order by a.id

stu表

伪彩色处理是指将灰度图像转换成彩色图象。因为人眼对于彩色的分辨能力远高于对灰度图像的分辨能力,所以将灰度图像转换成彩色可以提高人眼对图像细节的辨别能力。伪彩色并不能真实的反映图像像的彩色情况。

效果图:

强度分层法和灰度级-彩色变换法:
(1)强度分层法是伪彩色处理技术中最简单的一种。
在某个灰度级Li上设置一个平行于x-y平面的切割平面,切割平面下面的,即灰度级小于Li的像素分配给一种颜色,相应的切割平面上大于灰度级Li的像素分配给另一种颜色。这样切割结果可以分成两层的伪彩色。可以使用M个平面去切割,就会得到M个不同灰度级的区域,这样就是具有M种颜色的为彩色图像。这种方法虽然简单,但是视觉效果不理想。
(2)灰度级-彩色变换法可以将灰度图像变为具有多种颜色渐变的连续彩色图像。
主要就是将图像通过不同变换特性的红、绿、蓝3个变换器,然后将三个颜色通道的输出合成某种颜色。由于三种颜色变换的不同,使得不同大小灰度级可以合成不同的颜色。一组典型的变换传递函数如下图。

这里面需要注意的地方,代码只能是处理JPG格式的灰度图像,因为JPG图像的颜色深度是24位表示(R,G,B),每像素由3个字节表示即可,然而PNG图像的颜色深度是32位表示(R,G,B,A)。

下面的代码是测试代码,以处理24位深度的图像为例,同像素不同通道的颜色值要相同,组合表示出是具有一定灰度的颜色。在实际应用中需要修改下面的代码依据要处理的图像格式。

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#region 伪彩色图像处理

/// <summary>
/// 伪彩色图像处理
/// 博客园-初行 http://www.cnblogs.com/zxlovenet
/// 日期:2014.2.14
/// </summary>
/// <param name="bmp">传入的灰度图像</param>
/// <param name="method">使用何种方法,false强度分层法,true灰度级-彩色变换法</param>
/// <param name="seg">强度分层中的分层数</param>
/// <returns>返回伪彩色图像</returns>
private Bitmap gcTrans(Bitmap bmp, bool method, byte seg)
{
if (bmp != null)
{
if (System.Drawing.Imaging.PixelFormat.Format24bppRgb == bmp.PixelFormat)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = bmp.Width * bmp.Height * 3;
byte[] grayValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
bmp.UnlockBits(bmpData);

byte[] rgbValues = new byte[bytes];
//清零
Array.Clear(rgbValues, 0, bytes);
byte tempB;

if (method == false)
{
//强度分层法
for (int i = 0; i < bytes; i += 3)
{
byte ser = (byte)(256 / seg);
tempB = (byte)(grayValues[i] / ser);
//分配任意一种颜色
rgbValues[i + 1] = (byte)(tempB * ser);
rgbValues[i] = (byte)((seg - 1 - tempB) * ser);
rgbValues[i + 2] = 0;
}
}
else
{
//灰度级-彩色变换法
for (int i = 0; i < bytes; i += 3)
{
if (grayValues[i] < 64)
{
rgbValues[i + 2] = 0;
rgbValues[i + 1] = (byte)(4 * grayValues[i]);
rgbValues[i] = 255;
}
else if (grayValues[i] < 128)
{
rgbValues[i + 2] = 0;
rgbValues[i + 1] = 255;
rgbValues[i] = (byte)(-4 * grayValues[i] + 2 * 255);
}
else if (grayValues[i] < 192)
{
rgbValues[i + 2] = (byte)(4 * grayValues[i] - 2 * 255);
rgbValues[i + 1] = 255;
rgbValues[i] = 0;
}
else
{
rgbValues[i + 2] = 255;
rgbValues[i + 1] = (byte)(-4 * grayValues[i] + 4 * 255);
rgbValues[i] = 0;
}
}

}

bmp = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
ptr = bmpData.Scan0;

System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
bmp.UnlockBits(bmpData);

return bmp;
}
else
{
return null;
}
}
else
{
return null;
}
}
#endregion

颜色映射:

颜色映射的方法需要做一个颜色映射表,不同灰度级都会有对应的颜色。这个跟强度分层法相似,可以分成不同的层次,对应的颜色可以根据实际情况做映射。
在实际应用中,热成像测温系统所产生的红外图像为黑白灰度级图像,灰度值动态范围不大,人眼很难从这些灰度级中获得丰富的信息。为了更直观地增强显示图像的层次,提高人眼分辨能力,对系统所摄取的图像进行伪彩色处理,从而达到图像增强的效果,使图像信息更加丰富。例如对受热物体所成的像进行伪彩色时,将灰度低的区域设置在蓝色附近(或蓝灰、黑等),而灰度级高的区域设置在红色附近(或棕红、白等),以方便人们对物体的观察。

下面几张图片是在实际应用中的情况(图片来源网络,侵删):


xmind文件

ipython:
sudo pip install ipython

ipython notebook:
sudo pip install notebook

Pycharm


交易过程:
1. 客户下单
2. 客户完成支付
3. 商家接单
4. 商家发货

从软件开发角度, 还有一些非功能性需求需要实现:
1. 性能: 特别是秒杀的时候,如何满足高频率的支付需求?
2. 可靠性:不用说,系统能达到几个9,是衡量软件设计功力的重要指标。 99%是基础, 99.999%是目标,更多的9哪就是神了。
3. 易用性:支付中多一个步骤,就会流失至少2%的用户。 产品经理都在削尖脑袋想想怎么让用户赶紧掏钱。
4. 可扩展性: 近年来支付业务创新产品多,一元购、红包、打赏等,还有各种的支付场景。 怎么能够快速满足产品经理的需求,尽快上线来抢占市场,可扩展性对支付系统设计也是一个挑战。
5. 可伸缩性:为了支持公司业务,搞一些促销活动是必须的。 那促销带来的爆发流量,最佳应对方法就是加机器了。 平时流量低,用不了那么多机器,该释放的就释放掉了, 给公司省点钱。

典型支付系统架构:

某旅游公司:

京东金融:

支付系统一般会提供如下子系统:
1. 支付应用和产品.(应用层): 这是针对各端(PC Web端、android、IOS)的应用和产品。 为各个业务系统提供收银台支持,同时支付作为一个独立的模块,可以提供诸如银行卡管理、理财、零钱、虚拟币管理、交易记录查阅、卡券等功能;
2. 支付运营系统(应用层): 支付系统从安全的角度来说,有一个重要的要求是,懂代码的不碰线上,管运营的不碰代码。这对运营系统的要求就很高,要求基本上所有线上的问题,都可以通过运营系统来解决。
3. 支付BI系统(应用层): 支付中产生大量的数据,对这些数据进行分析, 有助于公司老板们了解运营状况,进行决策支持。
4. 风控系统(应用层):这是合规要求的风险控制、反洗钱合规等。
5. 信用信息管理系统(应用层):用来支持对信用算法做配置,对用户的信用信息做管理。
支付系统一般会提供如下子系统:
1. 支付应用和产品.(应用层): 这是针对各端(PC Web端、android、IOS)的应用和产品。 为各个业务系统提供收银台支持,同时支付作为一个独立的模块,可以提供诸如银行卡管理、理财、零钱、虚拟币管理、交易记录查阅、卡券等功能;
2. 支付运营系统(应用层): 支付系统从安全的角度来说,有一个重要的要求是,懂代码的不碰线上,管运营的不碰代码。这对运营系统的要求就很高,要求基本上所有线上的问题,都可以通过运营系统来解决。
3. 支付BI系统(应用层): 支付中产生大量的数据,对这些数据进行分析, 有助于公司老板们了解运营状况,进行决策支持。
4. 风控系统(应用层):这是合规要求的风险控制、反洗钱合规等。
5. 信用信息管理系统(应用层):用来支持对信用算法做配置,对用户的信用信息做管理。

http://www.bijishequ.com/detail/95641