如有错误,还望大佬指正,我也才刚学,难免有疏漏,勿怪勿怪…(〃´・ω・)
在 Python 里,标识符由字母、数字、下划线组成。
在 Python 中,所有标识符可以包括英文、数字以及下划线(_),但不能以数字开头。
Python 中的标识符是区分大小写的。
以下划线开头的标识符是有特殊意义的。以单下划线开头_foo
的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用from xxx import *
而导入。
以双下划线开头的 __foo
代表类的私有成员,以双下划线开头和结尾的 __foo__
代表 Python 里特殊方法专用的标识,如 __init__()
代表类的构造函数。
stu = 1
学习 Python 与其他语言最大的区别就是,Python 的代码块不使用大括号 {} 来控制类,函数以及其他逻辑判断。python 最具特色的就是用缩进来写模块。
缩进的空白数量是可变的,但是所有代码块语句必须包含相同的缩进空白数量,这个必须严格执行。
# 没有严格缩进,在执行时会报错
if True:
print ("True")
else:
print ("False")
变量
在 Python 中,每个变量 在使用前都必须赋值,变量 赋值以后 该变量 才会被创建
等号(=)用来给变量赋值
= 左边是一个变量名
= 右边是存储在变量中的值
=
等号右侧的值,自动推导出变量中存储数据的类型在 Python 中,如果要获取用户在键盘上的输入信息,需要使用到input
函数
用户输入的 任何内容 Python 都认为是一个 字符串
字符串变量 = input("提示信息:")
演练
# 1. 输入苹果单价
price_str = input("请输入苹果价格:")
# 2. 要求苹果重量
weight_str = input("请输入苹果重量:")
# 3. 计算金额
# 1> 将苹果单价转换成小数
price = float(price_str)
# 2> 将苹果重量转换成小数
weight = float(weight_str)
# 3> 计算付款金额
money = price * weight
print(money)
关键字 就是在 Python 内部已经使用的标识符
关键字 具有特殊的功能和含义
不允许定义和关键字相同的名字的标示符
import
关键字 可以导入一个 “工具包”。在 Python 中不同的工具包,提供有不同的工具
算数运算符 | 描述 | 补充 |
---|---|---|
+ | 加 | 10 + 20 = 30 |
- | 减 | 10 - 20 = -10 |
* | 乘 | 10 * 20 = 200 |
/ | 除 | 10 / 20 = 0.5 |
// | 取整除 | 返回除法的整数部分(商) 9 // 2 输出结果 4 |
% | 取余数 | 返回除法的余数 9 % 2 = 1 |
** | 幂 | 又称次方、乘方,2 ** 3 = 8 |
比较运算符 | > < == != >= <= | |
逻辑运算符 | and or not | |
赋值运算符 | = += -= *= /= //= **= |
运算符的优先级
运算符 | 描述 |
---|---|
** | 幂 (最高优先级) |
* / % // | 乘、除、取余数、取整除 |
+ - | 加法、减法 |
<= < > >= | 比较运算符 |
== != | 等于运算符 |
= %= /= //= -= += *= **= | 赋值运算符 |
not or and | 逻辑运算符 |
Python 程序语言指定任何非 0 和非空(None)值为 True,0 或者 None为 False。
# -*-coding:utf-8-*-
results=59
if results>=60:
print ('及格')
else :
print ('不及格')
# -*-coding:utf-8-*-
results = 89
if results > 90:
print('优秀')
elif results > 80:
print('良好')
elif results > 60:
print ('及格')
else :
print ('不及格')
Python 提供了 for 循环和 while 循环,当然还有一些控制循环的语句:
count = 1
sum = 0
while count <= 100:
sum = sum + count
count = count + 1
print(sum)
for letter in 'wsc':
print(letter)
# 输出
w
s
c
range()函数
Python函数range()
让你能够轻松地生成一系列的数字。
range(0,5) # 生成0,1,2,3,4
打印九九乘法表
for i in range(1, 10):
for j in range(1, i+1):
print('{}x{}={}\t'.format(i, j, i*j), end='')
print()
#输出结果
1x1=1
2x1=2 2x2=4
3x1=3 3x2=6 3x3=9
4x1=4 4x2=8 4x3=12 4x4=16
5x1=5 5x2=10 5x3=15 5x4=20 5x5=25
6x1=6 6x2=12 6x3=18 6x4=24 6x5=30 6x6=36
7x1=7 7x2=14 7x3=21 7x4=28 7x5=35 7x6=42 7x7=49
8x1=8 8x2=16 8x3=24 8x4=32 8x5=40 8x6=48 8x7=56 8x8=64
9x1=9 9x2=18 9x3=27 9x4=36 9x5=45 9x6=54 9x7=63 9x8=72 9x9=81
随机数
在 Python 中,要使用随机数,首先需要导入 随机数 的 模块 —— “工具包”
import random
导入模块后,可以直接在 模块名称 后面敲一个 . ,会提示该模块中包含的所有函数
random.randint(a, b)
,返回 [a, b] 之间的整数,包含 a 和 b
random.randint(12, 20) # 生成的随机数n: 12 <= n <= 20
random.randint(20, 20) # 结果永远是 20
random.randint(20, 10) # 该语句是错误的,下限必须小于上限
List 列表—一组有序、可变的数据集合;我们可以通过 List 列表的索引编号(位置编码)来访问列表中的元素;
集合中的任何一个元素,称为集合的元素或者成员;
同一个列表集合中可以同时存储数字、字符、字符串,甚至包含另一个 List;
创建 List 列表的方法有两种:
# 创建的时候直接复制
list01 = [100,90,80,70]
# 创建空 list 然后插入
list01 = []
list01.append(100)
list01.append(90)
访问list中的元素
list01 = [10,20,30,40,50,60,70,80,90,100]
print(list01[0]) # 结果:10 解释:访问列表集合的第一个元素
print(list01[-1]) # 结果:100 解释:访问集合的最后一个元素
print(list01[4:]) # 结果:[50,60,70,80,90,100]
print(list01[:4]) # 结果:[10,20,30,40] 解释:如果只有右边的数字,右边的编号取不到
print(list01[:-5]) # 结果:[10,20,30,40,50]
print(list01[-5:]) # 结果:[60,70,80,90,100]
print(list01[1:5]) # 结果:[20,30,40,50]
print(list01[-4:-1]) # 结果:[70,80,90]
print(list01[1::2]) #结果:[20, 40, 60, 80, 100] 解释:[开始索引:结束索引:每次变化索引]
print(list01[-1:-4:-1]) # 结果:[100,90,80]
基本操作
# 把list01的值赋给list02
list01 = [1,2,3]
list02 = list01
# 使用copy把list01的值拷贝给list03
list03 = list01.copy()
# 让两个list集合合并
list01 = [1,2,3]
list02 = [4,5,6]
print(list01+list02)
# 返回list集合元素的个数
list01 = ['a','b','c']
print(len(list01))
# 使用成员运算符
list01 = ['a','b','c']
print("a是否在list01中",'a' in list01) # in、not in都可以使用
# 元素的添加
list02.append("AAA")
list02.insert(1,"CCC")
# 使用 extend 添加,可以添加一个集合
list02.extend(["DDD","EEE","FFF"])
# 元素的删除
list01.remove('f')
list01.pop(1) # 删除第二个元素
del list01[1:5] # 切片删除第二个到第五个
list01.clear() # 清空list中所有的元素
基本运算
list01 = [45,90,123,987,-10,78,96]
print("List01的最大值:",max(list01))
print("List01的最小值:",min(list01))
print("list所有元素和:%d"%sum(list01))
# 使用 sort()进行排序,默认是升序
list01.sort()
# 先升序,再反转。使用 reverse()方法进行逆序操作
list01 = [12,33,44,55,6,22]
list01.sort()
list01.reverse()
# 添加参数
list01 = [12,33,44,55,6,22]
list01.sort(reverse=True)
print(list01)
OpenCV中文文档
cv2.imread("img/time.jpg",cv2.IMREAD_COLOR)
cv2.imshow("图像的名字",img) #显示图片
cv2.imwrite("文件名",img) #保存图片
cv.waitKey()
是一个键盘绑定函数。其参数是以毫秒为单位的时间。该函数等待任何键盘事件指定的毫秒。如果您在这段时间内按下任何键,程序将继续运行。如果0被传递,它将无限期地等待一次敲击键。它也可以设置为检测特定的按键,例如,如果按下键 a 等,我们将在下面讨论。
k = cv.waitKey(0)
按如下所示修改行:k = cv.waitKey(0) & 0xFF
cv.destroyAllWindows()
只会破坏我们创建的所有窗口。如果要销毁任何特定的窗口,请使用函数
cv.destroyWindow()
在其中传递确切的窗口名称作为参数。
import cv2 # opencv的读取格式为BGR
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread("img/time.jpg",cv2.IMREAD_COLOR) # 读取彩色图像
img2 = cv2.imread("img/time.jpg",cv2.IMREAD_GRAYSCALE) # 读取灰度图像
# print(img)
cv2.imshow("image",img) # 图像显示
cv2.imshow("image2",img2) # 图像显示
cv2.waitKey(0) # 等待时间,毫秒级,0表示任意键终止
cv2.destroyAllWindows()
cv2.imwrite("img/time-change.jpg",img) # 保存图片
import numpy as np
import cv2
img = cv2.imread('img/time.jpg',0)
cv2.imshow('image',img)
k = cv2.waitKey(0)
if k == 27: # 等待ESC退出
cv2.destroyAllWindows()
elif k == ord('s'): # 等待关键字,保存和退出
cv2.imwrite('img/time-c.jpg',img)
cv2.destroyAllWindows()
使用Matplotlib
Matplotlib是Python的绘图库,可为你提供多种绘图方法。
import matplotlib.pyplot as plt
OpenCV加载的彩色图像处于BGR模式。但是Matplotlib以RGB模式显示。因此,如果使用OpenCV读取彩色图像,则Matplotlib中将无法正确显示彩色图像。
对于单个像素访问,Numpy数组方法array.item()和array.itemset())被认为更好,但是它们始终返回标量。如果要访问所有B,G,R值,则需要分别调用所有的array.item()。
import cv2 as cv # opencv的读取格式为BGR
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
img = cv.imread("img/time.jpg")
print(img.item(10,10,2)) # 输出111
img.itemset((10,10,2),33) # 修改像素
print(img.item(10,10,2)) # 输出33
cv.imshow("change",img)
cv.waitKey(0)
图像属性包括行数,列数和通道数,图像数据类型,像素数等。
图像的形状可通过img.shape
访问。它返回行,列和通道数的元组(如果图像是彩色的)
像素总数可通过访问img.size
图像数据类型通过img.dtype
获得
import cv2 as cv # opencv的读取格式为BGR
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
img = cv.imread("img/time.jpg")
# 图像的形状
print("shape---->",img.shape) # 输出(400,400,3)
# 图像大小
print("size----->",img.size) # 输出480000
# 数据类型
print("dtype---->",img.dtype ) # 输出uint8
cv.imshow("change",img)
cv.waitKey(0)
注意
b,g,r = cv.split(img)
img = cv.merge((b,g,r))
注意:cv.split()
是一项耗时的操作(就时间而言)。因此,仅在必要时才这样做。否则请进行Numpy索引。
如果要在图像周围创建边框(如相框),则可以使用cv.copyMakeBorder()
。但是它在卷积运算,零填充等方面有更多应用。此函数采用以下参数:
import cv2 as cv
import matplotlib.pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('img/time.jpg')
replicate = cv.copyMakeBorder(img1,20,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
可以通过OpenCV函数cv.add()
或仅通过numpy操作res = img1 + img2
添加两个图像。两个图像应具有相同的深度和类型,或者第二个图像可以只是一个标量值。
注意:OpenCV加法和Numpy加法之间有区别。OpenCV加法是饱和运算,而Numpy加法是模运算。
图像融合
这也是图像加法,但是对图像赋予不同的权重,以使其具有融合或透明的感觉。根据以下等式添加图像:
G ( x ) = ( 1 − α ) f 0 ( x ) + α f 1 ( x ) G(x)=(1−α)f_0(x)+αf_1(x) G(x)=(1−α)f0(x)+αf1(x)
cv.addWeighted()
在图像上应用以下公式。
d s t = α ⋅ i m g 1 + β ⋅ i m g 2 + γ dst=α⋅img1+β⋅img2+γ dst=α⋅img1+β⋅img2+γ
import cv2 as cv # opencv的读取格式为BGR
import matplotlib.pyplot as plt
import numpy as np
img1 = cv.imread('img/time.jpg')
img2 = cv.imread('img/opencv.png')
dst = cv.addWeighted(img1,0.7,img2,0.3,0)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()
两张图片:数组具有相同的大小和相同数量的通道
掩膜(mask)
?有点像PS里的蒙版
数字图像处理中,掩模为二维矩阵数组,有时也用多值图像。数字图像处理中,图像掩模主要用于:
例如:mask中的 1 就是感兴趣的区域,感兴趣区内图像值保持不变,而区外图像值都为0。
cv.bitwise_and
是对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作
cv.bitwise_or
是对二进制数据进行“或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“或”操作
cv.bitwise_xor
是对二进制数据进行“异或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“异或”操作
cv.bitwise_not
是对二进制数据进行“非”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作
mask和原图必须有相同的shape和dtype
cv.line() cv.circle() cv.rectangle() cv.ellipse() cv.putText()
-1
,它将填充形状。默认厚度= 1cv2.LINE_AA
给出了抗锯齿的线条,看起来非常适合曲线。cv2.cvtColor(input_image, flag)
OpenCV中有超过150种颜色空间转换方法。但是我们将研究只有两个最广泛使用的,BGR↔灰色和BGR↔HSV。
对于颜色转换,我们使用cv函数。cvtColor(input_image, flag),其中flag决定转换的类型。
对于BGR→灰度转换,我们使用标志cv.COLOR_BGR2GRAY
。
对于BGR→HSV,我们使用标志cv.COLOR_BGR2HSV
注意:HSV的色相范围为[0,179],饱和度范围为[0,255],值范围为[0,255]。因此,如果你要将OpenCV值和它们比较,你需要将这些范围标准化
练习:提取图像中的蓝色部分
import cv2 as cv
import numpy as np
# 读取图片
img = cv.imread("img/opencv.png")
# 转换颜色空间 BGR 到 HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 定义HSV中蓝色的范围
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# 设置HSV的阈值使得只取蓝色
mask = cv.inRange(hsv, lower_blue, upper_blue)
# 将掩膜和图像逐像素相加
res = cv.bitwise_and(img,img, mask= mask)
cv.imshow('img',img)
cv.imshow('mask',mask)
cv.imshow('res',res)
cv.waitKey(0)
cv.destroyAllWindows()
翻转
cv2.flip(filename, flipcode)
变换
OpenCV提供了两个转换函数cv.warpAffine
和cv.warpPerspective
,您可以使用它们进行各种转换。
cv.warpAffine采用2x3转换矩阵,而cv.warpPerspective采用3x3转换矩阵作为输入
缩放
缩放只是调整图像的大小。为此,OpenCV带有一个函数cv.resize()
。图像的大小可以手动指定,也可以指定缩放比例。也可使用不同的插值方法。首选的插值方法是cv.INTER_AREA
(慢)和cv.INTER_LINEAR
用于缩放。默认情况下,出于所有调整大小的目的,使用的插值方法为cv.INTER_LINEAR
。
平移
平移是物体位置的移动。如果您知道在(x,y)方向上的位移,则将其设为 ( t x , t y ) (t_x,t_y) (tx,ty),你可以创建转换矩阵M,如下所示:
M = [ 1 0 t x 0 1 t y ] M=\begin{bmatrix}1 & 0 & t_x \\ 0 & 1 & t_y\\ \end{bmatrix} M=[1001txty]
您可以将其放入np.float32
类型的Numpy数组中,并将其传递给cv.warpAffine
函数。
import numpy as np
import cv2 as cv
img = cv.imread('img/time.jpg',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()
警告:cv.warpAffine
函数的第三个参数是输出图像的大小,其形式应为(width,height)
。记住width
=列数,height
=行数。
对于每个像素,应用相同的阈值(thresh)。如果像素值小于阈值,则将其设置为0,否则将其设置为最大值。
函数cv.threshold(src,thresh,maxval,type)
用于应用阈值。
ret,thresh = cv2.threshold(img,127,255,cv.THRESH_BINARY) # 将图像二值化
讲解滤波的视频
均值滤波 #简单的平均卷积操作
cv2.blur(img,(3,3))
一般是奇数(3,3), (5,5),(7,7)
方框滤波(和均值滤波一样,可以选择归一化,容易越界)
cv2.boxFilter(img,-1,(3,3),normalize=True)
高斯滤波
cv2.GaussianBlur(img,(5,5),1)
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到
中值滤波
cv2.medianBlur(img,5)
可以用来去除椒盐噪声(也称为脉冲噪声)
中值滤波 是一种非线性平滑技术。中值滤波是在“最小绝对误差”准则下的最优滤波。中值滤波对脉冲噪声有良好的滤除作用,特别是在滤除噪声的同时,能够保护信号的边缘,使之不被模糊。这些优良特性是线性滤波方法所不具有的。
中值滤波不是一种边缘增强算子。中值滤波是一种图象去噪(或图象平滑)算子。
椒盐噪声(也称为脉冲噪声)
就是图像上出现了一个一个的点
高斯噪声
高斯噪声是指它的概率密度函数服从高斯分布(即正态分布)的一类噪声
通常是二进制的图像,就只有黑白
cv2.erode(img,kernel)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
结果是,根据内核的大小,边界附近的所有像素都会被丢弃。因此,前景物体的厚度或大小减小,或只是图像中的白色区域减小。它有助于去除小的白色噪声,分离两个连接的对象等。
cv.dilate(img,kernel)
就是加粗效果
kernel = np.ones((3,3),np.uint8)
dilation = cv.dilate(img,kernel,iterations = 1)
图像膨胀操作过程
kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
kernel = np.ones((3,3),np.uint8)
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
高斯金字塔:向下采样(从金字塔底端到顶端)——缩小
cv2.pyrDown(img)
:将所有偶数行和列去除。
高斯金字塔:向上采样(从金字塔顶端到底端)——放大
cv2.pyrUp(img)
拉普拉斯金字塔的层由高斯金字塔的层与高斯金字塔的高层的扩展版本之间的差形成。
边缘是零散的点,轮廓是整体
cv2.findContours(img,mode,method)
—— 检索轮廓
cv2.RETR_EXTERNAL
:表示只检测外轮廓cv2.RETR_LIST
:检测的轮廓不建立等级关系cv2.RETR_CCOMP
:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如国内筒内还有一个连通物体,这个物体的边界也在顶层cv2.RETR_TREE
:建立一个等级树结构的轮廓。最常用的模式,检索所有的轮廓,并重构嵌套轮廓的层次cv2.CHAIN_APPROX_NONE
:存储所有的轮廓点,相邻两个点的像素位置差不超过1,以Freeman链码的方式输出轮廓,所有其他方法输出多边形cv2. cv2.CHAIN_APPROX_SIMPLE
:简化保存,比如矩形轮廓就只保存四个顶点的轮廓点。压缩水平的,垂直的和斜的部分,也就是,函数只保留他们的重点部分。cv2.CHAIN_APPROX_TC89_L1
:使用teh-Chinl chain近似算法cv2.CHAIN_APPROX_TC89_KCOS
:使用teh-Chinl chain近似算法binary, contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
binary:图片结果
contours:保存的事轮廓信息
cv.drawContours(img, contours, -1, (0,255,0), 3)
——绘制所有轮廓
绘制轮廓 drawContours(image, contours, contourIdx, color, thickness)
例如:mask = cv.drawContours(mask,contours,-1,(255,255,255),-1)
cv2.arcLength()
函数用于计算封闭轮廓的周长或曲线的长度
cv2.contourArea()
计算轮廓面积
cv.minEnclosingCircle()
查找最小包围圈
cv2.minAreaRect()
生成最小斜矩形(图中的红线)
cv2.boundingRect()
生成最小外接矩形(图中的绿线)
边缘检测
图像边缘是指图像局部特性的不连续性。
图像中存在边缘时,一定有较大的梯度值。
cv.Canny()
Canny算法是一种被广泛应用于边缘检测的标准算法,其目标是找到一个最优的边缘检测解或找寻一幅图像中灰度强度变换最强的位置。最优边缘检测主要通过低错误率,高定位性和最小响应三个标准进行评价。Canny算子的实现步骤如下:
Canny边缘检测算法是具有严格定义的
Canny算法具有满足边缘检测的三个标准和实现过程简单的优势
Canny算法寻找一幅图像中灰度强度变化最强的位置
图像梯度:图像就是函数
图像梯度是指图像某像素在x和y两个方向上的变化率(与相邻像素比较),是一个二维向量,由2个分量组成,X轴的变化、Y轴的变化 。
其中 X轴的变化是指当前像素右侧(X加1)的像素值减去当前像素左侧(X减1)的像素值。
同理,Y轴的变化是当前像素下方(Y加1)的像素值减去当前像素上方(Y减1)的像素值。
拐点被认为是图像中的良好特征,物体的良好特性包括尺度不变性与旋转不变性
尺度不变特征转换(Scale-invariant feature transform或SIFT
)是一种电脑视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,
SIFT
算法的特点有:
SIFT算法可以解决的问题:目标的自身状态、场景所处的环境和成像器材的成像特性等因素影响图像配准/目标识别跟踪的性能。而SIFT算法在一定程度上可解决:
检测特征点: sift.detect(image,keypoints)
或 keypoint = sift.detect(image, None)
SIFT的特征提取函数为detectAndCompute
特征提取可以获得所有的特征点
Brute-Force
匹配器也就是蛮力匹配器,顾名思义,它的工作原理是:在第一幅图像上选取一个关键点,然后依次与第二幅图像的每个关键点进行(描述符)距离测试,最后返回距离最近的关键点。
创建一个BFMatcher对象cv.BFMatcher(normType,corssCheck)
BFMatcher对象有两个方法
bf.match()
:会返回最佳匹配。bf.knnMatch()
:每个关键点返回k个匹配(降序排列之后取前K个),其中K是由用户设定的。通过查看图像的直方图,您可以直观地了解该图像的对比度,亮度,强度分布等
灰度直方图能反映一幅图像各灰度级像元占图像的面积比。
cv.calcHist([images],channels,mask,histSize,ranges)
cv2.VideoCapture("视频路径") #读取图像
import cv2
import matplotlib.pyplot as plt
import numpy as np
vc = cv2.VideoCapture("img/test.mp4")
while vc.isOpened():
ret ,frame = vc.read() # 如果正确读取帧,ret为True
if frame is None:
break
if ret == True:
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) # 将BGR格式变成灰度图像
print("gray----------->",gray)
cv2.imshow("result",gray)
if cv2.waitKey(30) & 0xFF == 27:
break
vc.release()
cv2.destroyAllWindows()
cv2.VideoWriter_fourcc('','','','')
cv2.VideoWriter_fourcc('I','4','2','0')
—未压缩的YUV颜色编码,4:2:0色度子采样。兼容性好,但文件较大。文件扩展名**.avi**cv2.VideoWriter_fourcc('P','I','M','1')
—MPEG-1编码类型,文件扩展名**.avi**。随机访问,灵活的帧率、可变的图像尺寸、定义了I-帧、P-帧和B-帧 、运动补偿可跨越多个帧 、半像素精度的运动向量 、量化矩阵、GOF结构 、slice结构 、技术细节、输入视频格式。cv2.VideoWriter_fourcc('X','V','I','D')
—MPEG-4编码类型,视频大小为平均值,MPEG4所需要的空间是MPEG1或M-JPEG的1/10,它对运动物体可以保证有良好的清晰度,间/时间/画质具有可调性。文件扩展名**.avi**。cv2.VideoWriter_fourcc('T','H','E','O')
—OGGVorbis,音频压缩格式,有损压缩,类似于MP3等的音乐格式。,兼容性差,件扩展名**.ogv**。cv2.VideoWriter_fourcc('F','L','V','1')
—FLV是FLASH VIDEO的简称,FLV流媒体格式是一种新的视频格式。由于它形成的文件极小、加载速度极快,使得网络观看视频文件成为可能,它的出现有效地解决了视频文件导入Flash后,使导出的SWF文件体积庞大,不能在网络上很好的使用等缺点。文件扩展名为**.flv**。cv2.VideoCapture("img/test.mp4").get(propId)
方法访问该视频的某些功能
cv2.VideoCapture("img/test.mp4").get(cv.CAP_PROP_FRAME_WIDTH)
:检查框架的宽度cv2.VideoCapture("img/test.mp4").get(cv.CAP_PROP_FRAME_HEIGHT)
检查框架高度其中一些值可以使用cv2.VideoCapture("img/test.mp4").set(propId,value)
进行修改。value
是你想要的新值。
读取视频帧率:frame_count = capture.get(cv2.CAP_PROP_FRAME_COUNT)
基于学习方式的分类
历史数据、训练、模型、预测等属于机器学习过程范畴
监督学习又叫做回归问题(应该是回归问题是监督学习问题的一种)
深度学习(DL,Deep Learning)是机器学习(ML,Machine Learning)领域中一个新的研究方向,它被引入机器学习使其更接近于最初的目标——人工智能(AI,Artificial Intelligence)。
深度学习是学习样本数据的内在规律和表示层次,这些学习过程中获得的信息对诸如文字,图像和声音等数据的解释有很大的帮助。它的最终目标是让机器能够像人一样具有分析学习能力,能够识别文字、图像和声音等数据。 深度学习是一个复杂的机器学习算法,在语音和图像识别方面取得的效果,远远超过先前相关技术。
深度学习在搜索技术、数据挖掘、机器学习、机器翻译、自然语言处理、多媒体学习、语音、推荐和个性化技术,以及其他相关领域都取得了很多成果。
使用深度学习框架完成建模任务有两个显著优势:
常见的深度学习优化器
深度学习防止过拟合的几种方法
深度学习模型
常见的损失函数
迁移学习
迁移学习是一种机器学习方法,就是把为任务 A 开发的模型作为初始点,重新使用在为任务 B 开发模型的过程中。
深度学习中,在计算机视觉任务和自然语言处理任务中,将预训练的模型作为新模型的起点是一种常用的方法,通常这些预训练的模型在开发神经网络的时候,已经消耗了巨大的时间资源和计算资源,迁移学习可以将已习得的强大技能迁移到相关的的问题上。
什么是卷积核的通道数?CNN的卷积输出通道数又是如何确定的?
CNN的卷积核通道数 = 卷积输入层的通道数
CNN的卷积输出层通道数(深度)= 卷积核的个数
卷积操作后,特征图大小计算
若图像为正方形:设输入图像尺寸为WxW,卷积核尺寸为FxF,步幅为S,Padding使用P,经过该卷积层后输出的图像尺寸为NxN:
N = W − F + 2 P S + 1 N=\frac{W-F+2P}{S}+1 N=SW−F+2P+1
卷积的计算
首先,有几个概念要搞定
输入图片的尺寸:一般用 n × n n×n n×n 表示输入的image大小。
卷积核的大小:一般用 f × f f×f f×f 表示卷积核的大小。
填充(Padding):一般用 p p p 来表示填充大小。设置填充的目的:希望每个输入方块都能作为卷积窗口的中心
步幅(Stride):一般用 s s s 来表示步长大小。设置步幅的目的:希望减小输入参数的数目,减少计算量
输出图片的尺寸:一般用 o o o 来表示。计算公式如下: o = n + 2 p − f s + 1 o = \frac{n+2p-f}{s}+1 o=sn+2p−f+1
由题意得: o = 3 , n = 5 , p = 2 o=3,n=5,p=2 o=3,n=5,p=2,代入公式 o = n + 2 p − f s + 1 o = \frac{n+2p-f}{s}+1 o=sn+2p−f+1
可得 2 s = 9 − f 2s=9-f 2s=9−f,代入一下选项,可得答案为A
具体原理是什么呢?输出的图片是怎么来的呢
假设有一个3×3卷积核 h,和一个待处理的7×7矩阵 x,假设步长为2,就是蓝色区域移动的格数变成了两个。
下图中写的应该是步幅(Stride)= 2,这个傻逼作者图片做错了ヾ(。`Д´。)ノ彡
这里就可以看出步幅的作用了,成倍的缩小了尺寸。从原图的7×7变成了3×3,但是不能说步幅为2,就缩小2倍,不是很严谨。
上图这种情况指的是padding = 0的情况,没有进行填充。这就导致有些方块不是卷积窗口的中心。
如果padding=2,就是在原图的基础上,向外扩充矩阵,并填充0。如图所示:
再按照原来的方式进行计算。
池化
随机池化(Stochastic Pooling)可以看作在一个池化窗口内对特征图数值进行归一化, 按照特征图归一化后的概率值大小随机采样选择,即元素值大的被选中的概率也大。
池化计算
设输入图像尺寸为WxH,其中W:图像宽,H:图像高,D:图像深度(通道数),卷积核的尺寸为FxF,S:步长
池化后输出图像大小:
W = W − F S + 1 W=\frac{W-F}{S}+1 W=SW−F+1
H = H − F S + 1 H=\frac{H-F}{S}+1 H=SH−F+1
池化后输出图像深度为D
BP神经网络算法又称为误差方向传播算法(Error Back Propagation Training),简称BP,是监督式学习算法的一种
BP神经网络算法的出现就是为了解决线性不可分的情况的,为解决非线性问题
BP神经网络:通常一个多层神经网络由L层神经元组成,第1层称为输入层,最后一层(第L层)被称为输出层,其它各层均被称为隐含层(第2层~第L-1层)
工作信号正向传播
工作信号正向传播:输入信号从 输入层 经 隐含层,神经元传向输出层,在输出端产生输出信号,这是工作信号的正向传播。在信号的向前传递过程中网络的权值是固定不变的,每一层神经元的状态只影响下一层神经元的状态。
BP神经网络可以用于解决回归问题也可以用于解决分类问题。
如果,在输出层不能得到期望的输出,则转入误差信号反向传播。
误差信号反向传播
网络的实际输出与期望输出之间差值即为误差信号,由输出端开始逐层向前传播这是误差信号的反向传播。
在误差信号反向传播的过程中,网络的权值由误差反馈进行调节。通过权值的不断修正,使网络的实际输出更接近期望输出。
归一化 : 归一化是将数据缩小到0- 1之间
min-max标准化
x ' = x − m i n A m a x A − m i n A x^'= \frac{x-minA}{maxA-minA} x'=maxA−minAx−minA
VGG
VggNet一共有六种不同的网络结构,但是每种结构都有含有5组卷积,每组卷积都使用3x3的卷积核,每组卷积后进行一个2x2最大池化,接下来是三个全连接层。VGGNet探索了卷积神经网络的深度与其性能之间的关系,成功地构筑了16~19层深的卷积神经网络,证明了增加网络的深度能够在一定程度上影响网络最终的性能,使错误率大幅下降,同时拓展性又很强,迁移到其它图片数据上的泛化性也非常好。
VGG16模型其中不包含输出层
Sigmoid函数
又名 Logistic 函数
,值域为 (0, 1) ,可以将任意一个实数映射到一个介于 (0, 1) 区间之内的值,常用于隐层神经元输出,其函数表达式为: f ( x ) = 1 1 + e − x f(x) = \frac{1}{1+e^{-x}} f(x)=1+e−x1
Tanh 函数
叫做 反正切 函数,值域为 (-1, 1) ,可以将任意一个实数映射到一个介于 (-1, 1) 区间之内的值,其函数表达式为: f ( x ) = e x − e − x e x + e − x f(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}} f(x)=ex+e−xex−e−x
Relu函数
:解析式: R e l u = m a x ( 0 , x ) Relu=max(0,x) Relu=max(0,x),ReLU目前仍是最常用的activation function,在搭建人工神经网络的时候推荐优先尝试
softmax函数
: S i = e i ∑ e j S_i = \frac{e^i}{\sum e^j} Si=∑ejei:映射区间[0,1],主要用于:离散化概率分布,值域为(0,1)
1,导入paddle
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear
树莓派,英语: Raspberry Pi,是可以运行Linux系统的电脑,为英国树莓派基金会所开发,其主要特点为机身小巧和价格低廉,一经推出便受到各种计 算机爱好者、开发者的喜爱。其处理器(CPU) 使用的是(ARM)架构。
在PaddlePaddlel练完成的模型,想要在在树莓派上的推测,需要转换成Paddlelite格式, 转换需要使用工具为opt
Raspbian是树莓派官方推出的操作系统
Paddle-Lite
框架是 PaddleMobile 新一代架构,重点支持移动端推理预测,特点高性能、多硬件、轻量级,支持PaddleFluid /TensorFlow/Caffe/ONNX模型的推理部署,目前已经支持 ARM CPU, Mali GPU, Adreno GPU, Huawei NPU 等多种硬件,正在逐步增加 X86 CPU, Nvidia GPU 等多款硬件,相关硬件性能业内领先。
create_paddle_predictor
函数用来根据CxxConfig
或MobileConfig
构建预测器。
paddle.nn.Linear
实现神经网络的全连接层
2016年,百度开源了PaddIcPaddle,已经发展成为国际主流认可的深度学习平台,下列关于paddlepaddle
说法正确的是(ABCD)。
A、主要包括图像识别、语音识别、情感分析等
B、可以实现CPU/GPU单机和分布式模式
C、支持海量数据、数台机器并行运算
D、该平台易用、高效、灵活和可伸缩等特点
计算机显示器的颜色模型为RGB
常见的颜色空间:RGB颜色空间,HSV颜色空间(色调(H),饱和度(S),明度(V)),HSL颜色空间
数字图像中有 ( ABCD ) 基本特征。
A、颜色特征
B、纹理特征
C、形状特征
D、空间关系特征
从图像工程的角度上,属于机器视觉过程的阶段有 ( ABC )。
A、括数字化成像
B、图像处理
C、图像分析
D、图像分割
Flask是一个使用Python编写的轻量级Web应用框架。关于Flask Web开发,使用Flask之前,需要安装,使用pip命令安装:pip install flask
使用Flask开发Web应用的主要步骤包括(ABCD)。
A、创建Flask对象
B、为每个请求创建一个处理的函数
C、在函数上使用注解的形式标识该函数处理哪个请求
D、在函数入口中使用Flask对象的run方法来启动该应用
边缘计算和云计算的区别:
边缘计算的特点:分布式和低延时,效率更高,安全性高,缓解流量压力,依赖数据端处理芯片的性能,设备故障影响小
计算机视觉
计算机视觉是一门研究如何使机器看的科学
计算机视觉从20世纪80年代就开始蓬勃发展
数据量,运算力和算法模型是影响计算机视觉行业发展的三大要素
百度
百度OCR的接口可以通过http的方式调用,也可以通过OCR Python SDK来调用。通过Python SDK调用时,下面(说法有误。
百度银行卡识别接口可以识别出卡片的信息。支持对主流银行卡的卡号、有效期、发卡行、卡片类型。
百度OCR接口调用:
去百度智能云管理中心新建项目,查看生成的AppID、API Key、Secret Key。正确的加载方式:pip install baidu-aip
细化是将一个曲线型物体细化为一条单像素宽的线,以图形化显示出其拓扑性质。(错)
消除连续区域内的小噪声点可以通过连续多次使用开闭运算(对)
图像分割技术是由图像处理向图像分析阶段过渡过程中必须的。
Q1T1
# 在桌面/quiz/Q1/data目录下有图片chip.png,利用openCV中的函数查找轮廓。
# 通过遍历每个轮廓的最小包围圆,如果圆的半径大于20 则在chip.png图片上画对应的白色圆圈,
# 并将画圆之后的图片保存为chip2.png,代码文件命名为Q1.py,最终将图片和代码保存在桌面/user/Q1目录下。
import cv2 as cv
img = cv.imread("../quiz/Q1/data/chip.png") # 读取图片
# 轮廓得用二进制图像
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 先转换成灰度图像
ret, img2 = cv.threshold(img_gray,155,255,cv.THRESH_BINARY) # 图像二值化
contours, hierarchy = cv.findContours(img2,cv.RETR_TREE,cv.CHAIN_APPROX_NONE)
for ct in contours:
(x,y), radius = cv.minEnclosingCircle(ct)
if(radius > 20.0):
cv.circle(img,(int(x),int(y)),int(radius),(255,255,255),1)
cv.imwrite("Q1/chip2.png",img)
# cv.imshow("chip2",img)
# cv.waitKey(0)
# cv.destroyAllWindows()
Q1T2
#在桌面/quiz/Q1/data目录下有一幅图片contours.jpg,使用轮廓绘制功能,提取前景图(图1)和前景对象的二值化(图2)
#然后逐个显示一幅图像内的边缘信息,图3、4,类似下图:由左图1生成2,3、4。
#分别保存为drawContours.jpg、mask.jpg、contours1.jpg、contours2.jpg,
#代码文件命名为Q1.py,最终将图片和代码保存在桌面/user/Q1目录下。
import cv2 as cv
import numpy as np
img = cv.imread("quiz/Q1/data/contours.jpg") # 读取图片
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 转换成灰度图
ret,img2 = cv.threshold(gray,128,255,cv.THRESH_BINARY) # 转换成二值图
contours,hierarchy = cv.findContours(img2,cv.RETR_TREE,cv.CHAIN_APPROX_NONE) # 查找所有轮廓
mask = np.zeros(img.shape,img.dtype) # 绘制掩膜mask
mask = cv.drawContours(mask,contours,-1,(255,255,255),-1) # 填充轮廓
cv.imwrite("user/Q1/mask.jpg",mask) # 保存图像
dc = cv.bitwise_and(img,mask) # ‘与’操作
cv.imwrite("user/Q1/drawContours.jpg",dc)
# 边缘信息:根据drawContours.jpg绘制轮廓
dc_gray = cv.cvtColor(dc,cv.COLOR_BGR2GRAY) #将drawContours.jpg转换为灰度图
ret,img2 = cv.threshold(dc_gray,128,255,cv.THRESH_BINARY) # 转换成二值图
contours,hierarchy = cv.findContours(img2,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) # 查找重要轮廓
n = len(contours)
for i in range(n):
temp = np.zeros(img.shape,img.dtype) # 临时画板
cv.imwrite("user/Q1/contours"+str(i+1)+".jpg",cv.drawContours(temp,contours,i,(255,255,255),2))
i+=1
Q1T3
# 在桌面/quiz/Q1/data目录下给定的两张图片,使用Python编程操作,利用OpenCV库判断图片的匹配情况。
# 具体流程:首先读取两张图片,初始化SIFT特征提取器,利用特征提取器分别对两个图像提取特征,
# 将两张图片的特征点分别绘制到各自图片上打印出来,
# 创建使用NORM_L2距离测量方式和crossCheck匹配条件的Brute-Force匹配器,
# 对两幅图像的关键点描述进行匹配并输出匹配的数量,最后计算有效的匹配数量,
# 规则为找到匹配的距离的最大值maxdist,然后最大距离作为参考只保留距离小于0.4*maxdist的哪些匹配点。
# 最终将代码保存在桌面/user/Q1目录下。
import cv2 as cv
dog1 = cv.imread("quiz/Q1/data/dog_1.jpg")
dog2 = cv.imread("quiz/Q1/data/dog_2.jpg")
# 初始化SIFT特征提取器
sift = cv.xfeatures2d.SIFT_create()
# 查找和绘制关键点
kp1, des1 = sift.detectAndCompute(dog1, None)
kp2, des2 = sift.detectAndCompute(dog2, None)
# 绘制关键点
kp_img1 = cv.drawKeypoints(dog1, kp1, dog1)
kp_img2 = cv.drawKeypoints(dog2, kp2, dog2)
# 创建一个BFMatcher匹配器
bf = cv.BFMatcher(cv.NORM_L2, crossCheck=True)
# 进行匹配
matches = bf.match(des1, des2)
print(len(matches))
# 对匹配进行排序
matches = sorted(matches, key=lambda x: x.distance)
maxdist = matches[-1].distance
print(maxdist)
# 保留距离小于0.4*maxdist的匹配点
goodMatches = []
for m in matches:
if m.distance < 0.4 * maxdist:
goodMatches.append(m)
else:
continue
print(len(goodMatches))
cv.imshow("kp_img1",kp_img1)
cv.imshow("kp_img2",kp_img2)
cv.waitKey(0)
cv.destroyAllWindows()
Q2T1
# 在桌面/quiz/Q2/data目录下有一段视频in.mp4,请使用python编写代码,读取视频的帧率、宽度、高度值。
# 调用opencv的函数,将该视频另存为flv格式,且视频的帧率、宽、高与in.mp4保持一致,
# 新视频名字为out.flv,代码文件命名为Q2.py,最终将视频和代码保存在桌面/user/Q2目录下
import cv2 as cv
video = cv.VideoCapture("quiz/Q2/data/in.mp4")
width = video.get(cv.CAP_PROP_FRAME_WIDTH)
height = video.get(cv.CAP_PROP_FRAME_HEIGHT)
fps = video.get(cv.CAP_PROP_FPS)
# print("width------>",width)
# print("height----->",height)
# print("fps-------->",fps)
fourcc = cv.VideoWriter_fourcc("F","L","V","1")
vid_flv = cv.VideoWriter("user/Q2/out.flv",fourcc,fps,(int(width),int(height)))
while True:
ret,frame = video.read()
if not ret:
break
vid_flv.write(frame)
video.release()
Q2T2
# 在桌面/quiz/Q2/data目录下有一段视频in.mp4,
# 请使用python编写代码,捕获该视频的第一帧,保存为cap1.jpg图片。
# 然后读取该图片,将图片垂直翻转,保存为cap2.jpg图片,代码文件命名为Q2.py,
# 最终将图片和代码保存在桌面/user/Q2目录下。
import cv2 as cv
video = cv.VideoCapture("quiz/Q2/data/in.mp4")
retval, cap1 = video.read()
cv.imwrite("user/Q2/cap1.jpg",cap1)
# 释放 VideoCapture
video.release()
cap2 = cv.flip(cap1,0)
cv.imwrite("user/Q2/cap2.jpg",cap2)
# cv.imshow("img",cap1)
# cv.waitKey(0)
# cv.destroyAllWindows()
Q3T2
# 在桌面/quiz/Q2/data目录下有许多照片,请使用python编写代码,将图片转换为视频。
# 设置视频的帧率为5fps,视频的大小为(300.200),
# 设置视频保存为avi格式,视频名字为out.avi,代码文件命名为Q2.py,
# 最终将视频和代码保存在桌面/user/Q2目录下。
import cv2 as cv
fourcc = cv.VideoWriter_fourcc('I','4','2','0')
out = cv.VideoWriter("user/Q2/out.avi",fourcc,5,(300,200))
for i in range(1,10):
temp = cv.imread("quiz/Q2/data/"+str(i)+".jpeg")
out.write(temp)
out.release()
Q3T1
#在桌面/quiz/Q3/目录下有代码文件Q3.py,给定CIFAR10数据集(图像大小为32X32),
# 请编写一个卷积神经网络模型完成图像分类模型,最终将代码文件Q3.py保存在桌面/user/Q3目录下。
# 任务一:搭建一个模型,由一层卷积层,一层最大池化层,一层全连接层组成。
# 卷积层包含10个大小为3 X 3的卷积核,步长为1,卷积后特征图尺寸不变;
# 池化层大小为2 X 2,步长为2;
# 全连接层输出图像属于飞机、汽车、鸟类、猫、鹿、狗、青蛙、马、船和卡车共计 10 个类别的概率。
# 部分代码已给出。附:PaddlePaddle常用函数表。
#任务二:进行模型训练。选择Adam的优化方法,学习率为0.001,
# 利用数据集训练模型。要求训练5轮,每一轮中每隔100个batch输出训练损失;
# 每一轮结束后输出模型在验证集上的准确率与损失。训练模型,请补充下列代码:
#1 请补充所需要的依赖包代码
# ___________1____________
import numpy as np
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D,Pool2D,Linear
# ___________1____________
trainset = paddle.dataset.cifar.train10()
testset = paddle.dataset.cifar.test10()
# 包装数据读取器,每次读取的数据数量设置为batch_size=8
train_loader = paddle.batch(trainset, batch_size=8)
valid_loader = paddle.batch(testset, batch_size=8)
# 定义cifar数据识别网络结构
class model_cifar(fluid.dygraph.Layer):
def __init__(self, name_scope, num_classes=10):
super(model_cifar, self).__init__(name_scope)
#2 请补充代码完成网络基本层的定义
# _____________2____________
self.conv = Conv2D(num_channels=3, num_filters=10, stride= 1, padding=1, filter_size=3, act='relu')
self.pool = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
self.fc = Linear(input_dim=2560, output_dim=num_classes, act='softmax')
Conv2D(num_channels=3,num_filters=10,stride=1)
# _____________2____________
def forward(self, input):
#3 请补充代码完成网络结构
# ___________3_____________
input = self.conv(input)
input = self.pool(input)
input = fluid.layers.flatten(input)
output = self.fc(input)
# _____________3____________
return output
def train(model):
model.train()
epochs_num = 5
# _____1_____ #定义优化器
opt = fluid.optimizer.AdamOptimizer(learning_rate=0.001, parameter_list=model.parameters())
train_loss = []
train_acc = []
# _____1_____
for pass_num in range(epochs_num):
for batch_id,data in enumerate(train_loader()): #将数据转换成fluid要求的格式
images=np.array([x[0].reshape(3,32,32) for x in data],np.float32)
labels = np.array([x[1] for x in data], dtype='int64').reshape(-1, 1)
# 调整输入数据形状和类型、构建标签,将numpy.ndarray转化成Tensor
# _________ 2___________
image = fluid.dygraph.to_variable(images)
label = fluid.dygraph.to_variable(labels)
# _________ 2___________
#进行训练预测
predict=model(image)
#获取损失值并计算平均损失值
# __________3___________
loss = fluid.layers.cross_entropy(predict, label)
avg_loss = fluid.layers.mean(loss)
# __________3___________
#计算精度
# __________4___________
acc = fluid.layers.accuracy(predict, label)
train_loss.append(avg_loss.numpy())
train_acc.append(acc.numpy())
# __________4___________
#每100个batch训练完后,显示一次损失值和精度值
# if ___________5_______
if batch_id != 0 and batch_id % 100 == 0:
print("epoch:{},batch_id:{},train_loss:{},train_acc:{}".format(pass_num,batch_id,avg_loss,acc))
#反向传播,计算评价损失
# ___________6__________
avg_loss.backward()
#最小化损失
# ___________7__________
opt.minimize(avg_loss)
#清除梯度值
# ___________8__________
model.clear_gradients()
# 模型验证
model.eval()
accuracies = []
losses = []
for batch_id, data in enumerate(valid_loader()):
# 调整输入数据形状和类型
image = np.array([x[0] for x in data],dtype='float32').reshape(-1, 3, 32, 32)
labels = np.array([x[1] for x in data], dtype='int64').reshape(-1, 1)
# 将numpy.ndarray转化成Tensor ——补充
img = fluid.dygraph.to_variable(image)
label = fluid.dygraph.to_variable(labels)
# 计算模型输出
logits = model(img)
pred = fluid.layers.softmax(logits)
# 计算验证集损失值
# _________9______________
# 计算验证集精度值
# _________10______________
loss = fluid.layers.softmax_with_cross_entropy(logits, label)
acc = fluid.layers.accuracy(pred, label)
accuracies.append(acc.numpy())
losses.append(loss.numpy())
# _________10______________
if __name__ == '__main__':
# 创建模型
with fluid.dygraph.guard():
# 进入训练模型
# _________11______________
model = model_cifar("cifar",num_classes=10)
# _________11______________
#启动训练过程
train(model)
Q3T2
# coding: utf-8
# 给定波士顿房价数据集即uci_housing数据集,请自行补充一个逻辑回归模型完成房价预测模型。附:PaddlePaddle常用函数表。
# 波士顿房价数据说明:此数据源于美国某经济学杂志上,分析研究波士顿房价( Boston HousePrice)的数据集。
# 数据集中的每一行数据都是对波士顿周边或城镇房价的情况描述,下面对数据集变量说明下,方便理解数据集变量代表的意义。
# CRIM: 城镇人均犯罪率
# ZN: 住宅用地所占比例
# INDUS: 城镇中非住宅用地所占比例
# CHAS: 虚拟变量,用于回归分析
# NOX: 环保指数
# RM: 每栋住宅的房间数
# AGE: 1940 年以前建成的自住单位的比例
# DIS: 距离 5 个波士顿的就业中心的加权距离
# RAD: 距离高速公路的便利指数
# TAX: 每一万美元的不动产税率
# PTRATIO: 城镇中的教师学生比例
# B: 城镇中的黑人比例
# LSTAT: 地区中有多少房东属于低收入人群
# MEDV: 自住房屋房价中位数(也就是均价)
# 波士顿房价给出了13个特征维度变量预测房价MEDV。
# 步骤一:准备数据
import paddle.fluid as fluid
import paddle
import os
import matplotlib.pyplot as plt
BUF_SIZE = 500
BATCH_SIZE = 20
# 开启静态图
paddle.enable_static()
# 用于训练的数据提供器,每次从缓存中随机读取批次大小的数据
train_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.uci_housing.train(), buf_size=BUF_SIZE), batch_size=BATCH_SIZE)
# 用于测试的数据提供器,每次从缓存中随机读取批次大小的数据
test_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.uci_housing.test(), buf_size=BUF_SIZE), batch_size=BATCH_SIZE)
# 步骤二:定义网络
# (1)网络结构
# 得分点
# 1、正确定义输入变量(3分)
# 2、正确定义标签变量(3分)
# 3、正确定义全连接层(3分)
# 定义张量变量x,表示13维的特征值
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
# 定义张量y,表示目标值
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
# 定义一个简单的线性网络,连接输入和输出的全连接层
# input:输入tensor;
# size:该层输出单元的数目为1
# act:激活函数默认
y_predict = fluid.layers.fc(input=x, size=1, act=None)
# (2)定义损失函数
# 得分点
# 1、正确求一个batch的损失值(4分)
# 2、正确对损失值求平均值(2分)
cost = fluid.layers.square_error_cost(input=y_predict, label=y) # 求一个batch的损失值
avg_cost = fluid.layers.mean(cost) # 对损失值求平均值
# (3)定义优化函数,采用SGD优化器,学习率为0.001
# 得分点
# 1、正确调用SGD优化器(2分)
# 2、正确求解最小损失(2分)
optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.001)
opts = optimizer.minimize(avg_cost)
# 步骤三:模型训练
# (1)创建Executor
use_cuda = False # use_cuda为False,表示运算场所为CPU;use_cuda为True,表示运算场所为GPU
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
# 创建一个Executor实例exe
exe = fluid.Executor(place)
# Executor的run()方法执行startup_program(),进行参数初始化
exe.run(fluid.default_startup_program())
# (2)定义输入数据维度
# 得分点
# 1、正确定义输入数据维度(4分)
feeder = fluid.DataFeeder(place=place, feed_list=[x, y]) # feed_list:向模型输入的变量表或变量表名
# (3)定义绘制训练过程的损失值变化趋势的方法draw_train_process,x轴为iter,y轴为cost,
# 曲线颜色为红色,图例和图标题为training cost,字体合适。
# # 得分点
# 1、正确定义图层(4分)
# 2、正确定义坐标轴(8分)
# 3、正确定义图例和标题(4分)
iter = 0
iters = []
train_costs = []
def draw_train_process(iters, train_costs):
title = "training cost"
plt.title(title, fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("cost", fontsize=14)
plt.plot(iters, train_costs, color='red', label='training cost')
plt.grid() # 图像带网格,可忽略
plt.show()
# (4)训练并保存模型,每一轮中每隔30个batch输出训练损失,每一轮结束后输出模型在验证集上的损失,并绘制出损失值变化趋势.
# 得分点
# 1、正确遍历train_reader迭代器(6分)
# 2、正确每隔30个batch输出训练损失(2分)
# 3、正确保存模型(3分)
EPOCH_NUM = 50
model_save_dir = "fit_line.inference.model"
for pass_id in range(EPOCH_NUM): # 训练EPOCH_NUM轮
# 开始训练并输出最后一个batch的损失值
train_cost = 0
for batch_id, data in enumerate(train_reader()): # 遍历train_reader迭代器
train_cost = exe.run(program=fluid.default_main_program(), # 运行主程序
feed=feeder.feed(data), # 喂入一个batch的训练数据,根据feed_list和data提供的信息,将输入数据转成一种特殊的数据结构
fetch_list=[avg_cost])
if batch_id % 30 == 0:
print("Pass:%d, Cost:%0.5f" % (pass_id, train_cost[0][0])) # 打印最后一个batch的损失值
iter = iter + BATCH_SIZE
iters.append(iter)
train_costs.append(train_cost[0][0])
# 开始测试并输出最后一个batch的损失值
test_cost = 0
for batch_id, data in enumerate(test_reader()): # 遍历test_reader迭代器
test_cost = exe.run(program=fluid.default_main_program().clone(for_test=True), # 运行测试
feed=feeder.feed(data), # 喂入一个batch的测试数据
fetch_list=[avg_cost]) # fetch均方误差
print('Test:%d, Cost:%0.5f' % (pass_id, test_cost[0][0])) # 打印最后一个batch的损失值
# 保存模型
# 如果保存路径不存在就创建
if not os.path.exists(model_save_dir):
os.makedirs(model_save_dir)
print('save models to %s' % model_save_dir)
# 保存训练参数到指定路径中,构建一个专门用预测的program
fluid.io.save_inference_model(model_save_dir, # 保存推理model的路径
['x'], # 推理(inference)需要 feed 的数据
[y_predict], # 保存推理(inference)结果的 Variables
exe) # exe 保存 inference model
draw_train_process(iters, train_costs)
Q3T3
# coding: utf-8
# 给定手写数字识别PaddlePaddle模型参数文件:mnist.pdparams及卷积神经网络的结构定义,
# 请基于PaddlePaddle使用Python编写推理程序对给定手写数字图片进行识别,
# 模型参数文件和待识别图片在桌面/quiz/Q3/data目录下,最终将代码保存在桌面/user/Q3目录下。
# 卷积神经网络的结构定义:
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear
import numpy as np
import cv2
# 定义模型结构
class MNIST(fluid.dygraph.Layer):
def __init__(self):
super(MNIST, self).__init__()
# 定义一个卷积层,使用relu激活函数
self.conv1 = Conv2D(num_channels=1, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
# 定义一个池化层,池化核为2,步长为2,使用最大池化方式
self.pool1 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
# 定义一个卷积层,使用relu激活函数
self.conv2 = Conv2D(num_channels=20, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
# 定义一个池化层,池化核为2,步长为2,使用最大池化方式
self.pool2 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
# 定义一个全连接层,输出节点数为10
self.fc = Linear(input_dim=980, output_dim=10, act='softmax')
# 定义网络的前向计算过程
def forward(self, inputs):
x = self.conv1(inputs)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = fluid.layers.reshape(x, [x.shape[0], 980])
x = self.fc(x)
return x
# 任务一:
# 编写一个图像预处理函数load_image,对指定路径图片进行数据预处理,
# 其中图像处理请使用OpenCV。处理流程为:首先读取数据目录下的待识别图片,
# 然后缩放大小为28X28,将其转换为灰度图,再转换为numpy数组,调整形状为(1, 1, 28, 28),
# 数据类型设置为float32,再对其进行归一化处理,最后返回处理后的数据。
# 得分点
# 1. 正确定义函数(2分)
# 2. 使用OpenCV进行图像处理(3分)
# 3. 正确加载图像(2分)
# 4. 正确缩放图像(3分)
# 5. 正确转换为灰度图(3分)
# 6. 正确转换为numpy数组(3分)
# 7. 正确调整数组形状(3分)
# 8. 正确设置数据类型(3分)
# 9. 正确进行归一化处理(3分)
def load_image(img_path):
img = cv2.imread(img_path)
img = cv2.resize(img, (28, 28))
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
img = np.array(img).reshape(1, 1, 28, 28).astype(np.float32)
img = 1.0 - img / 255.
return img
# 任务二:
# 编写推理代码,识别数据目录下的图片内容。首先打开PaddlePaddle动态图的模式,
# 实例化化MNIST模型得到模型对象,使用模型对象加载模型参数文件(mnist.pdparams,位于数据目录),
# 设置模型对象为评估模式,即仅用于预测,对数据目录下的待识别图片调用load_image函数得到预处理后数据,
# 将数据置入模型得到预测结果返回,对返回结果处理获取置信度最高的值的索引值,即预测值。
# 得分点
# 1. 正确打开PaddlePaddle动态图的模式(3分)
# 2. 正确实例化化MNIST模型(2分)
# 3. 正确加载模型参数文件(5分)
# 4. 正确设置设置模型对象为评估模式(5分)
# 5. 正确使用模型得到预测结果(5分)
# 6. 正确获取置信度最高预测值(5分)
with fluid.dygraph.guard():
model = MNIST()
model_dict, _ = fluid.load_dygraph("../../quiz/Q3/data/mnist")
model.load_dict(model_dict)
model.eval()
tensor_img = load_image('../../quiz/Q3/data/0.jpg')
results = model(fluid.dygraph.to_variable(tensor_img))
lab = np.argsort(results.numpy())
print("预测结果: ", lab[0][-1])