OpenCV学习路线(1)—— 基本数据类型

基本情况

  • 基本容器多为固定容量,容量可于创建时指定
  • 运算效率较高
  • OpenCV根据容器的不同容量定义了许多类型别名
  • 在使用时多使用类型别名以提高开发速度与可读性

基础类型

固定矩阵类型cv::Matx

Matx处于基本数据类型继承树的最顶端,其他基本容器多由它继承而来或使用它及它的派生类实现。Matx用于储存已知容量的小型数组。它的主要操作列表如下:

功能 示例
默认构造 Matx<4, 4, float> mat44f; Matx34d mat34d;
拷贝 Matx22d mat22d(other);
值构造 Matx23d mat23d(x1, x2, x3, x4, x5, x6);
含相同元素的矩阵 m1.all(m2);
全一矩阵 Matx22d.ones();
全零矩阵 Matx22d.zeros();
单位阵 Matx33d.eye();
随机阵 Matx34d.randu(); //均匀分布 Matx34d.nrandn(); // 正态分布
成员访问 m(i); //针对一维数组 m(i, j); //针对二维数组
运算与比较 直接使用运算符号
点积 m1.dot(m2); m1.ddot(m2); //双精度
改变形状 mat19f = mat33f.reshape<1, 9>();
类型转换 mat33f = (Matx33f)mat33d;
在(i, j)处获取n * m的子矩阵 mat44f.get_minor<n, m>(i, j);
提取第i行/列 mat44f.row/col(i);
提取对角线 mat44f.diag();
转置 mat34f.t();
逆矩阵 mat33d.inv(method); //method为计算方法,默认为高斯法
元素逐一相乘 m1.mul(m2);

类型别名命名形式为Matxabc
其中 a, b为维度,c为数据类型(f->float; d->double)

固定向量类型cv::Vec

Vec类继承自Matx类。准确来说,它继承自Matx<_Tp, cn, 1>,即一个一维数组。Vec支持使用下标访问元素,当然,像一维Matx一样通过括号访问也是可以的(见上节表格)。此外,三维Vec还支持向量的叉乘:vec3d1.cross(vec3d2);

Vec类型别名的命名格式为Vec{2, 3, 4, 6}{b, f, w, I, s, d}其中,s表示short而w表示unsigned short

点类型cv::Point

Point是OpenCV中最简单的数据类型,它是Point2i的类型别名。在使用时,通常使用类型别名进行操作,如Point{2, 3}{i, f, d}

Point类型可通过点操作符直接访问其成员。同时,它支持dotcross操作。特别地,通过p.inside(r)可判断点p是否在矩形r内。

cv::Scalar类型

Scalar类型可以理解为是一个四维的点,但它实际上通过继承一个cv::Vec< _Tp, 4 >实现。它可以通过mul(s2)函数与另一个Scalar类型进行逐元素相乘的运算;通过conj()函数进行共轭运算;通过isReal()进行真值检验(即判断s1, s2, s3是否全部等于0)。

cv::Size类型

Size类型类似于一个二维Point,且可用与Point相互转换。

未完待续。。。

2020年寒假第一周周报(Jan. 6th ~ Jan. 12th)

本周学习内容

线性代数


  1. 矩阵的基本运算:
    -加减:相同维度的矩阵对应元素加减
    -标量积:矩阵的每个元素分别与标量相乘
    -点乘:行向量和列向量相乘得到一个标量或者一个1*1矩阵,依此规律得到结果
    -转置:A(ij)=A^T(ji)
    -逆矩阵:A*A^(-1)=I
    -单位矩阵:AI=IA=AI
  2. 矩阵的行列式
    -行列式=0,则矩阵为奇异矩阵,不可逆,否则为非奇异矩阵,可逆。

机器学习


线性回归


假设函数(Hypothesis)

假设函数

代价函数(Cost Function)

代价函数

梯度下降(Gradient Descent)

更新参量

向量化

逻辑回归


假设函数

假设函数

代价函数

代价函数

梯度下降

同线性回归

正则化


在代价函数中加入惩罚项,防止高阶特征的参数过大导致过度拟合

本周工作总结

本周我主要完成了线性回归和爬虫程序的制作,通过一遍遍的尝试,我使我的程序在变快的同时也变得更加精确。这不仅磨炼了我的毅力,也使我获得了更多的经验。下周继续努力!

下周学习安排

  • 继续学习线性代数
  • 完成神经网络基础的学习并完成相关程序的编写
  • 每天学习英语

#END

基于Python Urllib库和Re库的爬虫应用

获取交通部官网2019年交通固定资产投资额等数据并将其存入Excel表格中

分析所需数据的位置及其上下文特征

进入交通部官网数据网站
通过右键检查表格元素,可以发现,每一个表格都被封装在一个html文件中,他们的网址位于网页源代码的872~893行,而他们的标题则位于864~867行。
代码如下:

1
        <div class="fl w100 mod_spsj mod1_kshsj_sj mart15">
2
			<ul id="myTabs" class="nav nav-tabs hidden-sm hidden-xs" role="tablist">
3
				<li class="sj_w180625"><b>可视化数据</b></li>
4
				<li class="active"><a href="#jtgdzctzwce" role="tab" data-toggle="tab">交通固定资产投资完成额</a></li>
5
				<li><a href="#yyxkhysl" role="tab" data-toggle="tab">营业性客货运输量</a></li>
6
				<li><a href="#cskyl" role="tab" data-toggle="tab">城市客运量</a></li>
7
				<li><a href="#gkscl" role="tab" data-toggle="tab">港口生产量</a></li>
8
			</ul>
9
......
10
<div class="list-group tab-content mod1_kshsj1_sj">
11
	<div role="tabpanel" class="tab-pane active" id="jtgdzctzwce">
12
		<div class="fl w100 mod1_kshsj1_a_sj">
13
			<IFRAME align="top" width="1110px" height="820px" frameborder="0" src="http://106.3.149.173/CatsCategory/listGLJCSJ5?tableName=cats_jtysybsjk_csky&pubflag=1&code=C13" scrolling="no" ></IFRAME>
14
		</div>
15
	</div>
16
	<div role="tabpanel" class="tab-pane" id="yyxkhysl">
17
		<div class="fl w100 mod1_kshsj1_a_sj">
18
			<IFRAME align="top" width="1110px" height="820px" frameborder="0" src="http://106.3.149.173/CatsCategory/listGLJCSJ5?tableName=cats_jtysybsjk_gksc&pubflag=1&code=C13" scrolling="no" ></IFRAME>
19
		</div>
20
	</div>
21
	<div role="tabpanel" class="tab-pane" id="cskyl">
22
		<div class="fl w100 mod1_kshsj1_a_sj">
23
			<IFRAME align="top" width="1110px" height="820px" frameborder="0" src="http://106.3.149.173/CatsCategory/listGLJCSJ5?tableName=cats_jtysybsjk_jtgdzctzwce&pubflag=1&code=C13" scrolling="no" ></IFRAME>
24
		</div>
25
	</div>
26
	<div role="tabpanel" class="tab-pane" id="gkscl">
27
		<div class="fl w100 mod1_kshsj1_a_sj">
28
			<IFRAME align="top" width="1110px" height="820px" frameborder="0" src="http://106.3.149.173/CatsCategory/listGLJCSJ5?tableName=cats_jtysybsjk_yyxkhysl&pubflag=1&code=C13" scrolling="no" ></IFRAME>
29
		</div>
30
	</div>
31
</div>

可见,上述网址前都具有属性class="fl w100 mod1_kshsj1_a_sj"故可以使用正则表达式<div class="fl w100 mod1_kshsj1_a_sj">.*?src="(.*?)"\s.*?</div>进行识别。
标题与此类似,不再赘述。

进入每一个表格的源代码,发现每一格中的数据都被<td></td>所包围,故可以使用正则表达式<td>(.*?)</td>识别。表头与之类似。

分析好了上下文,就可以进入编程环节了。

获取源代码


使用urllib库中的urllib.request.urlopen(url)方法获取网页信息该方法接受一个字符串,返回一个http.client.HTTPResponse对象,该对象的read()方法返回一个字符串,即网页的源代码。通过decode('utf-8')方法使源代码按照UTF-8标准编码。

1
response = urllib.request.urlopen(url)
2
    src = response.read().decode('utf-8')

匹配字符串


通过re库中的re.compile()方法将正则表达式编译,并在第二个参数位置加上re.S以确保查找不会被换行符所中断。使用re.findall()方法找出源代码中所有符合匹配模式的字符串,并将其以列表的形式储存。为方便编写代码,我编写了一个get_data()函数整合了这个过程

1
def get_data(url, pattern):
2
    response = urllib.request.urlopen(url)
3
    src = response.read().decode('utf-8')
4
    results = re.findall(pattern, src)
5
    return results

储存数据


通过openpyxl库储存数据。
我编写了fill_sheet()函数以实现这一过程。该函数接收文件对象,工作表名,要填写数据的区域左上角和右下角的坐标,以及数据来源和开始位置(默认为0),填写表格后返回最后填写的一个数据的下一位置。

1
def fill_sheet(workbook, sheetname, pos1, pos2, src_text, reading_pos=0):
2
    if sheetname not in workbook:  # 若工作表不存在,则创建一个
3
        workbook.create_sheet(sheetname)
4
    sh = workbook[sheetname]
5
    workbook.close() # 关闭文件后才能写入
6
    for i in range(pos1[0], pos2[0]+1):
7
        for j in range(pos1[1], pos2[1]+1):
8
            sh.cell(row=i, column=j, value=src_text[reading_pos])  # 在相应单元格中写入数据
9
            reading_pos += 1
10
    return reading_pos

完整程序


1
import urllib.request
2
import re
3
import openpyxl
4
5
6
def get_data(url, pattern):
7
    response = urllib.request.urlopen(url)
8
    src = response.read().decode('utf-8')  # 获取源代码
9
    results = re.findall(pattern, src)  # 找出所有匹配的结果
10
    return results
11
12
13
def fill_sheet(workbook, sheetname, pos1, pos2, src_text, reading_pos=0):
14
    if sheetname not in workbook:  # 如果工作表不存在,则创建一个
15
        workbook.create_sheet(sheetname)
16
    sh = workbook[sheetname]  # 获取工作表对象
17
    workbook.close()  # 关闭文件后才能写入
18
    for i in range(pos1[0], pos2[0]+1):
19
        for j in range(pos1[1], pos2[1]+1):
20
            sh.cell(row=i, column=j, value=src_text[reading_pos])  # 在对应单元格中写入数据
21
            reading_pos += 1
22
    return reading_pos
23
24
25
def main():
26
    url = 'http://www.mot.gov.cn/shuju/'
27
    # 编译各种所需的正则表达式
28
    pattern_get_graph_sites = re.compile(r'<div class="fl w100 mod1_kshsj1_a_sj">.*?src="(.*?)"\s.*?</div>', re.S)  # 图表网址
29
    pattern_get_datas = re.compile('<td>(.*?)</td>', re.S)  # 表中数据
30
    pattern_get_graph_headers = re.compile('<th style="width:120px">(.*?)</th>', re.S)  # 表头
31
    pattern_get_graph_names_block = re.compile('<div class="fl w100 mod_spsj mod1_kshsj_sj mart15">(.*?)</ul>', re.S)  # 标题代码区块
32
    pattern_get_graph_names = re.compile('<a.*?>(.*?)</a>', re.S)  # 图表标题
33
    # 匹配数据
34
    graph_names_block = get_data(url, pattern_get_graph_names_block)
35
    graph_sites = get_data(url, pattern_get_graph_sites)
36
    graph_names = re.findall(pattern_get_graph_names, graph_names_block[0])
37
    datas = []
38
    graph_headers = []
39
    for graph_site in graph_sites:
40
        datas.append(get_data(graph_site, pattern_get_datas))
41
        graph_headers.append(get_data(graph_site, pattern_get_graph_headers))
42
    # 储存数据
43
    wb = openpyxl.Workbook()
44
    for i in range(0, len(graph_names)):
45
        len_gh = len(graph_headers[i])
46
        fill_sheet(wb, graph_names[i], (1, 1), (1, len_gh), graph_headers[i])
47
        fill_sheet(wb, graph_names[i], (2, 1), (int(len(datas[i])/len_gh+1), len_gh), datas[i])
48
    del wb['Sheet']  # 删除默认工作表
49
    wb.save('results.xlsx')  # 保存文件
50
51
52
if __name__ == '__main__':  # 执行主函数
53
    main()

运行结果


表1
表2
表3
表4