Focus on self

Before changing the wold, I will figure out who I am.


  • Home

  • Categories

  • Tags

  • Archives

matplotlib.pyplot.draw绘制动画时异常

Posted on 2020-02-06 | In python作图

matplotlib.pyplot.draw绘制动画时异常

1. 问题

在玩《python极客项目编程》中的吉他声音模拟时,会将声音的震动图像画出来,但使用matplotlib.pyplot.draw画图时,出现了没有任何图象被绘制出来的情况。

2. 原因

《python极客项目编程》提供的代码没有问题,但是这是相对于它使用的matplotlib的版本来说没问题。

  • 早期draw()函数是同步更新界面的,即调用函数后就会立刻绘制
  • 后来的版本却变成了空闲异步更新界面,即等到有时间了才会绘制

3. 解决方案

在draw()函数后,加一个pause()函数来给一个空闲时间,让它有时间绘制。

如何在深度学习中使用开源Chinese Word Vectors

Posted on 2020-01-12 | In NLP

如何在深度学习中使用开源Chinese Word Vectors

摘要:Chinese-Word-Vectors开源项目提供了100多种预训练模型,但在深度学习中使用时,加载预训练向量存在词表重复项问题。本文着重于解决加载问题。

1. 起因

去年半年一直在搭建我的NLP练习项目——为语音识别文本进行标点恢复,使用的技术如下所示:

  • 词向量训练
  • BiLSTM
  • CRF

但是上面的技术在训练网络的时候,词向量是在训练中不断训练得到的。一方面这样的词向量更配合网络的结构,具有任务特定性;但是另一方面,受限于语料大小和计算资源,直接由自己的数据集训练出的词向量肯定是不够泛化,不够强健的。

2. Chinese-Word-Vectors技术方案存在的问题

时至今日,在2019年bert横扫NLP任务之后,使用预训练模型已经不再稀奇。使用预训练的模型可以用更少的训练资源得到较好的效果。即使是使用传统的word2vec也能有效提高模型的泛化性。

Chinese-Word-Vectors是北京师范大学和人民大学的研究者开源出来的100多个中文预训练词向量,所有向量都是在word2vec和skip-gram上训练出来的。

久仰大名,码下很久,但是未尝亲自试用。亲自使用后,便发现了一些问题。

  • 如何读取从Chinese-Word-Vectors下载下来的词向量?
  • 读取时发现词表有重复,导致存入python字典中后,导致词表大小和训练好的词向量矩阵不一致?
  • 读取到的词向量矩阵如何载入到深度学习模型的词嵌入矩阵embedding中?

果然纸上得来终觉浅,绝知此事要躬行。

3. 问题解决方式

  1. 词向量文件本身是以文本方式存储的,第一行是词向量size信息,后面每一行是每个词和它的词向量。通过使用ngram2vec工具中的代码可以加载词向量(Chinese-Word-Vectors也使用了ngram2vec工具来训练):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def load_dense(path):
vocab_size, size = 0, 0
vocab = {}
vocab["i2w"], vocab["w2i"] = [], {}
with codecs.open(path, "r", "utf-8") as f:
first_line = True
for line in f:
if first_line:
first_line = False
vocab_size = int(line.strip().split()[0])
size = int(line.rstrip().split()[1])
matrix = np.zeros(shape=(vocab_size, size), dtype=np.float32)
continue
vec = line.strip().split()
vocab["i2w"].append(vec[0])
# vocab的length不断增长
matrix[len(vocab["i2w"])-1, :] = np.array([float(x) for x in vec[1:]])
for i, w in enumerate(vocab["i2w"]):
vocab["w2i"][w] = i
return matrix, vocab, size
  1. 词表重复问题,是实际加载词向量中遇到的比较麻烦的问题,重复的词表导致无法用字典来索引每个词对应的词向量,所以上一步的词向量加载,实际上应该考虑重复问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def load_dense_drop_repeat(path):
vocab_size, size = 0, 0
vocab = {}
vocab["i2w"], vocab["w2i"] = [], {}
count = 0
with codecs.open(path, "r", "utf-8") as f:
first_line = True
for line in f:
if first_line:
first_line = False
vocab_size = int(line.strip().split()[0])
size = int(line.rstrip().split()[1])
matrix = np.zeros(shape=(vocab_size, size), dtype=np.float32)
continue
vec = line.strip().split()
if not vocab["w2i"].__contains__(vec[0]):
vocab["w2i"][vec[0]] = count
matrix[count, :] = np.array([float(x) for x in vec[1:]])
count += 1
for w, i in vocab["w2i"].items():
vocab["i2w"].append(w)
return matrix, vocab, size, len(vocab["i2w"])
  1. 如何将得到的此向量矩阵matrix载入到torch中的embedding中?(上一步中,为了减少每次读matrix的耗时,可以将matrix用numpy保存到npy文件):
1
2
3
4
5
emb = np.load(emb)
print('emb的shape:', emb.shape)
self.embedding = nn.Embedding(vocab_size, embedding_size)
self.embedding.weight.data.copy_(torch.from_numpy(emb))
self.embedding.weight.requires_grad = True

4. 总结

总的来看Chinese-Word-Vectors预训练数据是有其价值的,减少了很多的训练资源。但是由于自然语言处理的文本本身具有非常大的噪声,很难保证词向量是完美的、不包含任何错字和重复。

在使用Chinese-Word-Vectors过程中,尽量要匹配好自己的需求。

通用论坛正文提取

Posted on 2020-01-12 | In Web spiders

本人长期出售超大量微博数据、旅游网站评论数据,并提供各种指定数据爬取服务,Message to YuboonaZhang@Yahoo.com。同时欢迎加入社交媒体数据交流群:99918768

背景

参加泰迪杯数据挖掘竞赛,这次真的学习到了不少东西,最后差不多可以完成要求的内容,准确率也还行。总共的代码,算上中间的过程处理也不超过500行,代码思想也还比较简单,主要是根据论坛的短文本特性和楼层之间内容的相似来完成的。(通俗点说就是去噪去噪去噪,然后只留下相对有规律的日期,内容)

前期准备

  1. 软件和开发环境: Pycharm,Python2.7,Linux系统

  2. 用的主要Python包: jieba, requests, BeautifulSoup, goose, selenium, PhantomJS, pymongo等(部分软件的安装我前面的博客有介绍)

网页预处理

首先因为网站很多是动态的,直接用bs4是获取不到有些信息的,所以我们使用selenium和phantomjs将文件保存在本地,然后再处理。

相关的代码是

1
2
3
4
5
6
7
8
9
10
11
def save(baseUrl):
driver = webdriver.PhantomJS()
driver.get(baseUrl) # seconds
try:
element = WebDriverWait(driver, 10).until(isload(driver) is True)
except Exception, e:
print e
finally:
data = driver.page_source # 取到加载js后的页面content
driver.quit()
return data

由于网页中存在着大量的噪音(广告,图片等),首先我们需要将与我们所提取内容不一致的所有噪声尽可能去除。我们首先选择将一些带有典型噪声意义的噪声标签去除,比如script等,方法我们选择BeautifulSoup来完成。

代码大概是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for element in soup(text=lambda text: isinstance(text, Comment)):
element.extract()

[s.extract() for s in soup('script')]
[s.extract() for s in soup('meta')]
[s.extract() for s in soup('style')]
[s.extract() for s in soup('link')]
[s.extract() for s in soup('img')]
[s.extract() for s in soup('input')]
[s.extract() for s in soup('br')]
[s.extract() for s in soup('li')]
[s.extract() for s in soup('ul')]

print (soup.prettify())

处理之后的网页对比

之前

之后

可以看出网页噪声少了很多,但是还是不足以从这么多噪声中提取出我们所要的内容

由于我们不需要标签只需要标签里面的文字,所以我们可以利用BeautifulSoup提取出文字内容再进行分析

1
2
3
4
for string in soup.stripped_strings:
print(string)
with open(os.path.join(os.getcwd())+"/data/3.txt", 'a') as f:
f.writelines(string.encode('utf-8')+'\n')

去除噪声标签之后的信息

可以看出来还是非常杂乱,但是又是十分有规律的。我们可以发现每个楼层中的文本内容实质上都差不多,可以说重复的很多,而且都是一些特定的词,比如: 直达楼层, 板凳,沙发,等这类的词,所以我们需要将这些词删掉然后再进行分析

我所用的方法是利用jieba分词来对获取的网页文本进行分词,统计出出现词频最高的词,同时也是容易出现在噪声文章中的词语,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import jieba.analyse

text = open(r"./data/get.txt", "r").read()

dic = {}
cut = jieba.cut_for_search(text)

for fc in cut:
if fc in dic:
dic[fc] += 1
else:
dic[fc] = 1
blog = jieba.analyse.extract_tags(text, topK=1000, withWeight=True)

for word_weight in blog:
# print (word_weight[0].encode('utf-8'), dic.get(word_weight[0], 'not found'))
with open('cut.txt', 'a') as f:
f.writelines(word_weight[0].encode('utf-8') + " " + str(dic.get(word_weight[0], 'not found')) + '\n')

统计出来然后经过我们测试和筛选得出的停用词有这些

回帖
积分
帖子
登录
论坛
注册
离线
时间
作者
签到
主题
精华
客户端
手机
下载
分享

目前统计的词大约200左右。

然后还有去除重复文本的工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 去重函数
def remove_dup(items):
pattern1 = re.compile(r'发表于')
pattern2 = re.compile('\d{4}-\d{1,2}-\d{1,2} \d{2}:\d{2}:\d{2}')
pattern3 = re.compile('\d{1,2}-\d{1,2} \d{2}:\d{2}')
pattern4 = re.compile('\d{4}-\d{1,2}-\d{1,2} \d{2}:\d{2}')
pattern5 = re.compile(r'[^0-9a-zA-Z]{7,}')

# 用集合来作为容器,来做一部分的重复判断依据,另外的部分由匹配来做
# yield用于将合适的文本用生成器得到迭代器,这样就进行了文本的删除,在函数外面
# 可以用函数进行文本的迭代
seen = set()
for item in items:
match1 = pattern1.match(item)
match2 = pattern2.match(item)
match3 = pattern3.match(item)
match4 = pattern4.match(item)
match5 = pattern5.match(item)
if item not in seen or match1 or match2 or match3 or match4 or match5:
yield item
seen.add(item) # 向集合中加入item,集合会自动化删除掉重复的项目

在经过观察处理后的网页文本,我们发现还有一项噪声无法忽略,那就是纯数字。因为网页文本中有很多纯数字但是又不重复,比如点赞数等,所以我准备用正则匹配出纯数字然后删除。但是这样就会出现问题…因为有些用户名是纯数字的,这样我们会把用户名删掉的。为了解决这个问题我们使用保留字符数大于7的纯数字,这样既删除了大部分的没用信息又尽可能的保留了用户名

相关的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
st = []
for stop_word in stop_words:
st.append(stop_word.strip('\n'))
t = tuple(st)
# t,元组,和列表的区别是,不能修改使用(,,,,),与【,,,】列表不同
lines = []
# 删除停用词和短数字实现
for j in after_string:
# 如果一行的开头不是以停用词开头,那么读取这一行
if not j.startswith(t):
# 如何一行不全是数字,或者这行的数字数大于7(区别无关数字和数字用户名)读取这一行
if not re.match('\d+$', j) or len(j) > 7:
lines.append(j.strip())
# 删除所有空格并输出
print (j.strip())

处理之后的文本如下,规律十分明显了

去除噪声标签之后的信息

接下来就是我们进行内容提取的时候了

内容提取

内容提取无非是找到评论块,而评论块在上面我们的图中已经十分清晰了,我们自然而然的想到根据日期来区分评论块。经过观察,所有的论坛中日期的形式只有5种(目前只看到5种,当然后期可以加上)。我们可以用正则匹配出日期所在的行,根据两个日期所在行数的中间所夹的就是评论内容和用户名来完成我们的评论内容提取。

传入我们处理后的文本然后就匹配出日期所在行数

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
# 匹配日期返回get_list
def match_date(lines):
pattern1 = re.compile(r'发表于')
pattern2 = re.compile('\d{4}-\d{1,2}-\d{1,2} \d{2}:\d{2}:\d{2}')
pattern3 = re.compile('\d{1,2}-\d{1,2} \d{2}:\d{2}')
pattern4 = re.compile('\d{4}-\d{1,2}-\d{1,2} \d{2}:\d{2}')
pattern5 = re.compile(r'发表日期')

pre_count = -1
get_list = []

# 匹配日期文本
for string in lines:
match1 = pattern1.match(string)
match2 = pattern2.match(string)
match3 = pattern3.match(string)
match4 = pattern4.match(string)
match5 = pattern5.match(string)
pre_count += 1
if match1 or match2 or match3 or match4 or match5:
get_dic = {'count': pre_count, 'date': string}
get_list.append(get_dic)

# 返回的是匹配日期后的信息
return get_list

因为有回帖和没有回帖处理方式也不一样所以我们需要分类进行讨论。因为我们知道评论的内容是在两个匹配日期的中间,这样就有一个问题就是最后一个评论的内容区域不好分。但是考虑到大部分的最后一个回帖都是一行我们可以暂取值为3(sub==3,考虑一行评论和一行用户名),后来想到一种更为科学的方法,比如判断后面几行的文本密度,如果很小说明只有一行评论的可能性更大。

下面的代码是获取日期所在行数和两个日期之间的行数差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 返回my_count
def get_count(get_list):
my_count = []
date = []
# 获取时间所在行数
for i in get_list:
k, t = i.get('count'), i.get('date')
my_count.append(k)
date.append(t)
if len(get_list) > 1:
# 最后一行暂时取3
my_count.append(my_count[-1] + 3)
return my_count
else:
return my_count

# 获取两个时间所在的行数差
def get_sub(my_count):
sub = []
for i in range(len(my_count) - 1):
sub.append(my_count[i + 1] - my_count[i])
return sub

接下来就要分类讨论了

  1. 如果只有楼主没有评论(即my——count==1),这个时候我们可以使用开源的正文提取软件goose来提取正文。

  2. 如果有评论我们就需要根据sub的值来进行分类如果sub==2占多数(或者说比sub==3)占的多,那么我们就认为可能是用户名被删掉,删掉的原因有很多,比如去重的时候有人在楼中楼回复了导致用户名重复被删除,有可能该网站的标签比较特殊用户名在去标签的时候删除等,情况比较复杂且出现的频率不太高,暂未考虑。何况不影响我们提取评论内容,只需分类出来考虑就行


注意:下面余弦相似度这个是我开始的时候想多了!大部分情况就是:日期-评论-用户名,后来我没有考虑余弦相似度分类,代码少了,精度也没有下降。这里不删是想留下一个思考的过程。代码看看就好,最后有修改后的源码。
  1. 还有就是最常见的内容,就是sub==3占多数的情况。因为大部分的评论都是一行文本,所以我们需要考虑的的是sub==3的时候获取的评论文本在哪一行。通俗来说就是这三行的内容是日期-评论-用户名,还是日期-用户名-评论呢?虽然大部分是第一种情况,但是第二种情况我们也不能忽略。怎么判断这两种情况呢?这确实让我思考了很长一段时间,后来想到可以用余弦相似度来解决这个问题.科普余弦相似度可以看这里。简单来说就是用户名的长度都是相似的,但是评论的内容长度差异就非常大了。比如用户名长度都是7个字符左右,但是评论的长度可以数百,也可以只有一个。所以我们可以两两比较余弦相似度,然后取平均,相似度大的就是用户名了。这样我们就可以区分出评论内容进行提取了!这就是主要的思想。剩下的就是代码的实现了。

简单贴一下相关的代码

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
# 利用goose获取正文内容
def goose_content(my_count, lines, my_url):
g = Goose({'stopwords_class': StopWordsChinese})
content_1 = g.extract(url=my_url)
host = {}
my_list = []
host['content'] = content_1.cleaned_text
host['date'] = lines[my_count[0]]
host['title'] = get_title(my_url)
result = {"post": host, "replys": my_list}
SpiderBBS_info.insert(result)

# 计算余弦相似度函数
def cos_dist(a, b):
if len(a) != len(b):
return None
part_up = 0.0
a_sq = 0.0
b_sq = 0.0
for a1, b1 in zip(a, b):
part_up += a1 * b1
a_sq += a1 ** 2
b_sq += b1 ** 2
part_down = math.sqrt(a_sq * b_sq)
if part_down == 0.0:
return None
else:
return part_up / part_down

# 判断评论内容在哪一行(可能在3行评论块的中间,可能在三行评论块的最后)
def get_3_comment(my_count, lines):
get_pd_1 = []
get_pd_2 = []
# 如果间隔为3取出所在行的文本长度
test_sat_1 = []
test_sat_2 = []
for num in range(len(my_count)-1):
if my_count[num+1] - 3 == my_count[num]:
pd_1 = (len(lines[my_count[num]]), len(lines[my_count[num]+2]))
get_pd_1.append(pd_1)
pd_2 = (len(lines[my_count[num]]), len(lines[my_count[num]+1]))
get_pd_2.append(pd_2)

for i_cos in range(len(get_pd_1)-1):
for j_cos in range(i_cos+1, len(get_pd_1)):
# 计算文本余弦相似度
test_sat_1.append(cos_dist(get_pd_1[j_cos], get_pd_1[i_cos]))
test_sat_2.append(cos_dist(get_pd_2[j_cos], get_pd_2[i_cos]))

# 计算余弦相似度的平均值
get_mean_1 = numpy.array(test_sat_1)
print (get_mean_1.mean())
get_mean_2 = numpy.array(test_sat_2)
print (get_mean_2.mean())

# 比较大小返回是否应该按
if get_mean_1.mean() >= get_mean_2.mean():
return 1
elif get_mean_1.mean() < get_mean_2.mean():
return 2

# 获取评论内容
def solve__3(num, my_count, sub, lines, my_url):
# 如果get_3_comment()返回的值是1,那么说明最后一行是用户名的可能性更大,否则第一行是用户名的可能性更大
if num == 1:
host = {}
my_list = []
host['content'] = ''.join(lines[my_count[0]+1: my_count[1]+sub[0]-1])
host['date'] = lines[my_count[0]]
host['title'] = get_title(my_url)
for use in range(1, len(my_count)-1):
pl = {'content': ''.join(lines[my_count[use] + 1:my_count[use + 1] - 1]), 'date': lines[my_count[use]],
'title': get_title(my_url)}
my_list.append(pl)

result = {"post": host, "replys": my_list}
SpiderBBS_info.insert(result)

if num == 2:
host = {}
my_list = []
host['content'] = ''.join(lines[my_count[0]+2: my_count[1]+sub[0]])
host['date'] = lines[my_count[0]]
host['title'] = get_title(my_url)
for use in range(1, len(my_count) - 1):
pl = {'content': ''.join(lines[my_count[use] + 2:my_count[use + 1]]), 'date': lines[my_count[use]],
'title': get_title(my_url)}
my_list.append(pl)

result = {"post": host, "replys": my_list}
SpiderBBS_info.insert(result)

展望

提取的准确率应该要分析更多的bbs网站,优化删除重复词(太粗暴),优化停用词,针对短文本没回复情况的优化,准确提取楼主的用户名等,无奈时间太紧无法进一步优化。才疏学浅,刚学了几个月python,代码难免有不合理的地方,望各位提出宝贵意见。

使用Dlib、PyQt搭建人脸识别系统

Posted on 2020-01-12

使用Dlib、PyQt搭建人脸识别系统

1、软硬件需求

  1. 开发及实验平台(windows也是一样的)
    Ubuntu 16.04.1 x64;内核版本:4.8.0-36-generic

  2. 软件配置
    数据库: Python 模块Sqlite3版本:3.11.0
    Python版本:3.5
    PyQt5版本:5.10.1
    Python模块Dlib版本:19.9.0
    Python模块Opencv版本:3.4.0.12
    Python 模块face-recognition版本:1.2.2
    Python模块 numpy版本:1.14.2
    Python模块 pandas版本:0.22.0

  3. 硬件
    测试机:thinkpad E440
    摄像头:电脑自带720p HD摄像头

注意:**所有软件配置中python模块的安装都可以使用

insatll '模块名称'```完成,[pip安装方式][1],但是Dib安装的时候需要系统满足一定条件才能安装,[ubuntu安装Dlib][2]/[windows安装Dlib][3]**
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

## 2、什么是PyQt

PyQt是一个图形化软件开发的库,基于python,使用方便而且功能完善。

## 3、人脸识别功能的实现

### 如何识别人脸

简单的识别人脸可以借助face-recognition这个python模块中的接口实现,这个模块内部调用了Dlib来实现人脸识别,但是它对Dlib的使用比较粗糙,有很多可以我们自由改进。在进阶方案中我们可以自己来修改face-recognition的源码达到改善识别效果的目的。
下面用一个[例子][4]来介绍face-recognition的使用:
```python
import face_recognition
import cv2

# 开启摄像头
video_capture = cv2.VideoCapture(0)

# 载入一张已知的照片作为识别的先验参照,不然没有办法分辨谁是谁,这张照片可以放在当前文件夹中
obama_image = face_recognition.load_image_file("已知人脸的图片.jpg")
# 使用face_recognition模块把已知人脸图片的编码取出来
face_encoding1 = face_recognition.face_encodings(obama_image)[0]

# 载入第二张已知的照片作为识别的先验参照,这张照片可以放在当前文件夹中
biden_image = face_recognition.load_image_file("已知人脸的图片2.jpg")
# 使用face_recognition模块把已知人脸图片的编码取出来,
face_encoding2 = face_recognition.face_encodings(biden_image)[0]

# 用列表把已经编码的已知人脸特征编码存起来
known_face_encodings = [
face_encoding1,
face_encoding2
]
# 把名字按顺序存起来
known_face_names = [
"名字1",
"名字2"
]

# 准备一些变量
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True

while True:
# 获取一帧摄像头图像
ret, frame = video_capture.read()

# 将图像缩小为原来的1/4这样处理起来比较快
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)

# 这行代码将图像从BGR(opencv当前从摄像头获取的图片,以这种颜色格式存储着)转化为RGB(等会用到的颜色是这种颜色)
rgb_small_frame = small_frame[:, :, ::-1]

# 只处理process_this_frame = True的帧,减少计算量
if process_this_frame:
# 找到当前摄像头中所有的人脸的位置,把这些位置保存起来
face_locations = face_recognition.face_locations(rgb_small_frame)
# 将找到的人脸都编码为人脸特征编码
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)

face_names = []
# 查找摄像头中的人脸与已知人脸中的哪一个最为相像
for face_encoding in face_encodings:
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"

# 使用所有匹配的人脸中排序最先的那一个作为身份
if True in matches:
first_match_index = matches.index(True)
name = known_face_names[first_match_index]

face_names.append(name)

process_this_frame = not process_this_frame


# 将识别结果在展示在一个窗口中
for (top, right, bottom, left), name in zip(face_locations, face_names):
# 将人脸位置放大四倍,因为之前缩小了
top *= 4
right *= 4
bottom *= 4
left *= 4

# 用刚才得到的人脸位置在图像中画出方框框住人脸
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

# 在人脸框的下面画上一个方框,放识别出来的名字
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

# 显示出身份识别结果
cv2.imshow('Video', frame)

# 设置按'q'建就会退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break

# 释放摄像头
video_capture.release()
cv2.destroyAllWindows()

通过以上的代码可以了解如何使用face-recognition这一模块来进行人脸识别。

使用PyQt

(1)设计PyQt界面

Qt5界面可以使用Qt designer这一工具进行设计,但是PyQt5的界面有没有简便的工具呢。事实上PyQt5也使用Qt designer这一工具,在设计完成之后,可以使用pyuic工具转换为python可以使用的界面文件
人脸识别界面
如图所示为我用Qt designer设计的一个界面.ui文件,使用如下的命令将界面源码转换为.py格式的PyQt可以使用的界面文件face_check.py

1
pyuic -x -o face_check.py face_check.py

(2)为界面添加交互

但是有了界面之后,人机交互应该如何实现呢,这需要涉及到PyQt的交互机制,下面的代码展示了为“开始”按钮增加一个点击事件

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
__author__ = 'Zhang Zhe'
import sys
from PyQt5 import QtWidgets
from face_check import Ui_FaceCheck

# 定义一个新的类,这个类继承由Qt designer生成的界面类
class FaceCheck(QtWidgets.QDialog, Ui_FaceCheck):
def __init__(self, parent=None):
# 用来调用基类中的初始化函数
super(FaceCheck, self).__init__()
self.setupUi(self)
# 通过将“开始”按钮与onStartBtnClicked()函数连接起来,为“开始”按钮增加点击事件
self.start.clicked.connect(self.onStartBtnClicked)

def onStartBtnClicked(self):
"""
登录的点击事件
"""
# 开始按钮的点击事件只输出一句话“这是开始按钮”,这句话将被输出到控制台的输出中
print("这是开始按钮!!!")



if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
FaceCheck = FaceCheck()
FaceCheck.show()
sys.exit(app.exec_())

PyQt中提供了和Qt一样的信号槽机制。对于按钮来说,其默认有一个clicked事件可以连接

解决CMAKE编译第三方开源软件需要下载的问题

Posted on 2020-01-12 | In 编译开源软件

本人长期出售超大量微博数据、旅游网站评论数据,并提供各种指定数据爬取服务,Message to YuboonaZhang@Yahoo.com。同时欢迎加入社交媒体数据交流群:99918768

解决CMAKE编译第三方开源软件需要下载的问题

经常会出现这种问题:我们从github上面下载了一些开源软件,但是这个开源软件本身其实是会下载很多其他开源软件,编译后作为软件的一部分。
看起来好像没什么问题,但是有时候这个下载很耗时间,让整个安装变得很慢,它本身的这个下载过程下载东西真的很不稳定。所以就导致了有可能的安装失败。重新多次安装又要多次下载,这个过程真的很浪费时间和网络资源硬盘资源。

解决方案

通过对于我最近使用的一个软件的cmake过程的研究,发现这个软件安装时进行第三方的包的下载的时候,是通过CMAKE自带的下载和编译功能进行的。所以为了:

  • 能够让下载第三方源码的过程被消除
  • 同时为了保证不发生因为下载慢,导致的第三方的开源软件的编译的进程竞争,进而导致安装时的开源软件之间的互相依赖或者make文件不存在问题。

–采用网上对于CMAKE过程的修改方法

  1. 将.cmake 文件中的以下代码
    #–Download step————–
    DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
    URL https://github.com/gflags/gflags/archive/v2.1.2.zip
    URL_MD5 5cb0a1b38740ed596edb7f86cd5b3bd8
    部分更改为
    #–Download step————–
    DOWNLOAD_COMMAND “”

  2. 同时,将src(这个文件是原本解压下载的第三方源码source的地方,具体名称要看CMakeLists.txt中SOURCE_DIR的设置)中的各个第三方源码都解压好,放到src对应的文件夹中。

结果:这样整个程序编译第三方开源软件的编译过程就可以直接调用src目录中我们早就自己下载好的源码进行安装了

using-Electron-to-create-app-with-Js-html-css

Posted on 2020-01-12 | In App

notes of Electron Api Demo


section&category

1. add a new section to program

A category is consist of several sections, and the section is a part that contains a individual page

To create a new section in code, add following code in index.html

1
<button type="button" id="xxx2" data-section="xxx2" class="nav-button">Use system <em>dialogs</em></button>

in this pice of code, the real important element is (1)data-section=" " and (2)class=" "

  • (1)data-section=" " is relevant to template file to the file of the import links in the head of index.html. for example:

    1
    <link rel="import" href="sections/native-ui/dialogs.html">

    the file name is of no use in fact(you can choose no matter what), but it can tell what the file’s content is. The real thing makes the Electron knows what to render is this data-section="xxx2" in index.html and the id="xxx2-section" in template file’s <section> tag.
    when you make xxx2 the same in two files, then the Electron can render the correct html for section

  • (2)class=" " is about the style of the section looking like. In css file, it will all be defined.

2.add a demo

We can just copy a demo code of <div class="demo"> and paste to get a new demo, but the process of this demo must contain new JS action code different from the old demo.Or the new demo will just can be clicked but do nothing.

We can find that when the section code be imported by the head lines in index.html, the JS code used in the section code also is imported together.So the same JS code will just be imported once and just for the first section

python爬取图片

Posted on 2020-01-12 | In Web spiders

本人长期出售超大量微博数据、旅游网站评论数据,并提供各种指定数据爬取服务,Message to YuboonaZhang@Yahoo.com。同时欢迎加入社交媒体数据交流群:99918768

前言

最近在做机器学习下的人脸识别的学习,机器学习这个东西有点暴力,很大程度上靠训练的数据量来决定效果。为了找数据,通过一个博客的指导,浏览了几个很知名的数据集。

几个大型数据集是通过发邮件申请进行下载,几个小型数据集直接在网页的链接下载,还有一个Pubfig数据集则是提供了大量图片的链接来让我们自己写程序来下载。

权衡了数据量的需求,最后选择Pubfig的数据集,于是就自己写了一个python图片采集程序,里面用了urllib和requests两种方法.

分析Pubfig提供的下载文件的特点

people
这个数据文件提供了在数据集中出现的所有人物
urls
这个数据文件提供了每个人的urls

可以看出来这个数据集的处理其实非常简单了,可以通过readlines的方式存进列表用空格分开一下数据就可以把urls提取出来了。

处理一下urls文件

urls在文件的中后部,写个文件把它单纯地提取出来,方便使用。
我单独把Miley_Cyrus的部分提取出来放了一个txt文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pic_url = []
with open('./Miley_Cyrus.txt') as f:
for i in f.readlines():
pic_url.append(i.strip('\r\n'))

urls = []
for s in pic_url:
_, _, _, url, _, _ = s.split()
urls.append(url)

# 写入到文件里面
with open('url.data', 'w') as f:
for i in urls:
f.write(i)
f.write('\n')

爬取urls图片

1. Urllibs方法

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
import urllib.request as request
import socket
import os


# 在同级目录新建文件夹存图片
os.mkdir('./img')


# 为请求增加一下头
user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'
headers = ('User-Agent', user_agent)
opener = request.build_opener()
opener.addheaders = [headers]
request.install_opener(opener)

# 设定一下无响应时间,防止有的坏图片长时间没办法下载下来
timeout = 20
socket.setdefaulttimeout(timeout)


# 从文件里面读urls
urls = []
with open('./url.data') as f:
for i in f.readlines():
if i != '':
urls.append(i)
else:
pass


# 通过urllibs的requests获取所有的图片
count = 1
bad_url = []
for url in urls:
url.rstrip('\n')
print(url)
try:
pic = request.urlretrieve(url, './img3/%d.jpg' % count)
print('pic %d' % count)
count += 1
except Exception as e:
print(Exception, ':', e)
bad_url.append(url)
print('\n')
print('got all photos that can be got')


# 把没有抓取到的urls保存起来
with open('bad_url3.data', 'w') as f:
for i in bad_url:
f.write(i)
f.write('\n')
print('saved bad urls')

2. Requests方法

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
import requests
import socket
import os


# 在同级目录新建文件夹存图片
os.mkdir('./img')


# 设定一下无响应时间,防止有的坏图片长时间没办法下载下来
timeout = 20
socket.setdefaulttimeout(timeout)


# 从文件里面读urls
urls = []
with open('./url.data') as f:
for i in f.readlines():
if i != '':
urls.append(i)
else:
pass


# 为请求增加一下头,获取图片
user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'
headers = {
'User-Agent': user_agent
}
bad_url = []
count = 1
for url in urls:
url.rstrip('\n')
print(url)
try:
pic = requests.get(url, headers=headers)
with open('./img2/%d.jpg' % count, 'wb') as f:
f.write(pic.content)
f.flush()
print('pic %d' % count)
count += 1
except Exception as e:
print(Exception, ':', e)
bad_url.append(url)
print('\n')
print('got all photos that can be got')


# 保存坏链接
with open('bad_url.data', 'w') as f:
for i in bad_url:
f.write(i)
f.write('\n')
print('saved bad urls')

MongoDB的find函数如何使用

Posted on 2020-01-12

MongoDB的find函数如何使用


1、Why?为什么使用find()函数

我在mongo中存储的数据是爬网页的json数据,结构较为复杂,json内部嵌套的很厉害,光靠眼睛来看找数据好像有点困难。pycharm上的插件提供了搜查功能,可是我发现,但仍然还是要自己用json的格式提供要搜的关键词和值。经过搜集也可以发现其实这个功能只是对find()函数的一个封装。
所以,我们要用find()

2、示例数据

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
示例数据json:
{
"_id": {
"$oid": "5adcae9b3fa8b06fdbe7184e"
},
"json": {
"sjkList": [{
"jxbmc": "面向对象程序设计课程设计-0022",
"userModel": {
"roleCount": 0,
"status": 0,
"monitor": false,
"roleKeys": "",
"usable": false,
"roleValues": ""
},
"jgpxzd": "1",
"totalResult": "0",
"zhxs": "2",
"qsz": "21",
"listnav": "false",
"jxb_id": "62DAED714DEEA4ECE0530C0114AC99EB",
"xqdm": "0",
"kcmc": "面向对象程序设计课程设计",
"localeKey": "zh_CN",
"sfsjk": "1",
"xm": "孙斌",
"xqh_id": "1",
"rsdzjs": 0,
"zzz": "22",
"rangeable": true,
"jxbzh": "117171;117172",
"pageable": true,
"queryModel": {
"totalPage": 0,
"currentPage": 1,
"totalCount": 0,
"entityOrField": false,
"pageNo": 0,
"offset": 0,
"currentResult": 0,
"pageSize": 15,
"limit": 15,
"totalResult": 0,
"showCount": 10
}
}, {
"jxbmc": "自然地理与地质学实习-0003",
"userModel": {
"roleCount": 0,
"status": 0,
"monitor": false,
"roleKeys": "",
"usable": false,
"roleValues": ""
},
"jgpxzd": "1",
"totalResult": "0",
"zhxs": "2",
"qsz": "22",
"listnav": "false",
"jxb_id": "5F7A59A6AB1521FDE0530B0114ACF30A",
"xqdm": "0",
"kcmc": "自然地理与地质学实习",
"localeKey": "zh_CN",
"sfsjk": "1",
"xm": "孙斌",
"xqh_id": "1",
"rsdzjs": 0,
"zzz": "23",
"rangeable": true,
"jxbzh": "117171;117172",
"pageable": true,
"queryModel": {
"totalPage": 0,
"currentPage": 1,
"totalCount": 0,
"entityOrField": false,
"pageNo": 0,
"offset": 0,
"currentResult": 0,
"pageSize": 15,
"limit": 15,
"totalResult": 0,
"showCount": 10
}
}]
}
}

3、find()怎么用

find()函数的基本用法很简单

1
2
# -*- coding:utf-8 -*-
MongoClient['你的库名']['你的表名'].find({'key':'要搜的value'})

但是对应实例数据,复杂json嵌套数据下这个简单的搜索方法好像没用,找了很久网页,基本都是浅尝辄止,或者介绍的和我关心的不在一个频道。

但是后来还是找到了正确的方法:
可以看到第二个关键字’json’中的嵌套了数组,数组的组成单位是json串
为了获得”jxb_id”: “5F7A59A6AB1521FDE0530B0114ACF30A”这个关键词对应的数据,我们可以使用如下方法

1
2
# -*- coding:utf-8 -*-
MongoClient['你的库名']['你的表名'].find({"json.sjkList.jxb_id" : "5F7A59A6AB1521FDE0530B0114ACF30A"})

4、如何理解

想要理解为什么会这样来用,其实看一下mongodb的一些基本的命令行操作,会有一点启发,基本都会有’.’这个操作符号,这个操作符像是在往对象的内部不断地纵深。

我们把每个关键字对应的值理解为一个对象,为了进入对象内部,用’.’来操作也就很理所当然了。

2018年使用ipv6-XX-net翻墙

Posted on 2020-01-12 | In Web

2018年ubuntu使用XXnet


从大概两个月前开始,xx-net开始不好用了,几乎所有的ipv4的ip都被封锁了没有办法上网,所以很长一段时间我告别了它,openvpn成了我的最后的伙伴(很多其他的手机vpn软件也开始失效了)
但是今天我终于通过使用ipv6借助xx-net又能翻出围墙了

1、准备工作

  1. 下载最新版的xx-net
  2. 在ubuntu下安装miredo, miredo提供一种 IPv6/IPv4转换技术,它让只能访问ipv4的网络用户能够体验到ipv6的网络。当然如果你的网络运营商已经提供了ipv6服务那你就大可不必装这个软件了。(查看是否支持ipv6)
1
2
3
4
# 安装miredo
sudo apt install miredo
# 并且启动miredo,默认不是开机启动项,所以每次重新开机以后都要重新启动
sudo service miredo start

2、进行安装

  1. 安装xx-net,这个大家应该都比较熟,首先解压安装包
1
2
3
4
5
6
# 解压
sudo unzip XX-Net-3.8.7.zip
# 移动xx-net到/opt/目录,这个目录是我比较喜欢的软件安装目录,一般deb包安装的软件也都是安装在这个目录下面
sudo mv XX-Net-3.8.7 /opt/
# 开始运行
sudo /opt/XX-Net-3.8.7/start

3、进入localhost:8085管理界面

经过以上的步骤,我们已经开启了xx-net 以及 miredo服务,在浏览器中访问xx-net 的管理界面,我们现在应该能够看到一些内容
图片1:

4、注意事项

  1. 教育网没有办法使用miredo
  2. 重启电脑后联网后,需要使用启动miredo
1
sudo miredo

Yuboona Zhang

Don't focus too much.

9 posts
6 categories
19 tags
GitHub E-Mail
© 2020 Yuboona Zhang
Powered by Hexo
|
Theme — NexT.Pisces v5.1.3