python课程记录-10

这一课是numpy库。

import numpy as py

创建数组基本方法:

  1. array()

    python对象转换为数组

  2. empty()

    分配指定大小数组,不初始化

  3. zeros(),ones()

    建立全为0或1的数组

  4. eye(),diag()

    建立对角矩阵

  5. arange()

    初值、终值、步长建立一维数组

  6. linspace()

    初值、终值、元素个数建立一维数组

  7. logspace

    初值、终值、元素个数建立等比数列

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
a = np.array((1,2,3,4))
array([1, 2, 3, 4])
b = np.array([[1,2,3,4],[4,5,6,7],[7,8,9,10]])
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10]])
c = a.tolist()
[1,2,3,4]
d = np.empty((2,2)) #这里数组维数必须是是元组
array([[9.90263869e+067, 9.38159477e-312],
[0.00000000e+000, 9.38983138e-312]])
e = np.ones((2,2))
array([[1., 1.],
[1., 1.]])
f = np.diag((2,3,4))
array([[2, 0, 0],
[0, 3, 0],
[0, 0, 4]])
g = np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
h = np.eye(2,3)
array([[1., 0., 0.],
[0., 1., 0.]])
i = np.arange(5,10,1)
array([5, 6, 7, 8, 9])
j = np.linspace(5,10,4)
array([ 5. , 6.66666667, 8.33333333, 10. ])
k = np.logspace(0,1,5)
array([ 1. , 1.77827941, 3.16227766, 5.62341325, 10. ])

数组的基本属性

  1. ndim:数组的维度,也就是有几行
  2. shape:数组每维大小,元组形式
  3. size:数组里一共多少个元素
  4. dtype:数组数据类型
  5. itemsize:元素字节数
1
2
3
4
5
d1 = np.array([1,2,3,4,5,6])
d2 = np.array([[1,2,3],[4,5,6]])
d3 = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
print(d1.ndim, d2.ndim, d3.ndim) # 1 2 3
print(d1.shape, d2.shape, d3.shape) # (6,) (2, 3) (2, 2, 3)

数组操作

  1. 改变数据类型:astype
1
2
a = np.array([1.7, 1.2, 1.6])
b = a.astype(int) # b = array([1, 1, 1])

形状操作

  1. reshape

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import numpy as np
    a = np.array([1,2,3,4,5,6])
    b = a.reshape((2,3))
    # b = array([[1, 2, 3],
    # [4, 5, 6]])
    a[0]=10
    # a = array([10, 2, 3, 4, 5, 6])
    # b = array([[10, 2, 3],
    # [4, 5, 6]])
    b[0][0]=5
    # a = array([5, 2, 3, 4, 5, 6])
    # b = array([[5, 2, 3],
    # [4, 5, 6]])
    c = b.reshape((-1,2))
    # array([[5, 2],
    # [3, 4],
    # [5, 6]])
  2. shape:和reshape差不多的用法,a.reshape((-1,2))a.shape=(-1,2)效果是一样的

  3. resize:同上,a.resize((-1,2)),注意reshape和resize的参数是元组,而shape的参数则不是元组。此外,一般来说reshape有返回值,不对原始多维数组进行修改;resize无返回值,会对原始多维数组进行修改。但其实resize和reshape都可以有返回值,也都可以没有返回值,区别在于,reshape是改变形状而不改变数据量,或者说改变数组维度,如果reshape之后的元素数量和之前的不一致就会报错,但是resize不会,元素多了就去掉,少了就补零。

  4. ravel:扁平化,多维变成一维数组,但是修改ravel之后的元素,导致原始数组的元素跟着变。

  5. flatten:扁平化,多维变成一维数组,修改flatten之后的元素,不会导致原始数组的元素跟着变。

1
2
3
4
5
6
7
8
9
10
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
b = a.ravel() # b = ([1,2,3,4,5,6])
b[0]=99
#a = array([[99, 2, 3],
# [ 4, 5, 6]])
c = a.flatten() # c = ([99, 2, 3, 4, 5, 6])
c[1]=98
#a = array([[99, 2, 3],
# [ 4, 5, 6]])
  1. 转置:数组.T

数组组合

  1. hstack:水平

  2. vstack:垂直

  3. concatenate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import numpy as np
    a = np.array([[0,1,2],[3,4,5]])
    b = np.array([[0,2,4],[6,8,10]])
    c = np.hstack((a,b))
    # [[ 0 1 2 0 2 4]
    # [ 3 4 5 6 8 10]]
    d = np.vstack((a,b))
    # [[ 0 1 2]
    # [ 3 4 5]
    # [ 0 2 4]
    # [ 6 8 10]]
    e = np.concatenate((a,b),axis=1)
    # [[ 0 1 2 0 2 4]
    # [ 3 4 5 6 8 10]]
    f = np.concatenate((a,b),axis=0)
    # [[ 0 1 2]
    # [ 3 4 5]
    # [ 0 2 4]
    # [ 6 8 10]]

数组分割

  1. hsplit:水平
  2. vsplit:垂直
  3. split
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
a = np.array([[0,1,2],[3,4,5]])
a1, a2, a3 = np.hsplit(a,3)
b1, b2 = np.vsplit(a,2)
c1, c2 = np.split(a, 2, axis=0)
# a1 = [[0]
# [3]]
# a2 = [[1]
# [4]]
# a3 = [[2]
# [5]]
# b1 = [[0 1 2]]
# b2 = [[3 4 5]]
# c1 = [[0 1 2]]
# c2 = [[3 4 5]]

访问数组元素

  1. 切片下标:和列表切片一样,修改切片后的元素会导致原始数组改变

  2. 高级下标:

    1. 整数列表/元组作为下标

    2. 整数数组作为下标

    3. 布尔数组作为下标

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      array([10,9,8,7,6,5,4,3,2])
      # 1
      b = a[[0,-1,5,7]] #array([10,2,5,3])
      # 2
      c = a[np.array([3,3,-3,8])] #array([7,7,4,2])
      d = a[np.array([[3,3,-3,8],[1,2,3,4]])] #array([[7,7,4,2],[9,8,7,6]])
      # 3
      array([5,4,3,2,1])
      b = a[np.array([True,False,True,False,False])] #array([5,3])
      a[np.array([True,False,True,True,False])] = -1, -2, -3
      #array([-1, 4, -2, -3, 1])
      x = np.random.rand(4)
      # [0.75217218 0.49197318 0.0754037 0.8145583 ]
      x > 0.5
      # [ True False False True]
      x[x>0.5]
      # [0.75217218 0.8145583 ]
    4. 多维数组:数组不同维数的坐标用,隔开,例如二维数组aa[0,1]中,0是第一维(行),1是第二维(列),每个维度内可以用切片的方式访问,例如a[0,3:5]a[:,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
      # 数组
      # 0, 1, 2, 3, 4, 5
      # 10,11,12,13,14,15
      # 20,21,22,23,24,25
      # 30,31,32,33,34,35
      # 40,41,42,43,44,45
      # 50,51,52,53,54,55
      a[0, 3:5] # 第0行第3列和第4列
      # array([3,4])
      a[4:,4:] # 第4、5行和第4、5列
      # array([[44,45],[54,55]])
      a[:,2] # 第2列
      # array([ 2, 12, 22, 32, 42, 52])
      a[2,:] # 第2行
      # array([20, 21, 22, 23, 24, 25])
      a[2::2, ::2] #第2行到最后一行,步长2;所有列,步长2
      # array([[20, 22, 24], [40, 42, 44]])
      a[(0,1,2,3,4),(1,2,3,4,5)] #坐标为(0,1)(1,2)(2,3)(3,4)(4,5)的元素
      # array([1,12,23,34,45])
      a[3:,[0,2,5]] #第3行到最后一行,第0、2、5列
      # array([[30, 32, 35], [40, 42, 45], [50, 52, 55]])
      mask=np.array([1,0,1,0,0,1], dtype=bool)
      a[mask,2]
      # array([2,22,52])
      a[[1,2]] #相当于a[[1,2],:]
      # array([[10, 11, 12, 13, 14, 15], [20, 21, 22, 23, 24, 25]])
      x=np.array([[1,2],[3,4]])
      y=np.array([[1,1],[2,2]])
      a[x] #从2维数组变成3维数组
      # [[[10 11 12 13 14 15]
      # [20 21 22 23 24 25]]
      # [[30 31 32 33 34 35]
      # [40 41 42 43 44 45]]]
      a[x,y] # x和y的元素分别作为两个维度的坐标
      # x = 1 2
      # 3 4
      # y = 1 1
      # 2 2
      #a[x,y]=[a[1][1] a[2][1]
      # a[3][2] a[4][2]]
      # = [[11 21]
      # [32 42]]

ufunc

  1. 对数组中每个元素进行操作的函数,不需要写for循环
     2. 常用操作:加减乘除取余乘方、比较运算、布尔运算等等
     3. 自定义ufunc: frompyfunc(func, nin, nout)

其他函数操作

  1. 求和sum
  2. 平均值mean/average
  3. 方差var
  4. 标准差std
  5. 中位数median
  6. 最值min、max、ptp、argmin、argmax
  7. 排序sort、argsort
  8. 查找nonzero(a)、where(condition[,x,y])

广播(这部分短期内应该用不到,就不写了)

  1. 让数组shape相同的操作
  2. orrid对象
  3. mgrid和meshgrid函数

文件存取

  1. 这部分短期内应该也就读个图像,不看了

课后作业

读入图像文件Cat.jpg,并通过numpy的数组操作对图像进行修改,得到下面一系列图像:

  1. 反色图像:r、g、b为原始像素颜色,则反色后的颜色为255-r、255-g、 255-b
  2. 灰度图像: r、g、b为原始像素颜色,变成灰度的公式为: Gray = r0.299 + g0.587 + b*0.114
  3. 水平镜像图像:左右交换
  4. 垂直镜像图像:上下交换
  5. 行和列转置后的图像
  6. 逆时针旋转90°后的图像
  7. 红色/绿色/蓝色通道图像:其余两通道颜色为0, 0
  8. 红色通道的颜色替换成红色通道的最大值
  9. 红色/绿色/蓝色通道重新组合,红色变成蓝色,绿色变成红色,蓝色变成绿色

思路

首先读入图像:im = np.array(Image.open("cat.jpg"))

其次考虑保存图像,这里写了一个函数,把数组转为图像并按指定名称保存:

1
2
3
4
5
def saveimg(img, index):
img = Image.fromarray(img.astype('uint8'))
img.show()
img.save('Cat' + index + '.jpg')
return

接下来就是图像处理部分了,考虑到有通道分离的要求,所以先把3个通道的数据提取出来,彩色图像变成数组时,是用三维数组存储的,前两个维度表示行列对应位置的像素值,第三个维度表示颜色通道,这里的通道顺序是rgb(而如果用opencv库的话,就是gbr),也就是说,im[0,0,0]、im[0,0,1]、im[0,0,1]就分别表示左上角那个像素的红色、绿色和蓝色值,这三个值叠加以后的结果就是彩色图像看上去的颜色,因此分离通道后,得到的是3个二维数组,如下:

r, g, b = im[:, :, 0], im[:, :, 1], im[:, :, 2]

  1. 反色:这里构造一个和im尺寸一致且元素都是255的新数组,用这个新数组减去im即可。

    im2 = np.ones_like(im) * 255 - im

  2. 灰度:按照公式对分离出来的r、g、b三个通道进行运算即可。

    im3 = r * 0.299 + g * 0.587 + b * 0.114

  3. 水平镜像:每一行的元素逆序

    这里是二维数组,也就是说要逆序的是列坐标,所以是第二维逆序

    im4 = im[:, ::-1]

  4. 垂直镜像:每一列的元素逆序

    同上,第一维逆序

    im5 = im[::-1]

  5. 转置:这里的图像是三维数组,所以使用transpose函数来做,简单来说就是原本的第一、二维交换顺序,也就是transpose(0,1,2)—>transpose(1,0,2)

    im6 = im.transpose(1, 0, 2)

  6. 逆时针90度:矩阵逆时针90度的操作是左乘一个负对角线上均是1、其余都是0的方阵,也就是说,转置矩阵逆序即可

    im7 = im.transpose(1, 0, 2)[::-1]

  7. 三通道图像:把其他通道都变成0即可,最后把3个图拼起来

    1
    2
    3
    4
    5
    6
    7
    B_im = im.copy()
    B_im[:, :, [0, 1]] = 0
    G_im = im.copy()
    G_im[:, :, [0, 2]] = 0
    R_im = im.copy()
    R_im[:, :, [2, 1]] = 0
    im8 = np.concatenate((R_im, G_im, B_im), axis=1)
  8. 红色拉满:把红色通道变成255即可

    1
    2
    im9 = im.copy()
    im9[:, :, 0] = 255
  9. 通道重组:这里要想明白通道怎么组合,剩下的就很好做了。红色变成蓝色,绿色变成红色,蓝色变成绿色,也就是原本是红色的数值要变成蓝色通道,绿色数值变成红色通道,蓝色数值变成绿色通道,因此通道原本的(0,1,2)变成现在的(1,2,0)

    1
    2
    im10 = im.copy()
    im10 = im10[:, :, [1, 2, 0]]
  • Copyrights © 2020-2024 Kun Li

请我喝杯咖啡吧~

支付宝
微信