numpy库处理的是最起初数据类型是由同种元素构成的多维数组,也就是所谓的数组。数组中的所有元素的类型必须相同,数组中元素可以用整数索引,序号从0开始。
数组类型的维度叫做轴(axes),轴的个数叫做秩(rank)。例如,一维数组的秩为1,二维数组的秩为2。
通常用import numpy as np
引入numpy库,以免混淆
一、numpy介绍
- numpy库常用创建数组函数有以下7个
函数 | 描述 |
---|---|
np.array([x, y, z], dtype = int) | 从python列表和元组创建数组 |
np.arange(x, y, i) | 创建一个由x到y,步长为i的数组 |
np.linspace(x, y, n) | 创建一个由x到y,等分成n个元素的数组 |
np.indices((m, n)) | 创建一个m行n列的矩阵 |
np.random.rand(m, n) | 创建一个m行n列的随机数组 |
np.ones((m, n), dtype) | 创建一个m行n列全1的数组,dtype是数据类型 |
np.empty((m, n), dtype) | 创建一个m行n列全0的数组,dtype是数据类型 |
>>>import numpy as np
>>>a = np.ones((4,5))
>>>a
array([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
- 在创建好数组后,通过以下方法查看基本属性
属性 | 描述 |
---|---|
ndarray.ndim | 数组轴的个数 |
ndarry.shape | 数组在每个维度上大小的整数元祖 |
ndarray.size | 数组元素的总个数 |
ndarray.dtype | 数组元素的数据类型,dtype类型可以用于创建数组 |
ndarray.itemsize | 数组中每个元素的字节大小 |
ndarray.data | 包含实际数组元素的缓冲区地址 |
ndarray.flat | 数组元素的迭代器 |
>>>a.ndim
2
>>>a.shape
(4, 5)
>>>a.size
20
>>>a.dtype
dtype('float64')
>>>a.itemsize
8
>>>a.data
<memory at 0x00000269B5FB5708>
>>>a.flat
<numpy.flatiter at 0x269b5780460>
- 改变数组基础形态的操作方法
数组在numpy中被当做对象,可以采用以下方法进行操作。(其中flatten()用于数组降维,在矩阵运算及图像处理中用处很大)
方法 | 描述 |
---|---|
ndarray.reshape(n, m) | 不改变数组ndarray,返回一个维度为(n, m)的数组 |
ndarray.resize(new_size) | 与reshape()作用相同,直接修改数组ndarray |
ndarray.swapaxes(ax1, ax2) | 将数组n个维度中任意两个维度进行调换 |
ndarray.flatten() | 对数组进行降维,返回一个折叠后的一维数组 |
ndarray.ravel() | 作用同flatten()相同,但是返回的是一个数组的视图 |
>>>a.ravel()
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1.])
- numpy类的索引和切片
数组切片得到的是原始数组的视图,所有修改都会直接反映到源数组
方法 | 描述 |
---|---|
x[i] | 索引第i个元素 |
x[-i] | 从后向前索引第i个元素 |
x[n:m] | 默认步长为1,从前往后索引,不包含m |
x[-m:-n] | 默认步长为1,从后往前索引,结束位置为n |
x[n:m :i] | 指定i步长的由n到m的索引 |
>>>b = np.random.rand(5,3);b
array([[0.59532428, 0.72198343, 0.31319579],
[0.53958629, 0.01385479, 0.35459807],
[0.06605026, 0.78682018, 0.16177456],
[0.37520112, 0.93865079, 0.9332923 ],
[0.97885532, 0.06937877, 0.925661 ]])
>>>b[2]
array([0.06605026, 0.78682018, 0.16177456])
>>>b[1:3]
array([[0.53958629, 0.01385479, 0.35459807],
[0.06605026, 0.78682018, 0.16177456]])
- numpy的算术及比较运算函数
numpy的算术运算函数有以下8个
函数 | 描述 |
---|---|
np.add(x1, x2, [,y]) | y = x1 + x2 |
np.subtract(x1, x2, [,y]) | y = x1 - x2 |
np.multiply(x1, x2, [,y]) | y = x1 * x2 |
np.divide(x1, x2, [,y]) | y = x1 / x2 |
np.floor_divide(x1, x2, [,y]) | y = x1 // x2 |
np.negative(x, [,y] | y = -x |
np.power(x1, x2, [,y]) | y = x1 ** x2 |
np.remainder(x1, x2, [,y]) | y = x1 % x2 |
numpy的比较运算函数有以下7个
函数 | 描述 |
---|---|
np.equal(x1, x2, [,y]) | y = x1 == x2 |
np.not_equal(x1, x2, [,y]) | y = x1 != x2 |
np.less(x1, x2, [,y]) | y = x1 < x2 |
np.less_equal(x1, x2, [,y]) | y = x1 <= x2 |
np.greater(x1, x2, [,y]) | y = x1 > x2 |
np.greater_equal(x1, x2, [,y]) | y = x1 >= x2 |
np.where(condition[x, y]) | 根据给出的条件判断输出x还是y |
- numpy还有其他一些实用的函数
函数 | 描述 |
---|---|
np.abs(x) | 计算基于元素的整型、浮点型或复数的绝对值 |
np.sqrt(x) | 计算每个元素的平方根 |
np.squre(x) | 计算每个元素的平方 |
np.sign(x) | 计算每个元素的符号:1(+)、0、-1(-) |
np.ceil(x) | 计算大于或等于每个元素的最小值 |
np.floor(x) | 计算小于或等于每个元素的最大值 |
np.rint(x, [,out]) | 圆整、取每个元素为最近的整数,保留数据类型 |
np.exp(x, [,out]) | 计算每个元素的指数值 |
np.log(x), np.log10(x), np.log2(x) | 计算自然对数(e),基于10/2的对数 |
二、实例操作
下面将numpy与之前的PIL结合来提取图像特征形成手绘效果
- 图像的基本处理
>>>from PIL import Image
>>>import numpy as np
>>>im = np.array(Image.open(r'C:\Users\acer\Desktop\flash.jpg'))#加载图像并转换成数组对象
>>>print(im.shape, im.dtype)
(553, 960, 3) uint8
其中(553,960,3)分别表示长度、宽度(单位是像素)以及RGB值
>>>im = np.array(Image.open(r'C:\Users\acer\Desktop\flash.jpg').convert('L'))
>>>print(im.shape, im.dtype)
(553, 960) uint8
通过convert()
将图片转换成带有灰度的黑白色,ndarray也变为二维数据
>>>im0 = np.array(Image.open(r'C:\Users\acer\Desktop\flash.jpg').convert('L'))
>>>im1 = 255 - im0 #反变换
>>>im2 = (100/255)*im0 + 150 #区间变换
>>>im3 = 255 * (im1/255) ** 2 #像素平方处理
>>>pil_im1 = Image.fromarray(np.uint(im1))
>>>pil_im2 = Image.fromarray(np.uint(im2))
>>>pil_im3 = Image.fromarray(np.uint(im3))#分别对im1、im2、im3执行
>>>pil_im1.show()
>>>pil_im2.show()
>>>pil_im3.show()
效果图:(左上为原图)
- 手绘效果处理
为了实现手绘风格,首先需要读取原图像的明暗变化。通常可以使用梯度计算来提取图像轮廓,在numpy中即使用gradient()函数
附上代码
from PIL import Image
import numpy as np
vec_el = np.pi/2.2 #光源的俯视角度,弧度值
vec_az = np.pi/4. #光源的方位角度,弧度值
depth = 10. #(0-100)
im = Image.open(r'C:\Users\acer\Desktop\flash.jpg').convert('L')
a = np.asarray(im).astype('float')
grad = np.gradient(a) #取图像灰度的梯度值
grad_x, grad_y = grad #分别取横纵图像梯度值
grad_x = grad_x * depth / 100.
grad_y = grad_y * depth / 100.
dx = np.cos(vec_el) * np.cos(vec_az) #光源对x轴的影响
dy = np.cos(vec_el) * np.sin(vec_az) #光源对y轴的影响
dz = np.sin(vec_el) #光源对z轴的影响
A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)
uni_x = grad_x / A
uni_y = grad_y / A
uni_z = 1. / A
a2 = 255 * (dx*uni_x + dy*uni_y +dz*uni_z) #光源归一化
a2 = a2.clip(0, 255)
im2 = Image.fromarray(a2.astype('uint8')) #重构图像
im2.save(r'C:\Users\acer\Desktop\flashHandDraw.jpg')
在上述代码中,利用梯度重构图像时,对应不同梯度取0~255之间不同的灰度值,depth的作用在于调节这个对应关系。当depth较小时,背景区接近白色,显示轮廓描绘;当depth较大时,整体画面灰度值较深,显示浮雕效果
最后附上图片效果
原图:
效果图1(depth = 10):
效果图2(depth = 40):