1. 程式人生 > 其它 >opencv-python的影象變換、繪圖、滑動條、滑鼠事件筆記記錄

opencv-python的影象變換、繪圖、滑動條、滑鼠事件筆記記錄

一、影象變換

1.圖片縮放

cv2.resize(),可以直接按照大小縮放,也可以按照比例縮放。

點選檢視程式碼
import cv2

img = cv2.imread('lena.bmp')
# 按照指定的寬度、高度縮放圖片
res = cv2.resize(img, (132, 150))
# 按照比例縮放,如x,y軸均放大一倍
res2 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
cv2.imshow('shrink', res), cv2.imshow('zoom', res2)
cv2.waitKey(0)

2.圖片平移

cv2.warpAffine()使用仿射變換的函式實現平移,函式的第二個引數就是變換矩陣,主要就是用這個矩陣進行變換。

  • 仿射變換後,原圖中平行的線依然平行
  • 用cv2.warpAffine()實現仿射變換
  • 仿射變換需要定義一個2*3維的變換矩陣
點選檢視程式碼
import cv2

# 讀取圖片
img = cv2.imread('lena.jpg')
# 平移圖片
rows, cols = img.shape[:2]
# 定義平移矩陣,需要是numpy的float32型別
# x軸平移100,y軸平移50
M = np.float32([[1, 0, 100], [0, 1, 50]])
# 用仿射變換實現平移
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('shift', dst)
cv2.waitKey(0)

3.圖片旋轉

使用cv2.getRotationMatrix2D()函式來獲取旋轉矩陣M(2x3)的引數。(其實像上面圖片平移中的程式碼那樣自己手動設定M矩陣也是可以的,只不過自己計算矩陣M比較麻煩)
然後同樣也是使用仿射變換的函式cv2.warpAffine()進行旋轉。

點選檢視程式碼
import cv2

# 讀取圖片
img = cv2.imread('lena.jpg')

# 45°旋轉圖片並縮小一半
rows, cols = img.shape[:2]
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 0.5)
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('rotation', dst)
cv2.waitKey(0)

通過幾個點計算得到矩陣M,可以使用cv2.getAffineTransform()函式。

點選檢視程式碼
import cv2

# 讀取圖片
img = cv2.imread('lena.jpg')

# 變換前的三個點
Point1 = np.float32([[50, 50], [100, 60], [150, 700]])
# 變換後的三個點
Point2 = np.float32([[50, 100], [150, 60], [ 100, 200]])
# 生成變換矩陣
M = cv2.getAffineTransform(Point1 , Point2 )

4.透視變換

主要作用就是校正圖片的作用,如下圖:

點選檢視程式碼
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('case1r.png')

rows, cols = img.shape[:2]
# 原圖中需要校正的四個角點
pts1 = np.float32([[5, 321], [323, 5], [455, 769], [769, 453]])
# 變換後分別在左上、右上、左下、右下四個點
pts2 = np.float32([[0, 0], [320, 0], [0, 480], [320, 480]])
# 生成透視變換矩陣
M = cv2.getPerspectiveTransform(pts1, pts2)
# 進行透視變換
dst = cv2.warpPerspective(img, M, (320, 480))

# 用cv的函式顯示
cv2.imshow('raw', img)
cv2.imshow('dst', dst)
cv2.waitKey(0)

# 用matplotlib顯示
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('input')
plt.subplot(122), plt.imshow(dst[:, :, ::-1]), plt.title('output')
plt.show()

獲取需要矯正的圖片的四個點可以通過滑鼠右擊,啟動圖片編輯功能,然後得到圖片的四個角點。
也可以通過滑鼠事件相關的程式碼,通過滑鼠點選獲得圖片的四個角點座標,以下是通過滑鼠事件相關的程式碼點選獲取:

點選檢視程式碼
import cv2

# 滑鼠的回撥函式
def mouse_event(event, x, y, flags, param):
    # 通過event判斷具體是什麼事件,這裡是左鍵按下
    if event == cv2.EVENT_LBUTTONDOWN:
        print((x, y))

def main():
    img = cv2.imread('case1r.png')
    cv2.namedWindow('image')
    # 定義滑鼠的回撥函式
    cv2.setMouseCallback('image', mouse_event)
    while (True):
        cv2.imshow('image', img)
        # 按下ESC鍵退出
        if cv2.waitKey(20) == 27:
            break


if __name__ == '__main__':
    main()

二、繪圖

  • 建立黑色的底圖:img = np.zeros((640, 480, 3), np.uint8)
  • 畫直線:cv2.line()
  • 畫矩形:cv2.rectangle()
  • 畫圓:cv2.circle()
  • 畫半圓:'cv2.ellipse()'
  • 寫字:putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)

使用cv2.polylines()函式繪製多邊形

點選檢視程式碼
import cv2
import numpy as np

# 建立黑色底圖
img = np.zeros((640, 480, 3), np.uint8)

# 定義多邊形的幾個點
points = np.array([[10, 5],  [50, 10], [70, 20], [20, 30]], np.int32)
# 將頂點座標轉換成4*1*2維
points = points.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (0, 255, 255))
# 顯示
cv2.imshow('img', img)

三、滑動條

滑動條操作主要涉及到兩個函式:
cv2.createTrackbar(trackbarName, windowName, value, count, onChange)

  • trackbarName : 滑動條的名稱
  • windowName : 滑動條所在的視窗
  • value : 滑塊的起始值
  • count : 滑塊的最大值
  • onChange : 回撥函式,即當滑塊位置改變時就會呼叫的函式,並且回撥函式第一個引數為滑塊位置所對應的值

cv2.getTrackbarPos(trackbarname, winname)

  • trackbarname : 選擇的滑動條名稱
  • winname : 選擇的滑動條所在視窗的名稱

不使用回撥函式:

點選檢視程式碼
import cv2
import numpy as np
# 建立一個(500,500)的numpy陣列
img=np.zeros((500, 500), dtype='uint8')

# 新建一個視窗
cv2.namedWindow('img')

# 定義回撥函式,這裡pass表示不做任何事,用作佔位語句保持程式結構的完整性
def trackBar(x):
    pass

# 新建一個滑動條
cv2.createTrackbar('color', 'img', 0 , 255, trackBar)

while(True):
    cv2.imshow('img', img)

    # 返回滑塊所在位置對應的值
    color = cv2.getTrackbarPos('color','img')
    img[:] = [color]

    if cv2.waitKey(1) == ord('q'):
        break

cv2.destroyAllWindows()

使用回撥函式:

點選檢視程式碼
import cv2
import numpy as np
# 建立一個(500,500)的numpy陣列
img=np.zeros((500, 500), dtype='uint8')
# 新建一個視窗
cv2.namedWindow('img')
# 定義回撥函式,引數x為函式cv2.createTrackbar()傳遞的滑塊位置對應的值
def img_intensity_change(x):
    img[:] = [x]
# 新建一個滑動條
cv2.createTrackbar('color','img',0,255,img_intensity_change)
while(True):
    cv2.imshow('img', img)
    if cv2.waitKey(1) == ord('q'):
        break
cv2.destroyAllWindows()

四、滑鼠事件

滑鼠事件主要涉及到cv2.setMouseCallback(windowName, onMouse, param=None)函式,然後滑鼠事件主要在函式的onMouse引數下添加回調函式來完成,另外param引數可以進行像圖片引數的傳遞,這裡就可以在回撥函式中直接在圖上畫畫。

滑鼠點選獲取畫素點位置的程式碼:

點選檢視程式碼
import cv2

# 滑鼠的回撥函式
def mouse_event(event, x, y, flags, param):
    # 通過event判斷具體是什麼事件,這裡是左鍵按下
    if event == cv2.EVENT_LBUTTONDOWN:
        print((x, y))

def main():
    img = cv2.imread('case1r.png')
    cv2.namedWindow('image')
    # 定義滑鼠的回撥函式
    cv2.setMouseCallback('image', mouse_event)
    while (True):
        cv2.imshow('image', img)
        # 按下ESC鍵退出
        if cv2.waitKey(20) == 27:
            break


if __name__ == '__main__':
    main()

五、功能綜合demo

主要實現在圖上畫框,並且可以實現用滑動條選擇框的顏色和粗細,另外畫框的時候框的大小隨時變化,可以實時畫框(實現就是在滑鼠事件中加了一個把滑鼠上一次畫的框用底色覆蓋的函式,在第40行),滑動條的引數使用全域性變數來處理的。

點選檢視程式碼
import cv2
import numpy as np
drawing = False  # 是否開始畫圖
mode = True  # True:畫矩形,False:畫圓
start = (-1, -1)
px, py = -1, -1
r, g, b = 0, 255, 0
penSize = 1

def mouse_event(event, x, y, flags, img):
    global start, drawing, mode
    # 左鍵按下:開始畫圖
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        start = (x, y)
    # 滑鼠移動,畫圖
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            if mode:
                cv2.rectangle(img, start, (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:
            cv2.rectangle(img, start, (x, y), (0, 255, 0), 1)
        else:
            cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
# 滑鼠畫框
def my_mouse_event(event, x, y, flags, img):
    global start, drawing, mode, px, py
#     左鍵按下獲取起點座標
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        start = (x, y)
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            if mode:
                cv2.rectangle(img, start, (px, py), (0, 0, 0), penSize)
                cv2.rectangle(img, start, (x, y), (r, g, b), penSize)
                px, py = x, y
            else:
                cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
    # 左鍵釋放:結束畫圖
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        if mode:
            cv2.rectangle(img, start, (x, y), (r, g, b), penSize)
        else:
            cv2.circle(img, (x, y), 5, (0, 0, 255), -1)

def trackbar(x):
    pass

def main():
    global r, g, b, penSize
    img = np.zeros((512, 512, 3), np.uint8)
    cv2.namedWindow('image')

    # 建立 RGB 三個滑動條
    cv2.createTrackbar('R', 'image', 0, 255, trackbar)
    cv2.createTrackbar('G', 'image', 0, 255, trackbar)
    cv2.createTrackbar('B', 'image', 0, 255, trackbar)
    cv2.createTrackbar('penSize', 'image', 1, 5, trackbar)

    # cv2.setMouseCallback('image', mouse_event, img)
    cv2.setMouseCallback('image', my_mouse_event, img)
    while (True):
        cv2.imshow('image', img)
        # 獲取滑塊的值
        r = cv2.getTrackbarPos('R', 'image')
        g = cv2.getTrackbarPos('G', 'image')
        b = cv2.getTrackbarPos('B', 'image')
        penSize = cv2.getTrackbarPos('penSize', 'image')

        # 按下m切換模式
        if cv2.waitKey(1) == ord('m'):
            mode = not mode
        elif cv2.waitKey(1) == 27:
            break

if __name__ == '__main__':
    main()