[OpenCV-Python] OpenCV 中的 Gui特性 部分 II


部分 II
OpenCV 中的 Gui 特性

OpenCV-Python 中文教程(搬運)目錄

4 圖片

目標
  • 在這里你將學會怎樣讀入一幅圖像,怎樣顯示一幅圖像,以及如何保存一幅圖像
  • 你將要學習如下函數:cv2.imread(),cv2.imshow(),cv2.imwrite()
  • 如果你願意的話,我會叫你如何使用 Matplotlib 顯示一幅圖片


4.1 讀入圖像
  使用函數 cv2.imread() 讀入圖像。這幅圖像應該在此程序的工作路徑,或者給函數提供完整路徑,第二個參數是要告訴函數應該如何讀取這幅圖片。

  • cv2.IMREAD_COLOR:讀入一副彩色圖像。圖像的透明度會被忽略,這是默認參數。
  • cv2.IMREAD_GRAYSCALE:以灰度模式讀入圖像
  • cv2.IMREAD_UNCHANGED:讀入一幅圖像,並且包括圖像的 alpha 通道

import numpy as np
import cv2

# Load an color image in grayscale
img = cv2.imread('messi5.jpg',0)

  警告:就算圖像的路徑是錯的,OpenCV 也不會提醒你的,但是當你使用命令print img時得到的結果是None。


4.2 顯示圖像
  使用函數 cv2.imshow() 顯示圖像。窗口會自動調整為圖像大小。第一個參數是窗口的名字,其次才是我們的圖像。你可以創建多個窗口,只要你喜歡,但是必須給他們不同的名字

cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

窗口屏幕截圖將會像以下的樣子 (in Fedora-Gnome machine):

  cv2.waitKey() 是一個鍵盤綁定函數。需要指出的是它的時間尺度是毫秒級。函數等待特定的幾毫秒,看是否有鍵盤輸入。特定的幾毫秒之內,如果按下任意鍵,這個函數會返回按鍵的 ASCII 碼值,程序將會繼續運行。如果沒有鍵盤輸入,返回值為 -1,如果我們設置這個函數的參數為 0,那它將會無限期的等待鍵盤輸入。它也可以被用來檢測特定鍵是否被按下,例如按鍵 a 是否被按下,這個后面我們會接着討論。
cv2.destroyAllWindows() 可以輕易刪除任何我們建立的窗口。如果你想刪除特定的窗口可以使用 cv2.destroyWindow(),在括號內輸入你想刪除的窗口名。


  建 議:一 種 特 殊 的 情 況 是, 你 也 可 以 先 創 建 一 個 窗 口, 之 后再 加 載 圖 像。 這 種 情 況 下, 你 可 以 決 定 窗 口 是 否 可 以 調 整大 小。 使 用 到 的 函 數 是 cv2.namedWindow()。 初 始 設 定 函 數標 簽 是 cv2.WINDOW_AUTOSIZE。 但 是 如 果 你 把 標 簽 改 成cv2.WINDOW_NORMAL,你就可以調整窗口大小了。當圖像維度太大,或者要添加軌跡條時,調整窗口大小將會很有用
代碼如下:

cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

4.3 保存圖像
  使用函數 cv2.imwrite() 來保存一個圖像。首先需要一個文件名,之后才是你要保存的圖像。

cv2.imwrite('messigray.png',img)

 

4.4 總結一下
  下面的程序將會加載一個灰度圖,顯示圖片,按下’s’鍵保存后退出,或者按下 ESC 鍵退出不保存。

import numpy as np
import cv2

img = cv2.imread('messi5.jpg',0)
cv2.imshow('image',img)
k = cv2.waitKey(0)
if k == 27:         # wait for ESC key to exit
    cv2.destroyAllWindows()
elif k == ord('s'): # wait for 's' key to save and exit
    cv2.imwrite('messigray.png',img)
    cv2.destroyAllWindows()

  警告:如果你用的是 64 位系統,你需要將  k = cv2.waitKey(0) 這行改成k = cv2.waitKey(0)&0xFF。

 

使用 Matplotlib
  Matplotib 是 python 的一個繪圖庫,里頭有各種各樣的繪圖方法。之后會陸續了解到。現在,你可以學習怎樣用 Matplotib 顯示圖像。你可以放大圖像,保存它等等。

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.show()

窗口截屏如下:

  參見:Matplotib 有多種繪圖選擇。具體可以參見 Matplotib docs。我們也會陸續了解一些
  注意:彩色圖像使用 OpenCV 加載時是 BGR 模式。但是 Matplotib 是 RGB模式。所以彩色圖像如果已經被 OpenCV 讀取,那它將不會被 Matplotib 正確顯示。具體細節請看練習


附加資源:
  Matplotlib Plotting Styles and Features

練習:
  1. 當你用 OpenCV 加載一個彩色圖像,並用 Matplotib 顯示它時會遇
  到一些困難。請閱讀this discussion並且嘗試理解它。

 

 

5 視頻


目標
  • 學會讀取視頻文件,顯示視頻,保存視頻文件
  • 學會從攝像頭獲取並顯示視頻
  • 你將會學習到這些函數:cv2.VideoCapture(),cv2.VideoWrite()


5.1 用攝像頭捕獲視頻
  我們經常需要使用攝像頭捕獲實時圖像。OpenCV 為這中應用提供了一個非常簡單的接口。讓我們使用攝像頭來捕獲一段視頻,並把它轉換成灰度視頻顯示出來。從這個簡單的任務開始吧。
  為了獲取視頻,你應該創建一個 VideoCapture 對象。他的參數可以是設備的索引號,或者是一個視頻文件。設備索引號就是在指定要使用的攝像頭。一般的筆記本電腦都有內置攝像頭。所以參數就是 0。你可以通過設置成 1 或者其他的來選擇別的攝像頭。之后,你就可以一幀一幀的捕獲視頻了。但是最后,別忘了停止捕獲視頻。

import numpy as np
import cv2 cap = cv2.VideoCapture(0) while(True): # Capture frame-by-frame ret, frame = cap.read() # Our operations on the frame come here gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Display the resulting frame cv2.imshow('frame',gray) if cv2.waitKey(1) & 0xFF == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows()

  cap.read() 返回一個布爾值(True/False)。如果幀讀取的是正確的,就是 True。所以最后你可以通過檢查他的返回值來查看視頻文件是否已經到了結尾。
  有時 cap 可能不能成功的初始化攝像頭設備。這種情況下上面的代碼會報錯。你可以使用 cap.isOpened(),來檢查是否成功初始化了。如果返回值是True,那就沒有問題。否則就要使用函數 cap.open()。
你可以使用函數 cap.get(propId) 來獲得視頻的一些參數信息。這里propId 可以是 0 到 18 之間的任何整數。每一個數代表視頻的一個屬性,見下表

  其中的一些值可以使用 cap.set(propId,value) 來修改,value 就是你想要設置成的新值。
  例如,我可以使用 cap.get(3) 和 cap.get(4) 來查看每一幀的寬和高。
  默認情況下得到的值是 640X480。但是我可以使用 ret=cap.set(3,320)和 ret=cap.set(4,240) 來把寬和高改成 320X240。注意:當你的程序報錯時,你首先應該檢查的是你的攝像頭是否能夠在其他程序中正常工作(比如 linux 下的 Cheese)。


5.2 從文件中播放視頻
  與從攝像頭中捕獲一樣,你只需要把設備索引號改成視頻文件的名字。在播放每一幀時,使用 cv2.waiKey() 設置適當的持續時間。如果設置的太低視頻就會播放的非常快,如果設置的太高就會播放的很慢(你可以使用這種方法控制視頻的播放速度)。通常情況下 25 毫秒就可以了。

import numpy as np
import cv2 cap = cv2.VideoCapture('vtest.avi') while(cap.isOpened()): ret, frame = cap.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow('frame',gray) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

注意:你應該確保你已經裝了合適版本的 ffmpeg 或者 gstreamer。如果你裝
錯了那就比較頭疼了。


5.3 保存視頻
  在我們捕獲視頻,並對每一幀都進行加工之后我們想要保存這個視頻。對於圖片來時很簡單只需要使用 cv2.imwrite()。但對於視頻來說就要多做點工作。
  這次我們要創建一個 VideoWriter 的對象。我們應該確定一個輸出文件的名字。接下來指定 FourCC 編碼(下面會介紹)。播放頻率和幀的大小也都需要確定。最后一個是 isColor 標簽。如果是 True,每一幀就是彩色圖,否則就是灰度圖。
FourCC 就是一個 4 字節碼,用來確定視頻的編碼格式。可用的編碼列表可以從fourcc.org查到。這是平台依賴的。下面這些編碼器對我來說是有用個。
  • In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 givesvery small size video)
  • In Windows: DIVX (More to be tested and added)
  • In OSX : (I don’t have access to OSX. Can some one fill this?) 

FourCC 碼以下面的格式傳給程序,以 MJPG 為例:

cv2.cv.FOURCC('M','J','P','G') 或者 cv2.cv.FOURCC(*'MJPG')。


下面的代碼是從攝像頭中捕獲視頻,沿水平方向旋轉每一幀並保存它。

import numpy as np
import cv2 cap = cv2.VideoCapture(0) # Define the codec and create VideoWriter object fourcc = cv2.VideoWriter_fourcc(*'XVID') out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480)) while(cap.isOpened()): ret, frame = cap.read() if ret==True: frame = cv2.flip(frame,0) # write the flipped frame  out.write(frame) cv2.imshow('frame',frame) if cv2.waitKey(1) & 0xFF == ord('q'): break else: break # Release everything if job is finished cap.release() out.release() cv2.destroyAllWindows()

 

 

6 OpenCV 中的繪圖函數


目標
  • 學習使用 OpenCV 繪制不同幾何圖形
  • 你將會學習到這些函數:cv2.line(),cv2.circle(),cv2.rectangle() ,cv2.ellipse() ,cv2.putText() 等。

 

代碼
上面所有的這些繪圖函數需要設置下面這些參數:
  • img:你想要繪制圖形的那幅圖像。
  • color:形狀的顏色。以 RGB 為例,需要傳入一個元組,例如: (255,0,0 )代表藍色。對於灰度圖只需要傳入灰度值。
  • thickness:線條的粗細。如果給一個閉合圖形設置為 -1,那么這個圖形就會被填充。默認值是 1.
  • linetype:線條的類型,8 連接,抗鋸齒等。默認情況是 8 連接。cv2.LINE_AA為抗鋸齒,這樣看起來會非常平滑。


6.1 畫線
  要畫一條線,你只需要告訴函數這條線的起點和終點。我們下面會畫一條從左上方到右下角的藍色線段。

import numpy as np
import cv2 # Create a black image img = np.zeros((512,512,3), np.uint8) # Draw a diagonal blue line with thickness of 5 px cv2.line(img,(0,0),(511,511),(255,0,0),5)

     

 

6.2 畫矩形
  要畫一個矩形,你需要告訴函數的左上角頂點和右下角頂點的坐標。這次我們會在圖像的右上角話一個綠色的矩形。

cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)

     

 

6.3 畫圓
  要畫圓的話,只需要指定圓形的中心點坐標和半徑大小。我們在上面的矩形中畫一個圓。

cv2.circle(img,(447,63), 63, (0,0,255), -1)

     

 

6.4 畫橢圓
  畫橢圓比較復雜,我們要多輸入幾個參數。一個參數是中心點的位置坐標。
  下一個參數是長軸和短軸的長度。橢圓沿逆時針方向旋轉的角度。橢圓弧演順時針方向起始的角度和結束角度,如果是 0 很 360,就是整個橢圓。查看cv2.ellipse() 可以得到更多信息。下面的例子是在圖片的中心繪制半個橢圓。

cv2.ellipse(img,(256,256),(100,50),0,0,180,255,-1)

     

 

6.5 畫多邊形
  畫多邊形,需要指點每個頂點的坐標。用這些點的坐標構建一個大小等於行數 X1X2 的數組,行數就是點的數目。這個數組的數據類型必須為 int32。
  這里畫一個黃色的具有四個頂點的多邊形。

pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32) pts = pts.reshape((-1,1,2)) cv2.polylines(img,[pts],True,(0,255,255))

    

 

 # 這里 reshape 的第一個參數為 -1, 表明這一維的長度是根據后面的維度的計算出來的。
注意:如果第三個參數是 False,我們得到的多邊形是不閉合的(首尾不相連)。
注意:cv2.polylines() 可以被用來畫很多條線。只需要把想要畫的線放在一個列表中,將這個列表傳給函數就可以了。每條線都會被獨立繪制。這會比用cv2.line() 一條一條的繪制要快一些。


6.6 在圖片上添加文字
  要在圖片上繪制文字,你需要設置下列參數:
  • 你要繪制的文字
  • 你要繪制的位置
  • 字體類型(通過查看 cv2.putText() 的文檔找到支持的字體)
  • 字體的大小
  • 文字的一般屬性如顏色,粗細,線條的類型等。為了更好看一點推薦使用linetype=cv2.LINE_AA。
在圖像上繪制白色的 OpenCV。

font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA)

    

 

警 告:所 有 的 繪 圖 函 數 的 返 回 值 都 是 None, 所 以 不 能 使 用 img =cv2.line(img,(0,0),(511,511),(255,0,0),5) 。


結果
下面就是最終結果了,通過你前面幾節學到的知識把他顯示出來吧。

winname = 'example'
cv2.namedWindow(winname)
cv2.imshow(winname, img)
cv2.waitKey(0)
cv2.destroyWindow(winname)

     

 

更多資源
  橢圓函數中的角度不是我們的圓形角度。更多細節請查看討論
練習
  嘗試使用這些函數揮着 OpenCV 的圖標。

 

7 把鼠標當畫筆


目標
  • 學習使用 OpenCV 處理鼠標事件
  • 你將要學習的函數是:cv2.setMouseCallback()


7.1 簡單演示
  這里我們來創建一個簡單的程序,他會在圖片上你雙擊過的位置繪制一個圓圈。首先我們來創建一個鼠標事件回調函數,但鼠標事件發生是他就會被執行。鼠標事件可以是鼠標上的任何動作,比如左鍵按下,左鍵松開,左鍵雙擊等。我們可以通過鼠標事件獲得與鼠標對應的圖片上的坐標。根據這些信息我們可以做任何我們想做的事。你可以通過執行下列代碼查看所有被支持的鼠標事件。

import cv2
events=[i for i in dir(cv2) if 'EVENT'in i]
print(events) 
['EVENT_FLAG_ALTKEY', 'EVENT_FLAG_CTRLKEY', 'EVENT_FLAG_LBUTTON', 'EVENT_FLAG_MBUTTON', 
'EVENT_FLAG_RBUTTON', 'EVENT_FLAG_SHIFTKEY', 'EVENT_LBUTTONDBLCLK', 'EVENT_LBUTTONDOWN',
'EVENT_LBUTTONUP', 'EVENT_MBUTTONDBLCLK', 'EVENT_MBUTTONDOWN', 'EVENT_MBUTTONUP', 'EVENT_MOUSEHWHEEL',
'EVENT_MOUSEMOVE', 'EVENT_MOUSEWHEEL', 'EVENT_RBUTTONDBLCLK', 'EVENT_RBUTTONDOWN', 'EVENT_RBUTTONUP']

 

所有的鼠標事件回調函數都有一個統一的格式,他們所不同的地方僅僅是被調用后的功能。我們的鼠標事件回調函數只用做一件事:在雙擊過的地方繪制一個圓圈。下面是代碼,不懂的地方可以看看注釋。

import cv2
import numpy as np # mouse callback function def draw_circle(event,x,y,flags,param): if event == cv2.EVENT_LBUTTONDBLCLK: cv2.circle(img,(x,y),100,(255,0,0),-1) # Create a black image, a window and bind the function to window img = np.zeros((512,512,3), np.uint8) cv2.namedWindow('image') cv2.setMouseCallback('image',draw_circle) while(1): cv2.imshow('image',img) if cv2.waitKey(20) & 0xFF == 27: break cv2.destroyAllWindows()

 

 

 

7.2 高級一點的示例
  現在我們來創建一個更好的程序。這次我們的程序要完成的任務是根據我們選擇的模式在拖動鼠標時繪制矩形或者是圓圈(就像畫圖程序中一樣)。所以我們的回調函數包含兩部分,一部分畫矩形,一部分畫圓圈。這是一個典型的例子他可以幫助我們更好理解與構建人機交互式程序,比如物體跟蹤,圖像分割等。

import cv2
import numpy as np drawing = False # true if mouse is pressed mode = True # if True, draw rectangle. Press 'm' to toggle to curve ix,iy = -1,-1 # mouse callback function def draw_circle(event,x,y,flags,param): global ix,iy,drawing,mode if event == cv2.EVENT_LBUTTONDOWN: drawing = True ix,iy = x,y elif event == cv2.EVENT_MOUSEMOVE: if drawing == True: if mode == True: cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) else: cv2.circle(img,(x,y),5,(0,0,255),-1) elif event == cv2.EVENT_LBUTTONUP: drawing = False if mode == True: cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) else: cv2.circle(img,(x,y),5,(0,0,255),-1) # Next we have to bind this mouse callback function to OpenCV # # window. In the main loop, we should set a keyboard binding for 
# key ‘m’ to toggle between rectangle and circle. img = np.zeros((512,512,3), np.uint8) cv2.namedWindow('image') cv2.setMouseCallback('image',draw_circle) while(1): cv2.imshow('image',img) k = cv2.waitKey(1) & 0xFF if k == ord('m'): # 切換模式 mode = not mode elif k == 27: break cv2.destroyAllWindows()

 

 

更多資源
練習
  1. 在我們最后的一個練習中,我們繪制的是一個填充的矩形。你可以試着修改代碼繪制一個沒有填充的矩形。

if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        ix,iy = x,y

    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing == True:
            if mode == True:
                # cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
                pass
            else:
                cv2.circle(img,(x,y),5,(0,0,255),-1)

    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        if mode == True:
            cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
        else:
            cv2.circle(img,(x,y),5,(0,0,255),-1)

 

    

 

 

8 用滑動條做調色板


目標
  • 學會把滑動條綁定到 OpenCV 的窗口
  • 你將會學習這些函數:cv2.getTrackbarPos(),cv2.creatTrackbar()等。


8.1 代碼示例
  現在我們來創建一個簡單的程序:通過調節滑動條來設定畫板顏色。我們要創建一個窗口來顯示顯色,還有三個滑動條來設置 B,G,R 的顏色。當我們滑動滾動條是窗口的顏色也會發生相應改變。默認情況下窗口的起始顏色為黑。
 cv2.getTrackbarPos() 函數:

  第一個參數是滑動條的名字

  第二個參數是滑動條被放置窗口的名字

  第三個參數是滑動條的默認位置。第四個參數是滑動條的最大值

  第五個函數是回調函數,每次滑動條的滑動都會調用回調函數。回調函數通常都會含有一個默認參數,就是滑動條的位置。在本例中這個函數不用做任何事情,我們只需要 pass 就可以了。

  滑動條的另外一個重要應用就是用作轉換按鈕。默認情況下 OpenCV 本身不帶有按鈕函數。所以我們使用滑動條來代替。在我們的程序中,我們要創建一個轉換按鈕,只有當裝換按鈕指向 ON 時,滑動條的滑動才有用,否則窗戶口都是黑的。

import cv2
import numpy as np def nothing(x): pass # Create a black image, a window img = np.zeros((300,512,3), np.uint8) cv2.namedWindow('image') # create trackbars for color change cv2.createTrackbar('R','image',0,255,nothing) cv2.createTrackbar('G','image',0,255,nothing) cv2.createTrackbar('B','image',0,255,nothing) # create switch for ON/OFF functionality switch = '0 : OFF \n1 : ON' cv2.createTrackbar(switch, 'image',0,1,nothing) while(1): cv2.imshow('image',img) k = cv2.waitKey(1) & 0xFF if k == 27: break # get current positions of four trackbars r = cv2.getTrackbarPos('R','image') g = cv2.getTrackbarPos('G','image') b = cv2.getTrackbarPos('B','image') s = cv2.getTrackbarPos(switch,'image') if s == 0: img[:] = 0 else: img[:] = [b,g,r] cv2.destroyAllWindows()

 

 

練習
1. 結合上一節的知識,創建一個畫板,可以自選各種顏色的畫筆繪畫各種圖
形。

import cv2
import numpy as np def nothing(x): pass # 當鼠標按下時變為 True drawing=False # 如果 mode 為 true 繪制矩形。按下 'm' 變成繪制曲線。 mode=True ix,iy=-1,-1 # 創建回調函數 def draw_circle(event,x,y,flags,param): r=cv2.getTrackbarPos('R','image') g=cv2.getTrackbarPos('G','image') b=cv2.getTrackbarPos('B','image') color=(b,g,r) global ix,iy,drawing,mode # 當按下左鍵是返回起始位置坐標 if event==cv2.EVENT_LBUTTONDOWN: drawing=True ix,iy=x,y # 當鼠標左鍵按下並移動是繪制圖形。 event 可以查看移動, flag 查看是否按下 elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_FLAG_LBUTTON: if drawing==True: if mode==True: cv2.rectangle(img,(ix,iy),(x,y),color,-1) else: # 繪制圓圈,小圓點連在一起就成了線, 3 代表了筆畫的粗細 cv2.circle(img,(x,y),3,color,-1) # 下面注釋掉的代碼是起始點為圓心,起點到終點為半徑的 # r=int(np.sqrt((x-ix)**2+(y-iy)**2)) # cv2.circle(img,(x,y),r,(0,0,255),-1) # 當鼠標松開停止繪畫。 elif event==cv2.EVENT_LBUTTONUP: drawing==False # if mode==True: # cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) # else: # cv2.circle(img,(x,y),5,(0,0,255),-1) img=np.zeros((512,512,3),np.uint8) cv2.namedWindow('image') cv2.createTrackbar('R','image',0,255,nothing) cv2.createTrackbar('G','image',0,255,nothing) cv2.createTrackbar('B','image',0,255,nothing) cv2.setMouseCallback('image',draw_circle) while(1): cv2.imshow('image',img) k=cv2.waitKey(1)&0xFF if k==ord('m'): mode=not mode elif k==27: break

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM