一起學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函數有點像。

 

 

 

 

 

​這一講就先到這裏了。