一、学习目标
- 了解图片的通道与数组结构
- 了解使用numpy创建一个图片
- 了解使用numpy对图片的一般操作方法
如有错误欢迎指出~
二、了解numpy对图像的编辑
2.1 了解zeros方法的使用方法并且输入了解uint8类型
在前两节中,我们对图像的属性进行了查看,得到了宽、高以及通道,但是我们对整体的图片数据结构还是存在一定的不理解;这一节将加深对图片数据结构上的理解,方便我们接下来的学习。
首先我们需要使用numpy创建一张图片,从最基本的操作逐步对图像数据结构进行了解。我们先在代码头部引入所需库:
代码语言:javascript复制import cv2
import numpy as np
引入之后,我们可以使用numpy创建一个指定大小以及通道数的图片数据;可以使用numpy的zeros方法。zeros方法可以把数组转换为我们所需要的矩阵,并且这个数组将会以0这个元素进行填充。zeros接收3个参数,第一个参数为shape形状,这个形状指你这个数组需要的维度;第二个接收的参数为dtype,表示该数组的数据类型,默认为numpy.float64;第三个接收的参数为order,这个参数是可选参数,有2个默认选项,分别是C与F,表示是行优先还是列优先,由于我们现在用不到所以暂时不做过多讲解。
搞明白了zeros方法的参数后,我们可以简单的创建一个一位数组:
代码语言:javascript复制data=np.zeros(3)
print(data)
以上代码是创建了有3个元素的一维数组,用0进行填充,并且将值进行输出,结果如下:
那如何创建一个二维数组呢?很简单,但很多人会写错,以下是个错误示例:
代码语言:javascript复制data=np.zeros(3,2)
以上使用逗号进行间隔后,2作为了第二个参数dtype,但是dtype中并没有该类型,所以导致了错误,将会提示:
这是进行传参应该使用方括号或者圆括号将参数进行说明,代码如下:
代码语言:javascript复制data=np.zeros([3,2])
或
代码语言:javascript复制data=np.zeros((3,2))
运行结果如下:
我们已知第二个参数dtype,接下来我们尝试一下使用uint8类型对创建进行指定:
代码语言:javascript复制data=np.zeros((3,2),np.uint8)
print(data)
得到结果为:
由于在第一节中,我们已了解uint8的数据范围就是0-255,我们将创建的3行2列的数组第0列第0个做加法运算,增加258,查看是否将会数据溢出:
代码语言:javascript复制data=np.zeros((3,2),np.uint8)
data[0][1]=data[0][1] 258
print(data[0][1])
运行结果如下:
结果正确,数据并没有超过258,通过这个示例我们更加的了解了uint8该类型的取值范围。
2.2 了解使用numpy创建与图片数据结构一致的数据类型
我们已知一张图片的数据类型为uint8,并且是3通道的,那么我们这时将可以通过zeros创建一张与图片数据结构类似的图片。现在我们创建一张长宽都为3,通道为3的数组矩阵:
代码语言:javascript复制data=np.zeros((3,3,3),np.uint8)
print(data)
这个查看数据:
以上结构很方便我们了解整个结构,接下来修改数据创建一个200*200,有3个通道的矩阵:
代码语言:javascript复制data=np.zeros((200,200,3),np.uint8)
创建完毕后我们可以使用显示我们创建的一张“图片”,并且需要添加等待,不然整个程序将会一闪而过:
代码语言:javascript复制data=np.zeros((200,200,3),np.uint8)
cv2.imshow("dataImg",data)
运行结果如下:
这个时候将会得到一张纯黑色的图片。我们现在可以通过搜索引擎查看对应纯黑色的RGB值是多少,我通过搜索引擎查看,得到了0 0 0 为黑色;恰好,我们的数据都是以0作为填充的,所以结果为正确。查询结果如下:
从以上图片得知,颜色为白色则是255 255 255的RGB值,那么这时我们可以对该矩阵进行值的改变,即可得到一张白色图片。那我们是否可以这样编写呢?
代码语言:javascript复制data=np.zeros((200,200,3),np.uint8)*255
以上的编写方式是不对的,该方式是0成0,永远等于0,不过以上方式可以使每个元素都乘上255。这个时候我们可以把数组的创建方法改为ones,ones与zeros类似,我们可以从方法名上可以得知,zeros是创建数组时填充0,那ones必定是填充1了。我们写一个简单代码进行尝试:
代码语言:javascript复制data=np.ones((3,3,3),np.uint8)
print(data)
运行结果如下:
修改之前的代码将zeros方法改为ones方法,完整代码如下:
代码语言:javascript复制import cv2
import numpy as np
data=np.ones((200,200,3),np.uint8)*255
cv2.imshow("dataImg",data)
cv2.waitKey (0)
cv2.destroyAllWindows()
这时将会得到一张白色的图片:
2.3 使用OpenCV对图片进行生成
其实我们在创建这些数据时,就已经是创建了一张图片。我们的所有文件资源在计算机中都是以数字存储,而我们所见的这些图片只不过是以人类较为习惯的方式去进行呈现;即使我们操作Photoshop对图片进行更改,那也是以一种人类较为习惯的方式去对一张图片进行修改,但本质上是对数据的编辑。
那既然我们是创建了一张图片,那我们就去保存这一张图片。使用OpenCV的imwrite方法可以对图片数据进行保存。imwrite接收两个参数,第一个是path路径,表示图片存储的位置,但是需要注意的是一定不能够使用中文路径,否则有可能会出现错误;第二个参数为一个数组类型的参数,也就是我们的图像数据。那么我们就可以将自己生成的图像数据传入第二个参数。代码如下:
代码语言:javascript复制import cv2
import numpy as np
data=np.ones((200,200,3),np.uint8)*255
cv2.imwrite(r"C:UsersmxDesktopdataImg.png",data)
cv2.imshow("dataImg",data)
cv2.waitKey (0)
cv2.destroyAllWindows()
我所存储的位置是桌面,运行程序后将会在桌面生成一个dataImg名称的白色图片。
我们以上代码使用ones创建后,乘上255,这行代码可以更改为:
代码语言:javascript复制data=np.zeros((200,200,3),np.uint8)
data.fill(255)
使用fill方法可以将一个数组内填充一个值。
2.4 了解通道到底指的是什么
有一些同学不了解图像或者numpy,可能会对一些名称有一定的不理解。什么是通道对于这一部分同学来说可能听得还是有点糊涂的;很简单,我们直接使用代码来看通道是啥。
我们已经了解了numpy创建3个通道的图片数据如下:
代码语言:javascript复制data=np.zeros((200,200,3),np.uint8)
那此时,我们将该代码编程简单直观的方式,以便我们观察,分别更改创建的数组为3,3与3,3,3以及3,3,4 :
代码语言:javascript复制data=np.zeros((3,3),np.uint8)
代码语言:javascript复制data=np.zeros((3,3,3),np.uint8)
这时候查看数据:
其实从3,3到3,3,3明显的注意到是厚度增加了;我们之前说过,图像是由3张单通道图像组成,每一张表示一种色彩,其实就可以理解为我们所看见的图像是由3张通道图像叠加而成,这时就理解了该通道的含义。
注:文章首发于ebaina
三、总结
- 了解图片的通道与数组结构
- 了解使用numpy使用zeros,ones创建图像结构的数据
- 了解使用numpy使用fill对数据进行填充
- 了解了使用OpenCV 的imwrite方法保存数据