1. 程式人生 > 實用技巧 >Opencv 學習筆記(一)——三小時精通Opencv(Chapter)

Opencv 學習筆記(一)——三小時精通Opencv(Chapter)

參考:2020最新-3h精通Opencv
程式碼


1.Images-Videos-Webcam

影象、視訊、網路攝像頭

######################## READ IMAGE ############################
# import cv2
# # LOAD AN IMAGE USING 'IMREAD'
# img = cv2.imread("Resources/lena.png")
# # DISPLAY
# cv2.imshow("Lena Soderberg",img)
# cv2.waitKey(0)

######################### READ VIDEO #############################
# import cv2
# frameWidth = 640
# frameHeight = 480
# cap = cv2.VideoCapture("Resources/test_ video.mp4")
# while True:
#     success, img = cap.read()
#     img = cv2.resize(img, (frameWidth, frameHeight))
#     cv2.imshow("Result", img)
#     if cv2.waitKey(1) & 0xFF == ord('q'):
#         break
######################### READ WEBCAM  ############################

#開啟網路攝像頭
import cv2
frameWidth = 640
frameHeight = 480
cap = cv2.VideoCapture(0)
cap.set(3, frameWidth)
cap.set(4, frameHeight)
cap.set(10,150)
while True:
    success, img = cap.read()
    cv2.imshow("Result", img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break


4.繪圖

import cv2
import numpy as np

img = np.zeros((512,512,3),np.uint8)
#print(img)
#img[:]= 255,0,0

cv2.line(img,(0,0),(img.shape[1],img.shape[0]),(0,255,0),3)
cv2.rectangle(img,(0,0),(250,350),(0,0,255),2)
cv2.circle(img,(400,50),30,(255,255,0),5)
cv2.putText(img," OPENCV  ",(300,200),cv2.FONT_HERSHEY_COMPLEX,1,(0,150,0),3)


cv2.imshow("Image",img)

cv2.waitKey(0)

5.影象提取並顯示

提取固定位置的影象重新鋪平顯示

import cv2
import numpy as np

img = cv2.imread("Resources/cards.jpg")

width,height = 250,350
pts1 = np.float32([[111,219],[287,188],[154,482],[352,440]])# 獲取輪廓
pts2 = np.float32([[0,0],[width,0],[0,height],[width,height]]) # 顯示平面
matrix = cv2.getPerspectiveTransform(pts1,pts2)
imgOutput = cv2.warpPerspective(img,matrix,(width,height))


cv2.imshow("Image",img)
cv2.imshow("Output",imgOutput)

cv2.waitKey(0)

7.顏色

import cv2
import numpy as np

def empty(a):
    pass

def stackImages(scale,imgArray):
    rows = len(imgArray)
    cols = len(imgArray[0])
    rowsAvailable = isinstance(imgArray[0], list)
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    if rowsAvailable:
        for x in range ( 0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
                if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv2.cvtColor( imgArray[x][y], cv2.COLOR_GRAY2BGR)
        imageBlank = np.zeros((height, width, 3), np.uint8)
        hor = [imageBlank]*rows
        hor_con = [imageBlank]*rows
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
            if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
        hor= np.hstack(imgArray)
        ver = hor
    return ver



path = 'Resources/lambo.png'
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars",640,240)
cv2.createTrackbar("Hue Min","TrackBars",0,179,empty)
cv2.createTrackbar("Hue Max","TrackBars",19,179,empty)
cv2.createTrackbar("Sat Min","TrackBars",110,255,empty)
cv2.createTrackbar("Sat Max","TrackBars",240,255,empty)
cv2.createTrackbar("Val Min","TrackBars",153,255,empty)
cv2.createTrackbar("Val Max","TrackBars",255,255,empty)

while True:
    img = cv2.imread(path)
    imgHSV = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    h_min = cv2.getTrackbarPos("Hue Min","TrackBars")
    h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
    s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
    s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
    v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
    v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
    print(h_min,h_max,s_min,s_max,v_min,v_max)
    lower = np.array([h_min,s_min,v_min])
    upper = np.array([h_max,s_max,v_max])
    mask = cv2.inRange(imgHSV,lower,upper)
    imgResult = cv2.bitwise_and(img,img,mask=mask)


    # cv2.imshow("Original",img)
    # cv2.imshow("HSV",imgHSV)
    # cv2.imshow("Mask", mask)
    # cv2.imshow("Result", imgResult)

    imgStack = stackImages(0.6,([img,imgHSV],[mask,imgResult]))
    cv2.imshow("Stacked Images", imgStack)

    cv2.waitKey(1)



8.形狀識別

繪製圖像輪廓

參考:python-opencv2利用cv2.findContours()函式來查詢檢測物體的輪廓

importcv2

img=cv2.imread('D:\\test\\contour.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)

contours,hierarchy=cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,contours,-1,(0,0,255),3)

cv2.imshow("img",img)
cv2.waitKey(0)

cv2.findContours()函式

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])

opencv2返回兩個值:contours:hierarchy。

注:opencv3會返回三個值,分別是img, countours, hierarchy

引數

第一個引數是尋找輪廓的影象;

第二個引數表示輪廓的檢索模式,有四種(本文介紹的都是新的cv2介面):
cv2.RETR_EXTERNAL表示只檢測外輪廓
cv2.RETR_LIST檢測的輪廓不建立等級關係
cv2.RETR_CCOMP建立兩個等級的輪廓,上面的一層為外邊界,裡面的一層為內孔的邊界資訊。如果內孔內還有一個連通物體,這個物體的邊界也在頂層。
cv2.RETR_TREE建立一個等級樹結構的輪廓。

第三個引數method為輪廓的近似辦法
cv2.CHAIN_APPROX_NONE儲存所有的輪廓點,相鄰的兩個點的畫素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點座標,例如一個矩形輪廓只需4個點來儲存輪廓資訊
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似演算法

返回值

cv2.findContours()函式返回兩個值,一個是輪廓本身,還有一個是每條輪廓對應的屬性

hierarchy返回值

此外,該函式還可返回一個可選的hierarchy結果,這是一個ndarray,其中的元素個數和輪廓個數相同,每個輪廓contours[i]對應4個hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分別表示後一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號,如果沒有對應項,則該值為負數。

print(type(hierarchy))
print(hierarchy.ndim)
print(hierarchy[0].ndim)
print(hierarchy.shape)

cv2.contourArea()函式

計算輪廓面積參考:OpenCV中contourArea輪廓面積演算法

cv2.contourArea(cnt, True) # 計算輪廓對應圖形 的面積

cnt:輸入的單個輪廓值

cv2.arcLength()函式

計算弧長/邊長

cv2.arcLength(cnt,True)

cv2.drawContours()函式

[python] view plain copy

cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])

  • 第一個引數是指明在哪幅影象上繪製輪廓;
  • 第二個引數是輪廓本身,在Python中是一個list。
  • 第三個引數指定繪製輪廓list中的哪條輪廓,如果是-1,則繪製其中的所有輪廓。後面的引數很簡單。其中thickness表明輪廓線的寬度,如果是-1(cv2.FILLED),則為填充模式。繪製引數將在以後獨立詳細介紹。

計算邊的個數

參考:多邊形逼近approxPolyDP

findContours後的輪廓資訊contours可能過於複雜不平滑,可以用approxPolyDP函式對該多邊形曲線做適當近似,

approxPolyDP 主要功能是把一個連續光滑曲線折線化,對影象輪廓點進行多邊形擬合。原理圖:對比之前黑點連線,之後藍色連線:

Douglas-Peucker壓縮演算法

參考2:Douglas-Peucker壓縮演算法參考3:opencv 使用approxPolyDP輪廓近似

1.連線曲線首尾兩點A、B形成一條直線AB;
2.計算曲線上離該直線段距離最大的點C,計算其與AB的距離d;
3.比較該距離與預先給定的閾值threshold的大小,如果小於threshold,則以該直線作為曲線的近似,該段曲線處理完畢。
4.如果距離大於閾值,則用點C將曲線分為兩段AC和BC,並分別對兩段曲線進行步驟[1~3]的處理。
5.當所有曲線都處理完畢後,依次連線各個分割點形成折線,作為原曲線的近似。

cv2.approxPolyDP()函式

approx = cv2.approxPolyDP(contour,epsilon,True)(python)

void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)(C++)

例如:approxPolyDP(contourMat, approxCurve, 10, true)//找出輪廓的多邊形擬合曲線

第一個引數 InputArray curve:輸入的點集
第二個引數OutputArray approxCurve:輸出的點集,當前點集是能最小包容指定點集的。畫出來即是一個多邊形。
第三個引數double epsilon:指定的精度,也即是原始曲線與近似曲線之間的最大距離。
第四個引數bool closed:若為true,則說明近似曲線是閉合的;反之,若為false,則斷開。

Charpter08:

import cv2
import numpy as np

#函式:使 影象集中顯示
def stackImages(scale,imgArray):
    rows = len(imgArray)
    cols = len(imgArray[0])
    rowsAvailable = isinstance(imgArray[0], list)
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    if rowsAvailable:
        for x in range ( 0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
                if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv2.cvtColor( imgArray[x][y], cv2.COLOR_GRAY2BGR)
        imageBlank = np.zeros((height, width, 3), np.uint8)
        hor = [imageBlank]*rows
        hor_con = [imageBlank]*rows
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
            if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
        hor= np.hstack(imgArray)
        ver = hor
    return ver

#函式:get輪廓
#需要注意的是cv2.findContours()函式接受的引數為二值圖,即黑白的(不是灰度圖),所以讀取的影象要先轉成灰度的,再轉成二值圖
def getContours(img):
    contours,hierarchy = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE) #findContours檢測外部輪廓
    for cnt in contours:   #for in 迴圈結構   contours輪廓
        area = cv2.contourArea(cnt)  #計算輪廓的面積
        print(area)
        if area>500:
            cv2.drawContours(imgContour,cnt,-1,(255,0,0),3)     #  繪製輪廓(等高線)   在 imgContour 上繪製
            peri = cv2.arcLength(cnt,True)   #  計算弧長/邊長
            print(peri)
            
            approx = cv2.approxPolyDP(cnt,0.02*peri,True)
            objCor = len(approx)  # 計算 邊的個數
            print(objCor)

            if objCor == 3 :objectType = "Tri"
            elif objCor == 4 :
                aspRatio = w/float(h)  #寬長比
                if aspRatio > 0.95 and aspRatio < 1.05 : objectType = "Square"
                else:objectType = "Rectangle"
            elif objCor>4 :objectType = "Circles"
            else : objectType = "None"

            # 繪製矩形框
            x,y,w,h = cv2.boundingRect(approx)   # x,y  寬 高
            cv2.rectangle(imgContour,(x,y),(x+w,y+h),(0,255,0),2)  #繪製矩形
            cv2.putText(imgContour,objectType,(x+(w//2)-10,y+(h//2)-10),cv2.FONT_HERSHEY_COMPLEX,0.5,(0,0,0),2) #標註名稱


path = "Resources/shapes.png"
img = cv2.imread(path)
imgContour = img.copy()

#轉換成灰度 以便發現邊緣、拐角點
imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#高斯函式 模糊處理
imgBlur = cv2.GaussianBlur(imgGray,(7,7),1)
#邊緣檢測器
imgCanny = cv2.Canny(imgBlur,50,50)
#黑白影象
imgBlank = np.zeros_like(img)
#得到輪廓
getContours(imgCanny)


imgStack = stackImages(0.6,([img,imgGray,imgBlur],
                            [imgCanny,imgContour,imgBlur]))

cv2.imshow("imgStack",imgStack)
# cv2.imshow("Original",img)
# cv2.imshow("Gray",imgGray)
# cv2.imshow("Blur",imgBlur)
cv2.waitKey(0)

9.面部識別

import cv2
import numpy as np

faceCascade = cv2.CascadeClassifier("Resources/haarcascade_frontalface_default.xml")

img = cv2.imread("Resources/lena.png")
img1 = cv2.imread("Resources/face1.jpg")
img2 = cv2.imread("Resources/face2.jpg")

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(imgGray,1.1,4)

for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

cv2.imshow("imgStack",img)

cv2.waitKey(0)

結合charpter01 呼叫網路攝像頭進行人臉識別

import cv2
faceCascade = cv2.CascadeClassifier("Resources/haarcascade_frontalface_default.xml")

frameWidth = 640
frameHeight = 480
cap = cv2.VideoCapture(0)
cap.set(3, frameWidth)
cap.set(4, frameHeight)
cap.set(10,150)
while True:
    success, img = cap.read()
    imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(imgGray, 1.1, 4)

    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)

    cv2.imshow("Result", img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break


python+opencv開啟大華攝像機視訊

參考:python+opencv開啟大華攝像機視訊

import cv2
# 大華攝像機的視訊採集語句,subtype=1,輔碼流。0,主碼流。
cap = cv2.VideoCapture('rtsp://admin:[email protected]:554/cam/realmonitor?channel=1&subtype=1')

while(1):

# ret:成功返回True,失敗返回False
    ret, frame = cap.read()
    
# 在影象上畫矩形:後面4組數字依次左上座標,右下座標,顏色,寬度
    cv2.rectangle(frame,(10,0),(510,128),(0,255,0),3)
# 建立名為frame的視窗,顯示frame,
    cv2.imshow('frame',frame)
# 按q鍵終止
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 釋放資源,關閉所有視窗
cap.release()
cv2.destroyAllWindows()