参考:
1、http://docs.opencv.org/3.3.0/ 官方文档api
2、http://docs.opencv.org/3.3.0/d6/d00/tutorial_py_root.html 官方英文教程
3、https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html
4、https://github.com/makelove/OpenCV-Python-Tutorial# 进阶教程
5、https://docs.opencv.org/3.3.0/index.html 官方英文教程
6、https://github.com/abidrahmank/OpenCV2-Python-Tutorials
7、https://www.learnopencv.com/
8、http://answers.opencv.org/questions/ OpenCV论坛
9、https://github.com/opencv/opencv 官方github
10、https://github.com/abidrahmank/OpenCV2-Python-Tutorials
注:安装的版本 opencv_python-3.3.0-cp36-cp36m-win_amd64.whl
参考:https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html
Meanshift and Camshift
OpenCV中的平移(Meanshift)
在OpenCV中使用meanshift,首先我们需要设置目标,找到它的直方图,以便我们可以在每个框架上反投影目标来计算均值。 我们还需要提供窗口的初始位置。 对于直方图,这里只考虑色相。 另外,为了避免由于低光引起的错误值,使用 cv2.inRange()函数丢弃低光值。
import numpy as np import cv2 cap = cv2.VideoCapture('slow.flv') # take first frame of the video ret,frame = cap.read() # setup initial location of window r,h,c,w = 250,90,400,125 # simply hardcoded the values track_window = (c,r,w,h) # set up the ROI for tracking roi = frame[r:r+h, c:c+w] hsv_roi = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180]) cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX) # Setup the termination criteria, either 10 iteration or move by atleast 1 pt term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 ) while(1): ret ,frame = cap.read() if ret == True: hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1) # apply meanshift to get the new location ret, track_window = cv2.meanShift(dst, track_window, term_crit) # Draw it on image x,y,w,h = track_window img2 = cv2.rectangle(frame, (x,y), (x+w,y+h), 255,2) cv2.imshow('img2',img2) k = cv2.waitKey(60) & 0xff if k == 27: break else: cv2.imwrite(chr(k)+".jpg",img2) else: break cv2.destroyAllWindows() cap.release()
OpenCV的Camshift
它几乎与 meanshift一样,但它返回一个旋转的矩形(这是我们的结果)和框参数(用于在下一次迭代中作为搜索窗口传递)。 请参阅以下代码:import numpy as np import cv2 cap = cv2.VideoCapture('slow.flv') # take first frame of the video ret,frame = cap.read() # setup initial location of window r,h,c,w = 250,90,400,125 # simply hardcoded the values track_window = (c,r,w,h) # set up the ROI for tracking roi = frame[r:r+h, c:c+w] hsv_roi = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180]) cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX) # Setup the termination criteria, either 10 iteration or move by atleast 1 pt term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 ) while(1): ret ,frame = cap.read() if ret == True: hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1) # apply meanshift to get the new location ret, track_window = cv2.CamShift(dst, track_window, term_crit) # Draw it on image pts = cv2.boxPoints(ret) pts = np.int0(pts) img2 = cv2.polylines(frame,[pts],True, 255,2) cv2.imshow('img2',img2) k = cv2.waitKey(60) & 0xff if k == 27: break else: cv2.imwrite(chr(k)+".jpg",img2) else: break cv2.destroyAllWindows() cap.release()
Optical Flow
OpenCV中的Lucas-Kanade Optical Flow
OpenCV在单个函数
cv2.calcOpticalFlowPyrLK()中提供所有这些。 在这里,我们创建一个简单的应用程序来跟踪视频中的某些点。 要确定点数,我们使用
cv2.goodFeaturesToTrack()。 我们采取第一帧,检测一些Shi-Tomasi角点,然后我们迭代地使用Lucas-Kanade光流跟踪这些点。 对于函数
cv2.calcOpticalFlowPyrLK()我们传递前一帧,先前的点和下一帧。 它返回下一个点以及一些状态数字,如果找到下一个点,其值为1,否则为零。 我们迭代地将这些下一个点作为下一步中的前一点。 请参阅以下代码:
import numpy as np import cv2 cap = cv2.VideoCapture('slow.flv') # params for ShiTomasi corner detection feature_params = dict( maxCorners = 100, qualityLevel = 0.3, minDistance = 7, blockSize = 7 ) # Parameters for lucas kanade optical flow lk_params = dict( winSize = (15,15), maxLevel = 2, criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) # Create some random colors color = np.random.randint(0,255,(100,3)) # Take first frame and find corners in it ret, old_frame = cap.read() old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params) # Create a mask image for drawing purposes mask = np.zeros_like(old_frame) while(1): ret,frame = cap.read() frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # calculate optical flow p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) # Select good points good_new = p1[st==1] good_old = p0[st==1] # draw the tracks for i,(new,old) in enumerate(zip(good_new,good_old)): a,b = new.ravel() c,d = old.ravel() mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2) frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1) img = cv2.add(frame,mask) cv2.imshow('frame',img) k = cv2.waitKey(30) & 0xff if k == 27: break # Now update the previous frame and previous points old_gray = frame_gray.copy() p0 = good_new.reshape(-1,1,2) cv2.destroyAllWindows() cap.release()(此代码不检查下一个关键点的正确性,因此即使图像中的任何一个特征点消失,也有可能发现下一个点可能看起来很接近,所以实际上对于一个强大的跟踪角落 应该在特定的间隔内检测点,OpenCV样品出现这样一个样本,每5帧找到一个特征点,并且还对所选择的光流点进行反向检查, samples/python2/lk_track.py)。
OpenCV中的 Dense Optical Flow
Lucas-Kanade方法计算稀疏特征集的光流(在我们的示例中,使用Shi-Tomasi算法检测到的角)。 OpenCV提供了另一种算法来找到密集的光流。 它计算帧中所有点的光流。 它是基于Gunner Farneback的算法,它在2003年由Gunner Farneback在“Two-Frame Motion Estimation Based on Polynomial Expansion”中解释。以下示例显示了如何使用上述算法找到致密光流。 我们得到一个带有光流向量(u,v)的2通道阵列。 我们发现它们的大小和方向。 我们对结果进行颜色编码,以便更好地显示。 方向对应于图像的色相值。 大小对应于值平面。 请参阅以下代码:
import cv2 import numpy as np cap = cv2.VideoCapture("vtest.avi") ret, frame1 = cap.read() prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY) hsv = np.zeros_like(frame1) hsv[...,1] = 255 while(1): ret, frame2 = cap.read() next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY) flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0) mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1]) hsv[...,0] = ang*180/np.pi/2 hsv[...,2] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX) rgb = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR) cv2.imshow('frame2',rgb) k = cv2.waitKey(30) & 0xff if k == 27: break elif k == ord('s'): cv2.imwrite('opticalfb.png',frame2) cv2.imwrite('opticalhsv.png',rgb) prvs = next cap.release() cv2.destroyAllWindows()OpenCV comes with a more advanced sample on dense optical flow, please see
samples/python2/opt_flow.py
.
Exercises
- Check the code in
samples/python2/lk_track.py
. Try to understand the code. - Check the code in
samples/python2/opt_flow.py
. Try to understand the code.
背景减法
BackgroundSubtractorMOG
它是一种基于高斯混合的背景/前景分割算法。 在2001年由P.KadewTraKuPong和R.Bowden的论文“改进的用于实时跟踪的背景混合模型”中引入了该方法。它使用一种通过K高斯分布的混合来对每个背景像素进行建模的方法 K = 3〜5)。 混合物的重量代表这些颜色停留在场景中的时间比例。 可能的背景颜色是保持更长和更静态的背景颜色。
编码时,我们需要使用函数cv2.createBackgroundSubtractorMOG()创建一个后台对象。 它具有一些可选的参数,如历史长度,高斯混合数,阈值等。它全部设置为一些默认值。 然后在视频循环内,使用backgroundsubtractor.apply()方法获取前景mask。
import numpy as np import cv2 cap = cv2.VideoCapture('vtest.avi') fgbg = cv2.createBackgroundSubtractorMOG() while(1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow('frame',fgmask) k = cv2.waitKey(30) & 0xff if k == 27: break cap.release() cv2.destroyAllWindows()
BackgroundSubtractorMOG2
它也是基于高斯混合的背景/前景分割算法。 它基于Z.Zivkovic的两篇论文,2004年的“改进的背景扣除自适应高斯混合模型”和“2006年背景减法任务的每个图像像素的有效自适应密度估计”。该算法的一个重要特征是 它为每个像素选择适当数量的高斯分布。 (记住,在最后一种情况下,我们在整个算法中采用了K高斯分布)。 它可以更好地适应不同场景的照明变化等。如前所述,我们必须创建一个背景减法器对象。 在这里,您可以选择是否检测到阴影。 如果 detectShadows = True(默认为true),它会检测并标记阴影,但会降低速度。 阴影将以灰色标记。
import numpy as np import cv2 cap = cv2.VideoCapture('vtest.avi') fgbg = cv2.createBackgroundSubtractorMOG2() while(1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow('frame',fgmask) k = cv2.waitKey(30) & 0xff if k == 27: break cap.release() cv2.destroyAllWindows()
BackgroundSubtractorGMG
该算法结合统计背景图像估计和每像素贝叶斯分割。它使用前几个(默认为120)帧进行后台建模。它采用概率前景分割算法,使用贝叶斯推理识别可能的前景对象。估计是适应性的较新观测值比旧观测值更重,以适应可变照明。进行几个形状过滤操作,如关闭和打开,以消除不必要的噪音。在几帧之前你会得到一个黑色的窗口。
import numpy as np import cv2 cap = cv2.VideoCapture('vtest.avi') kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) fgbg = cv2.createBackgroundSubtractorGMG()fgbg = cv2.createBackgroundSubtractorKNN()
while(1): ret, frame = cap.read() fgmask = fgbg.apply(frame) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) cv2.imshow('frame',fgmask) k = cv2.waitKey(30) & 0xff if k == 27: breakcap.release()cv2.destroyAllWindows()