numpy 和图像处理结合

2021-04-13 15:00:53 浏览数 (1)

NumPy 是一个运行速度非常快的数学库,主要用于数组计算,支持大量的维度数组与矩阵运算。

简单点说,涉及到数字计算等都可以使用,它的优势在于底层是C语言开发的,处理速度非常快。

看一个例子:计算 a^2 b^2

1.使用列表计算

代码语言:javascript复制
import numpy as np

a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = []
for i in range(len(a)):
    s = a[i]*a[i] b[i]*b[i]
    c.append(s)
print(c)

结果

代码语言:javascript复制
[37, 53, 73, 97, 125]

2.使用numpy 计算

代码语言:javascript复制
import numpy as np

a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = np.array(a)**2 np.array(b)**2
print(c)

结果

代码语言:javascript复制
[ 37  53  73  97 125]

总结:numpy 把列表看成单个元素,省去了从列表中提取出来,然后处理又返回去,直接一步到位。


numpy 在科研计算或者数据分析方面用的还是比较多的,但是一般人平时好像都不怎么用。主要是找不到应用场景或者习惯于用老方法。

其实 numpy 用来造数据或者对多维列表处理是非常方便的,我平常用的主要也是处理这些。


生成全是1的 ndarray 数值

代码语言:javascript复制
import numpy as np
#  一维数组:ones生成
one = np.ones(3)  # 创建包含3个元素且值全为1的一维数组
print(one)
print(type(one))

结果

代码语言:javascript复制
[1. 1. 1.]
<class 'numpy.ndarray'>

数字3写成n,就能生成带有 n 个 1 的数组。

对应的 np.zeros(n) 生成的就是元素值为 0 的数组


生成3行2列,全是1的 ndarray 数值

代码语言:javascript复制
import numpy as np
#  二维数组:ones生成
one = np.ones([3,2])  # 创建二维数组
print(one)
print(type(one))

结果

代码语言:javascript复制
[[1. 1.]
 [1. 1.]
 [1. 1.]]
<class 'numpy.ndarray'>

数字3和2表示行数和列数。更多维度继续增加即可,通常2维用的比较多。


生成三维数组,数字可以指定

代码语言:javascript复制
import numpy as np
#  三维数组
full = np.full([2,3,4],8)
print(full)
print(type(full))

结果

代码语言:javascript复制
[[[8 8 8 8]
  [8 8 8 8]
  [8 8 8 8]]

 [[8 8 8 8]
  [8 8 8 8]
  [8 8 8 8]]]
<class 'numpy.ndarray'>

生成有序数组

和random库的 range方法一样用,其实包含了random库的全部功能

代码语言:javascript复制
import numpy as np

arange = np.arange(1,10,2)
print(arange)
print(type(arange))

结果

代码语言:javascript复制
[1 3 5 7 9]
<class 'numpy.ndarray'>

上面的一些方法,对于生成大量的数字非常有用,不用循环就可以搞定。

不过生成的数组类型是 ndarray ,直接和 python 的列表是不能计算操作的,如果习惯使用列表对数据处理,可以使用 tolist() 方法将 ndarray 类型转换成你熟悉的列表数据类型。

代码语言:javascript复制
import numpy as np

arange = np.arange(1,10,2)
print(arange)
print(type(arange))

# 转换成列表
new_arange = arange.tolist()
print(new_arange)
print(type(new_arange))

结果

代码语言:javascript复制
[1 3 5 7 9]
<class 'numpy.ndarray'>
[1, 3, 5, 7, 9]
<class 'list'>

更多其它方法,可以查看 numpy 的官方文档。


下面看看我是怎样利用numpy 对图片的数据进行处理的。

为了便于观看数据,下面故意图片变小了一些

将上面的图片变成3*3大小的

代码语言:javascript复制
img = Image.open("数字_0.jpg").resize((3,3))

它对应的像素数据是下面这样的,3*3*3

代码语言:javascript复制
[
  [[0, 0, 0], [1, 1, 1], [0, 0, 0]],
  [[1, 1, 1], [255, 255, 255], [0, 0, 0]],
  [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
]

同样的方法,再打开数字 1,获取其对应的数据

代码语言:javascript复制
img2 = Image.open("数字_1.jpg").resize((3,3))

它对应的像素数据是下面这样的,3*3*3

代码语言:javascript复制
[
  [[255, 255, 255], [2, 2, 2], [255, 255, 255]], 
  [[255, 255, 255], [2, 2, 2], [255, 255, 255]], 
  [[255, 255, 255], [2, 2, 2], [255, 255, 255]]
]

如果要将两张图片水平方向合成在一起。

只需要将它们的数据,横向组成在一起就可以了。

得到下面这种数据结构。

代码语言:javascript复制
[
  [[0, 0, 0], [1, 1, 1], [0, 0, 0]],[[255, 255, 255], [2, 2, 2], [255, 255, 255]], 
  [[1, 1, 1], [255, 255, 255], [0, 0, 0]],[[255, 255, 255], [2, 2, 2], [255, 255, 255]], 
  [[0, 0, 0], [0, 0, 0], [0, 0, 0]][[255, 255, 255], [2, 2, 2], [255, 255, 255]]
]

用列表的话,相信你应该知道怎么操作,循环遍历拼接就可以了。不过想想还是挺麻烦的。

用 numpy 处理的话就非常简单了。hstack可以将两个列表直接水平方向拼接在一起。

代码语言:javascript复制
np.hstack((图片0数据, 图片1数据))

先看一个纯数字列表案例

代码语言:javascript复制
import numpy as np

zero = [
    (0, 0, 0),
    (0, 0, 0),
    (0, 0, 0),
]
one = [
    (1, 1, 1),
    (1, 1, 1),
    (1, 1, 1),
]
# Horizontal 水平拼接
a = np.hstack((zero, one))
print(a)
# vertical 竖直拼接
b = np.vstack((zero, one))
print(b)

结果

代码语言:javascript复制
[[0 0 0 1 1 1]
 [0 0 0 1 1 1]
 [0 0 0 1 1 1]]
 
[[0 0 0]
 [0 0 0]
 [0 0 0]
 [1 1 1]
 [1 1 1]
 [1 1 1]]

证明确实可以,下面将其用到图片上

代码语言:javascript复制
import numpy as np 
from PIL import Image

# 打开图片,并将图片数据转换成ndarray 数组
img = np.array(Image.open("数字图片/数字_0.jpg"))
img2 = np.array(Image.open("数字图片/数字_1.jpg"))
# 利用np.hstack将 img 和 img2 数据进行拼接
b = np.hstack((img, img2))
# 将ndarray数据重新转换回图片数据格式
image = Image.fromarray(b)
# 显示图片
image.show()
# 保存图片
image.save("new.jpg")

(全文完)


欢迎转载,转载请注明出处! 欢迎关注公众微信号:叶子陪你玩编程

0 人点赞