使用OpenCV進行圖像分析

背景

在進行一個和視頻分析相關的項目研究的時候,我們需要前置使用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 cv2import numpy as npframe = cv2.imread(gemfield.jpg)

當frame是一幀圖像的時候,它來自一段視頻中的一幀:

import cv2import numpy as npvideo_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 npimport cv2cap = 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: breakcv2.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 npimport cv2frame = 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)#畫出所有的contoursframe = cv2.drawContours(frame, contours, -1, (0,255,0), 3)#畫出第4個contourframe = 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


推薦閱讀:

【小林的OpenCV基礎課 6】基本數學操作 初識掩膜
圖像對比檢測
如何從0學習opencv,完成類似人臉檢測的畢設?
人臉識別博客匯總以及一些學習建議

TAG:OpenCV | 計算機視覺 | Python |