一起学opencv-python二(numpy数组基本操作学习)

参考了https://www.yiibai.com/numpy/numpy_ndarray_object.html。其实opencv对像素进行运算用的就是numpy,它的MATLAB真的很像。学会了numpy,后面像素运算就完全看得懂了,或者说必须会numpy,否则的话,没办法往下学,那么废话不多说,直接开始吧。

 

 

 

下图中可以看到,二维数组的单维是可以元素个数不一样的,比如说下图中的a=np.array([1,2],[3]),只不过打印出来显示的不是矩阵的形式了,从这个角度来看,多维数组要比矩阵灵活一些。

 

中括号一点要加上,虽然有的时候用小括号或者大括号似乎没问题,但是时不时又会有问题。

还是用中括号吧,下图是我的尝试。

 

 

 

 

 

最小维度是2,所以强制加上了一层中括号,必须变成两层以上的中括号,complex是复数的意思,和MATLAB一样,为了和电流i区分,虚数单位用的是j。

数据类型

 

这些数据类型不是无意义的,如果选错数据类型的话,数据是可能会丢失或者畸变的。

下面是一些例子。

 

如果参数只有一个可以不加中括号,如果dtype是uint8,数据是255,那还行,因为uint8的范围就是0-255,但是如果是256,就溢出了,溢出的位就被舍弃了,所以就是0,因为256是100000000,dtype改成int16就没有问题了。dtype是整数的时候,如果输入的数据有小数,小数点后面的直接截断舍弃,不是四舍五入。如果输入的是负数,比如-255,我们用uint8存,为什么打印的是1呢?-255需要一个符号位,所以需要16位来存,而计算机里存的都是补码,所以-255是000000011111111,补码是1111111000000001,而我们的dtype是uint8,所以是舍弃了高八位,就是00000001,也就是1。

 

 

 

 

 

我也不知道这个端记号是干嘛用的,查了很多资料都没看到。

 

 

 

这个确实类似一种结构体,dtype中的每一个小括号定义的是每一个元素的结构,(‘age‘,np.int8)中的age像是字典的key,将来调用这个dtype的时候必须赋给它value,后面的那个是存储的数据类型,h正好是<i2的简写,没有报错。

 

S20应该是string160,i1是int8,f4应该是float32。

 

这里边必须用小括号,应该是固定格式。

数组属性

 

 

 

 

a.shape是会改变原来的a,因为有一个赋值号嘛,而reshape不改变原来的a,只是输出一个新的数组。不是矩阵形式的多维数组虽然可以求shape,但是如果维数不统一,就不会显示了,就像上图中红色箭头指向。

 

如果不是矩阵形式的求size会有问题,是矩阵形式的就没有问题了,并且reshape的时候,是要求维数乘起来等于size的。说起来reshape函数在MATLAB里面也有,不过用法有点区别。

 

中间用到了一个arange的函数,如果不知道怎么用,很简单,help一下。

 

start是开始,是可选的,也就是可有可没有,默认是0,stop是结束值,但是一般不会包含在输出里面,当然有一些特殊情况。step是步长,也是可选的,默认是1,dtype如果没有指定,就会借鉴其它输入参数的类型。

 

 

 

上面是一些例子,还有三个函数有类似功能,上面也列出来了,这三个函数在MATLAB里面也都有,我只介绍一下linspace。

 

这个真的是和MATLAB用法很像。num默认是50,也就是输出个数是50,endpoint如果是真,输出就包含stop,反之,不包含,如果retstep,是return step的缩写是真,就返回step,反之,不返回。

 

这个输出的是等差数列,还有一个logspace输出的是等比数列。

 

MATLAB里面的plot,我们可以用matplotlib来实现一样的效果,不过稍微有一点不同,例如要加plt.show这一句:

 

上面还有一个zeros创建新数组的方法,这个后面还会介绍到,我不得不感叹MATLAB和numpy共通的地方好多啊。

 

不要忘了返回的是字节数,也就是Byte而不是bit。

 

 

 

当然上面不是全部,如果想知道更多,help一下。

 

实例化这个类的时候可以输入的参数有很多,下面的Parameters就是,看到这些应该是在__new__魔法方法里面实现创建的。

 

Attributes里面有很多属性,T是转置,imag是求数组的虚部,real是求实部,size上面也说过,是求数组元素的数量,这个是按照能形成矩阵的最多计算的,比如[[1,2],[3]]的size就是2,把[1,2]和[3]看做元素,因为再细下去不是矩阵的形式。

 

 

 

上面有一个例子,这个例子里面用到了shape参数,但是没有指定buffer,也就是要传进去的数据,所以输出的元素都是随机值。这个ndarray类还有很多魔法方法,我们就不看了。

 

创建数组方法

上面已经介绍过了很多了其实,有np.array,np.arange,np.linspace,还有一些比较特别的。

 

 

 

暂时没看出来有什么区别。搜了一下资料,参考了https://blog.csdn.net/zhuxianjianqi/article/details/8094984

Fortran和matlab语言中的多维数组存储方式为列优先原则,内循环最好是列循环;而c语言中的多维数组存储方式为行优先原则,内循环最好是行循环。下面介绍何为行优先存储,何为列优先存储。

 

这个会对程序运行时间有影响,上面的博文中也有介绍,enmmm,我们了解一下吧。不过要求算法效率的这里还是要掌握一下,你们自己去看资料就行了。

 

 

 

不指定dtype,numpy会根据输入的元素给出一个比较适合的选择,上面元素是0的时候选择的是float64,输入元素有字符串的时候,用的是U1,也就是utf-8。

 

 

 

zeros和ones在MATLAB里面也有,不过用法还是不太一样。如果MATLAB里面只给一个参数,会产生的是方阵。

 

MATLAB里还有eye可以产生方阵,还有一个diag可以产生对角阵,magic产生魔方矩阵。

 

numpy可以吗?

 

除了魔方矩阵,其它用法是一样的。

 

这里再稍微说一下MATLAB比较不一样的地方,首先是索引从1开始。而且在索引数组元素的时候要用小括号而不是中括号。而我们大多数都是从0开始的,而且是用中括号的。

 

 

还有一点,MATLAB里可以不先声明数组就直接对其中某一个元素赋值,没有赋值的元素默认为0。(这样做一般MATLAB会给出警告,说先声明一下会加快程序速度,不过不是error)

 

而python里面不行。

 

这个不是c语言里面变量必须先定义的意思,而只是针对数组必须先声明才能对其中元素赋值。

 

 

 

集合虽然没有写,但是貌似可以,但是我认为这个大括号不是集合的意思,在MATLAB里面大括号装的是cell数组,这里应该也是。

 

这个和array有什么区别呢?参考了

https://www.jb51.net/article/138281.htm

array和asarray都可以将结构数据转化为ndarray,但是主要区别就是当数据源是ndarray时,array仍然会copy出一个副本,占用新的内存,但asarray不会。

 

 

 

这样其实看出来了array会生成一个副本,所以是深拷贝,而asarray是浅拷贝,关于深浅拷贝,以前在python哪里也讨论过,这里复习一下。可以参考一下

https://blog.csdn.net/slowlifes/article/details/78186919

深拷贝:指的是拷贝一个对象时,不仅仅把对象的引用进行复制,还把该对象引用的值也一起拷贝。这样进行深拷贝后的拷贝对象就和源对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人叫张三,然后使用克隆技术以张三来克隆另外一个人叫李四,这样张三和李四就是相互独立的,不管张三缺胳膊还是李四少腿了都不会影响另外一个人。

浅拷贝:指的是拷贝一个对象时,仅仅拷贝对象的引用进行拷贝,但是拷贝对象和源对象还是引用同一份实体。此时,其中一个对象的改变都会影响到另一个对象。例如,一个人一开始叫张三,后来改名字为张老三了,可是他们还是同一个人,不管张三缺胳膊还是张老三少腿,都反应在同一个人身上。

 

 

 

上面例子报错了,help一下,和上面写的差不太多啊,那么我们看看例子:

 

help里面的例子还会有错,我也是有点醉。但是不知道为什么第二个例子是对的,我打算放弃这个函数了。

 

 

 

说实话,目前对这个方法有什么用还不太清楚。

 

 

 

 

 

这个三个上面学习过了,linspace和logspace举几个例子。

 

数组的切片和索引

 

 

 

虽然MATLAB里面冒号也有一样的用法,不过参数的含义不一样,python是第二个冒号后面的参数是步长,而MATLAB是第一个冒号后面。看下面例子的时候要注意MATLAB的索引从0开始。

 

 

 

 

 

...也可以指代所有,同样只有一个冒号也可以。下面是演示对多维数组进行访问和切片。

 

访问一个具体元素可以用a[1][1]这种,也可以用a[1,1]。

还有一些所谓的高级索引:

 

 

 

这个需要解释一下,x[[0,1,2],[0,1,0]]和np.array([x[0,0],x[1,1],x[2,0]])的结果是一样的,两个列表的元素是对应的,逗号前面是行,后面是列。

rows = np.array([[0,0],[3,3]]) 

cols = np.array([[0,2],[0,2]]) 

y = x[rows,cols]

这个我们看一下过程:

先是y=x[[0,0],[0,2]

   [3,3],[0,2]]

然后就是y=[ x[0,0] x[0,2]

                    x[3,0] x[3,2] ]

 

 

 

z = x[1:4,1:3]  

y = x[1:4,[1,2]]

我们来分析一下:1:4就是第一至第三行,后面1:3和[1,2]都是第一和第二列。

 

np.isnan就是判断是不是np.nan。

 

和MATLAB的find函数有点像。

 

 

 

 

 

​这一讲就先到这里了。