2015年8月9日 星期日

使用openCV讀圖檔並在視窗中顯示圖片

我以前修過兩門課:數位影像處理(Digital Image Processing)和電腦視覺(Computer Vision)
個人覺得一次修這兩門課根本就是在騙學分。
因為好像學的東西都差不多,但可以一次集到六學分。
我也不太清楚在定義上這兩者有什麼不同,要去區分這兩者可能意義也不大。
但修完課後我的感覺是:電腦視覺好像特別針對機器人視覺(robotic vision)的應用去發展。
所以比較強調real-time system上的實現,對演算法的運算複雜度比較有要求。
但影像處理上好像比較沒有對執行時間上有太大限制,反正只要效果夠好,就給他慢慢跑。

兩者其實overlapping的部分非常大啦,只是應用的方向比較有差別。
或是可以說電腦視覺在技術的部分是以影像處理為基礎,往機器人視覺方面的應用開發。
例如電腦視覺的應用偏向視訊影片中的偵測和追蹤,還有三維空間定位技術或建模(SLAM)。

而影像處理好像比較沒有在管三維空間定位的部分,重點放在影像中的對象或整體的效果。
效果上的話:除雜訊或影像復原(restoration),影像銳利化(enhancement)或提高解析度(superresolution)
影像中的對象:切割(segmentation)和辨別(detection/recognition)
主要應用的精神是幫人類處理比較大量的資訊,只要能達到效果,處理時間又能接受就OK。

進入主題:
數位影像處理中,我們處理的對象基本單位是像素(pixel)(三維的叫voxel)
影像圖檔的raw data在處理時,我們希望能轉成二維的矩陣的形式,
如果是彩色圖片的話,raw data 會被轉成三維。
在RGB的色彩模型下是三個二維矩陣,分別儲存RGB三個channel下每個點的intensity值。

在python中用openCV來讀圖檔是非常方便的,跟在matlab下一樣簡單。
先引入openCV的函式庫套件: import cv2
讀圖檔並轉成矩陣的形式: img = cv2.imread("test.jpg",0)
函式cv2.imread()中第一個參數是圖檔名,通常跟.py程式檔放在同一個folder下,
如果沒有放在同一個資料夾下的話,參數部分要輸入圖檔絕對路徑才行。
第二個參數很好用,是flag的部分。有三個flags,因為我很懶,輸入數字就好了:
1 (cv2.IMREAD_COLOR) --> 讀取一般彩色圖檔,如果有透明度(A)channel的話會被省略。
0 (cv2.IMREAD_GRAYSCALE) --> 如果是彩色圖檔的話會自動轉成一個二維的灰階矩陣。
-1 (cv2.IMREAD_UNCHANGED) --> 如果是包含透明度四個channel的彩色圖片,用這個。
如果沒輸入第二個參數的話,預設值是1

如果只是秀個圖,其實最簡單就是輸入圖檔名就好(反正flag預設直是1)。
但如果要進行一些圖像的處理,第二個參數就變得超好用。
因為在影像處理中,我們很多基本操作是以一個二維的灰階矩陣為處理的對象。
本來讀完三維的彩色圖檔後,還要再下一個色彩轉灰階的指令。
但openCV在這邊加入這個flag,就很貼心地在讀完檔後就也順便幫你轉好了。

如果想知道圖檔的各維度的大小(size) (高height,寬width,channel數)
可以印出img下的shape屬性(property)來看看 : print(img.shape)
常用的情況下會用幾個參數去接,方便之後使用: m, n, c = img.shape
但這樣的寫法要很小心,必須要預先知道img的channel數,才知道要設幾個參數去接。
一般來說我們比較需要知道的資訊是二維影像矩陣的列數(m)和行數(n),
所以可以暫時先不考慮是否為彩色影像或灰階影像的問題:m, n = img.shape[:2]
img下還有另一個size屬性,size屬性會告訴你矩陣中所有成員的個數,
所以如果是 print(img.size) 會得到的值是:m*n*c
通常這個資訊我幾乎沒需要用到過,只是matlab下會用size,Python下要用shape。

用視窗秀圖:cv2.imshow("image show", img)
cv2.imshow()函式的第一個參數是視窗的名稱。第二個參數擺要顯示的圖片矩陣。

最後收尾的部份通常會加上: cv2.waitKey(0)
                                                     cv2.destroyAllWindows()
其作用是:視窗會一直顯示直到某個按鍵被按下,則關閉視窗。

cv2.waitKey()函式的功用是暫停系統,於特定時間內等待接收鍵盤端的輸入。
函式的輸入參數是以millisecond (0.001秒)為基本單位,
函式的輸出是按入鍵對應的ASCII code。
如果是 cv.waitKey(0)的話,系統會一直被暫停到天荒地老,除非某個按鍵被按下為止,才會繼續執行下一行的指令。
如果是 k=cv.waitKey(10000) 得到的是:指令會暫停系統最多10秒來等待接收鍵盤端的輸入。
10秒內如果鍵盤上任何一個按鍵被按下,
則assign其對應的ASCII code數值(type為integer)給k,並馬上往下執行下一行指令。
如果等待10內都沒有任何按鍵被按下,則函式會輸出值-1給k,接著繼續執行下一行指令。
大家常設定的按鍵及其對應的ASCII code有: esc(27),  q(113)( for quit) 和 s(115)(for save)

最後,如果用cv2.imshow()顯示圖檔的話,視窗上方並不會又x關閉的按鈕。
所以為了方便,通常程式的最後會加上關閉所有視窗的指令。
如果只要關閉特定的視窗:cv2.destroyWindow("image show")
cv2.destroyWindow() 的參數是要關閉特定視窗的視窗名稱。





沒有留言:

張貼留言