您當前的位置:首頁 > 舞蹈

使用OpenCV進行影象分析

作者:由 Gemfield 發表于 舞蹈時間:2018-04-04

背景

在進行一個和影片分析相關的專案研究的時候,我們需要前置使用OpenCV對影象進行預處理。在密集使用OpenCV的API的過程中,我們有了這樣一種感覺:大部分人寫的API都是ctrl+c 和 ctrl+v,而OpenCV的好多API,每一個API背後都是一篇論文。感動之餘,Gemfield寫了這篇文章,把調研過程中使用過的OpenCV的API都在這篇文章中予以解釋。Gemfield也歡迎OpenCV的使用者提供和反饋自己使用過的並且覺得有意義的OpenCV API。

本文示例程式碼基於OpenCV 3。1和python 2。7。14。

frame變數

在下文中任何一個演算法的示例程式碼中,都會用到

frame

這個變數。

frame

代表一個圖片或者一幀影象。它在C++中是個Mat結構,在Python中是numpy儲存的多維陣列。當frame是一個圖片的時候,它來自讀取的一個圖片:

import

cv2

import

numpy

as

np

frame

=

cv2

imread

‘gemfield。jpg’

當frame是一幀影象的時候,它來自一段影片中的一幀:

import cv2

import numpy as np

video_cap = cv2。VideoCapture(‘gemfield。mp4’)

while True:

rc, frame = video_cap。read()

if not rc:

break

常規操作

1,cv2.namedWindow()是新增一個播放視窗。

2,cv2.destroyWindow()是銷燬一個播放視窗。

3,cv2.setMouseCallback('gemfield window 1', callback_function)

,為gemfield window 1播放視窗建立個回撥,一般用於滑鼠事件。callback_function的第一個引數是event。

cv2

namedWindow

‘gemfield window 1’

cv2

destroyWindow

‘gemfield window 1’

cv2

setMouseCallback

‘gemfield window 1’

callback_func1

顏色操作

1,cv2.cvtColor()

改變frame的顏色。flag有cv2。COLOR_BGR2GRAY 、cv2。COLOR_BGR2HSV等幾十個吧。

Image Thresholding

1,cv2.threshold()

將一副影象的畫素點按照黑白顏色二分類,非黑即白。

影象平滑

要用卷積核的啊。

1,cv2.filter2D()

2,cv2.blur()

3,cv2.GaussianBlur()

高斯模糊,gemfield最常用的。使用Gaussian kernel做卷積。

4, cv2.medianBlur()

5,cv2.bilateralFilter()

影象梯度和邊緣檢測

1,cv2.Sobel()

2,cv2.Scharr()

3,cv2.Laplacian()

最好用的、最好上手的API當屬下Canny 邊緣檢測,它融合了梯度檢測和NMS:

4,cv2.Canny()

Image Pyramids 影象金字塔

影象融合方面用處很大。

1,cv2.pyrUp()

2,cv2.pyrDown()

影象變換之Fourier Transform

1,cv2.dft()

2,cv2.idft()

Template Matching

1,cv2.matchTemplate()

模板匹配,這個就很有用了。雖然和神經網路比起來是慘不忍睹,但是對於一些模式恆定不變的目標檢測,這個還是很有用的。就是使用簡單的滑動視窗的方式去尋找獵物。模板匹配的模式有6種:

cv2。TM_CCOEFF;

cv2。TM_CCOEFF_NORMED

cv2。TM_CCORR

cv2。TM_CCORR_NORMED

cv2。TM_SQDIFF

cv2。TM_SQDIFF_NORMED

2,cv2.minMaxLoc()

Hough 線變換和圓變換

一版都會先做edge detection。

1,cv2.HoughLines()

用於檢測影象中的直線。不知道為啥,效果很差。

2,cv2.HoughCircles()

用於檢測影象中的直線。不知道為啥,效果還是很差。

Image Segmentation 影象分割

1,cv2.watershed()

使用Watershed演算法。用處不大,和很多其它API一樣,神經網路出來後,這些東西就進博物館了。

Foreground Extraction 前景提取

1,cv2.grabCut()

Feature Detection and Description 特徵檢測和描述

1,cv2.cornerHarris()

2,cv2.cornerSubPix()

Harris角檢測,這個非常有用。

3,cv2.goodFeaturesToTrack()

Shi-Tomasi 角檢測演算法。這個應用很廣。

4,cv2.SIFT()

5,cv2.SURF()

這2個API在OpenCV 3。1中已經被挪走了。

Background Subtraction 背景移除

主要是為了拿到(移動的)前景,OpenCV實現了3個背景移除的演算法:BackgroundSubtractorMOG、BackgroundSubtractorMOG2、BackgroundSubtractorGMG。

1,cv2.BackgroundSubtractorMOG2()

使用了Gaussian Mixture-based Background/Foreground Segmentation 演算法,基於2004年的“Improved adaptive Gausian mixture model for background subtraction”和2006年的 “Efficient AdaptiveDensity Estimation per Image Pixel for the Task of Background Subtraction” 這2篇論文。

import numpy as np

import cv2

cap = cv2。VideoCapture(‘gemfield。mp4’)

fgbg = cv2。createBackgroundSubtractorMOG2(history=20, detectShadows=False)

while 1:

ret, frame = cap。read()

fgmask = fgbg。apply(frame)

cv2。imshow(‘frame’,fgmask)

k = cv2。waitKey(30) & 0xff

if k == 27:

break

cv2。destroyAllWindows()

cap。release()

createBackgroundSubtractorMOG2這個API有3個引數,detectShadows表明是否檢測影子,history指明當前幀受之前多少幀的影響, varThreshold設定閾值,越高的值表明越多的畫素被歸為背景。

Morphological Transformations 形態變換

要用卷積核的。

1,cv2.erode()

腐蝕,亮色腐蝕(和卷積核有關)。

2,cv2.dilate()

膨脹,預設的卷積核是亮色膨脹。

3,cv2.morphologyEx()

根據flag的不同,可以是open或者close。

Histograms

1,cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

frame

=

cv2

imread

‘gemfield。jpg’

0

hist

=

cv2

calcHist

([

frame

],[

0

],

None

,[

256

],[

0

256

])

引數介紹:

1,images : 輸入的影象,用方括號框起來:“[img]”。

2,channels : it is also given in square brackets。 It is the index of channel for which we calculate histogram。 For example, if input is grayscale image, its value is [0]。 For color image, you can pass [0],[1] or [2] to calculate histogram of blue,green or red channel respectively。

3。 mask : mask image。 To find histogram of full image, it is given as “None”。 But if you want to find histogram of particular region of image, you have to create a mask image for that and give it as mask。

4。 histSize : this represents our BIN count。 Need to be given in square brackets。 For full scale, we pass [256]。BIN就是pixal value的範圍的個數,比方說10到20就是一個BIN。

5。 ranges : this is our RANGE。 Normally, it is [0,256]。

Perspective Transformation 透視變換

這個非常有用。

1,cv2.getPerspectiveTransform()

得到透射變換矩陣。

2,cv2.warpPerspective()

直接透射變換影象。

3,cv2.perspectiveTransform()

使用透射變換矩陣把之前座標系的點轉換到新的座標系中。

Contours 輪廓

1,cv2.findContours()

2,cv2.drawContours()

import numpy as np

import cv2

frame = cv2。imread(‘gemfield。jpg’)

imgray = cv2。cvtColor(frame,cv2。COLOR_BGR2GRAY)

ret,thresh = cv2。threshold(imgray,127,255,0)

image, contours, hierarchy = cv2。findContours(thresh,cv2。RETR_TREE,cv2。CHAIN_APPROX_SIMPLE)

#畫出所有的contours

frame = cv2。drawContours(frame, contours, -1, (0,255,0), 3)

#畫出第4個contour

frame = cv2。drawContours(frame, contours, 3, (0,255,0), 3)

#也可以這麼弄

cnt = contours[4]

frame = cv2。drawContours(frame, [cnt], 0, (0,255,0), 3)

如上面的程式碼展示的那樣,cv2。findContours()函式有3個引數,第一個是frame,第二個引數指定尋找contour的模式(主要是因為輪廓會巢狀,所以衍生出各種模式),第三個引數是contour 的近似方法。返回值是三個,image、contours、hierarchy。返回值中的contours 是個python list,是image中的所有contours,該list中的每一個元素是一個numpy array,代表一個單獨的輪廓的邊界上的點的座標。hierarchy表明輪廓的巢狀層級。

話說findContours()函式的第三個引數是contour的近似方法,這到底是什麼意思呢?它代表的意思就是如何去用點表示一個輪廓。比如:

cv2。CHAIN_APPROX_NONE,儲存輪廓線上的所有的點;

cv2。CHAIN_APPROX_SIMPLE,在上面的基礎上去掉冗餘的點;

3,cv2.moments()

輪廓矩。用一個字典M儲存輪廓矩的相關資訊。然後根據這些資訊計算得到自己想要的,比方說中心位置的x、y座標。

4,cv2.contourArea()

計算輪廓面積。

5,cv2.arcLength()

計算輪廓周長。

6,Contour Approximation

實現了Douglas-Peucker演算法,根據輪廓來擬合自己想要找的形狀。

7, cv2.convexHull()

這個有點像 contour approximation,但其實不是。這個函式檢查輪廓曲線是否有不是凸的部分,如果有,把它弄平或者凸。也可以單獨使用函式 cv2。isContourConvex()來僅僅做判斷(不返回修正後的曲線)。

8, cv2.boundingRect()

在輪廓上擬合矩形。為了擬合出面積最小的矩形,還可以使用cv2。minAreaRect()和cv2。boxPoints()來擬合出旋轉的矩形。

9, cv2.minEnclosingCircle()

在輪廓上擬合出圓。

10,cv2.fitEllipse()

在輪廓上擬合出橢圓。

11, cv2.fitLine()

在輪廓上擬合出直線。

12,cv2.matchShapes()

比較2個輪廓的異同。

HOG 方向梯度直方圖

1,cv2.HOGDescriptor()

hog

=

cv2

HOGDescriptor

()

hog

setSVMDetector

cv2

HOGDescriptor_getDefaultPeopleDetector

()

while

True

ret

frame

=

camera

read

()

found

w

=

hog

detectMultiScale

frame

winStride

=

8

8

),

padding

=

32

32

),

scale

=

1。05

for

x

y

w

h

in

found

# the HOG detector returns slightly larger rectangles than the real objects。

# so we slightly shrink the rectangles to get a nicer output。

pad_w

pad_h

=

int

0。15

*

w

),

int

0。05

*

h

cv2

rectangle

frame

x

+

pad_w

y

+

pad_h

),

x

+

w

-

pad_w

y

+

h

-

pad_h

),

0

255

0

),

1

cv2

imshow

‘img’

frame

一般結合SVM分類器來檢測行人,這方面比較成功。

Image Inpainting

1,cv2.inpaint()

需要mask。

人臉檢測

要弄懂什麼是級聯啊。

1,cv2.CascadeClassifier()

影片領域中的目標追蹤

1,cv2.meanShift()

使用聚類演算法進行目標追蹤。返回一個矩形的track window。

2, cv2.calcOpticalFlowPyrLK()

OpenCV實現的Lucas-Kanade 光流演算法,對於鏡頭多變的video來說,不好弄。

一些有用的github專案

1,鏡頭分割(切換)檢測

Breakthrough/PySceneDetect

標簽: cv2  Frame  gemfield  輪廓  opencv