├── .gitignore ├── 1.Introduction to OpenCV └── README.md ├── 10.Object Detection └── README.md ├── 11.OpenCV-Python Bindings └── README.md ├── 12.Appendix └── README.md ├── 2.Gui Features in OpenCV ├── Code │ ├── demo1.py │ ├── demo2.py │ ├── demo3.py │ ├── demo4.py │ ├── demo5.py │ ├── demo6.py │ ├── demo7.py │ ├── demo8.py │ ├── demo9.py │ └── messi5.jpg ├── README.md └── image │ ├── image1.png │ ├── image2.png │ ├── image3.png │ └── image4.png ├── 3.Core Operations ├── Code │ ├── demo1.py │ ├── demo2.py │ ├── demo3.py │ ├── demo4.py │ ├── demo5.py │ ├── demo6.py │ ├── messi5.jpg │ ├── ml.png │ ├── opencv-logo-white.png │ └── opencv-logo.png ├── Image │ ├── image1.png │ ├── image2.png │ ├── image3.png │ └── image4.png └── README.md ├── 4.Image Processing in OpenCV ├── Image │ ├── image1.png │ ├── image10.png │ ├── image11.png │ ├── image12.png │ ├── image13.png │ ├── image14.png │ ├── image15.png │ ├── image16.png │ ├── image17.png │ ├── image18.png │ ├── image19.png │ ├── image2.png │ ├── image20.png │ ├── image21.png │ ├── image22.png │ ├── image23.png │ ├── image24.png │ ├── image25.png │ ├── image26.png │ ├── image27.png │ ├── image28.png │ ├── image29.png │ ├── image3.png │ ├── image30.png │ ├── image31.png │ ├── image32.png │ ├── image33.png │ ├── image34.png │ ├── image35.png │ ├── image36.png │ ├── image37.png │ ├── image38.png │ ├── image39.png │ ├── image4.png │ ├── image40.png │ ├── image41.png │ ├── image42.png │ ├── image43.png │ ├── image44.png │ ├── image45.png │ ├── image46.png │ ├── image47.png │ ├── image48.png │ ├── image49.png │ ├── image5.png │ ├── image50.png │ ├── image51.png │ ├── image52.png │ ├── image53.png │ ├── image54.png │ ├── image55.png │ ├── image56.png │ ├── image57.png │ ├── image58.png │ ├── image59.png │ ├── image6.png │ ├── image60.png │ ├── image61.png │ ├── image62.png │ ├── image63.png │ ├── image64.png │ ├── image65.png │ ├── image66.png │ ├── image67.png │ ├── image68.png │ ├── image69.png │ ├── image7.png │ ├── image70.gif │ ├── image71.png │ ├── image72.png │ ├── image73.png │ ├── image74.png │ ├── image75.png │ ├── image76.png │ ├── image77.png │ ├── image78.png │ ├── image79.png │ ├── image8.png │ ├── image80.png │ ├── image81.png │ ├── image82.png │ ├── image83.png │ ├── image84.png │ ├── image85.png │ └── image9.png └── README.md ├── 5.Feature Detection and Description ├── Image │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image13.jpg │ ├── image14.jpg │ ├── image15.jpg │ ├── image16.jpg │ ├── image17.jpg │ ├── image18.jpg │ ├── image19.jpg │ ├── image2.jpg │ ├── image20.jpg │ ├── image21.jpg │ ├── image22.jpg │ ├── image23.jpg │ ├── image24.jpg │ ├── image3.jpg │ ├── image4.jpg │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ └── image9.jpg └── README.md ├── 6.Video Analysis ├── Image │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image2.gif │ ├── image3.jpg │ ├── image4.gif │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ └── image9.jpg └── README.md ├── 7.Camera Calibration and 3D Reconstruction ├── Image │ ├── image1.jpg │ ├── image10.jpg │ ├── image2.jpg │ ├── image3.jpg │ ├── image4.jpg │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ └── image9.jpg └── README.md ├── 8.Machine Learning ├── Image │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image13.jpg │ ├── image14.jpg │ ├── image15.jpg │ ├── image16.jpg │ ├── image17.jpg │ ├── image2.jpg │ ├── image3.jpg │ ├── image4.jpg │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ └── image9.jpg └── README.md ├── 9.Computational Photography └── README.md ├── README.md └── image.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | .DS_Store 107 | */.DS_Store 108 | 109 | -------------------------------------------------------------------------------- /1.Introduction to OpenCV/README.md: -------------------------------------------------------------------------------- 1 | # 第一章:OpenCV简介 2 | 3 | 本章节将介绍如何在不同系统平台安装配置OpenCV。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## OpenCV-Python教程简介 10 | 11 | *** 12 | 13 | ### OpenCV 14 | 15 | OpenCV于1999年由Gary Bradsky在英特尔创立,第一个版本于2000年问世。随后Vadim Pisarevsky加入了Gary Bradsky,主要负责管理英特尔的俄罗斯软件OpenCV团队。2005年,OpenCV被用于Stanley车型,并赢得2005年DARPA大挑战。后来,它在Willow Garage的支持下持续并积极发展,转为由Gary Bradsky和Vadim Pisarevsky领导该项目。OpenCV现在支持与计算机视觉和机器学习相关的众多算法,并且正在日益扩展。 16 | 17 | OpenCV支持各种编程语言,如C ++,Python,Java等,可以在不同的系统平台上使用,包括WindowsLinux,OS X,Android和iOS。基于CUDA和OpenCL的高速GPU操作接口也在积极开发中。 18 | 19 | OpenCV-Python是OpenCV的Python API,结合了OpenCV C++ API和Python语言的最佳特性。 20 | 21 | ### OpenCV中的Python实现 22 | 23 | OpenCV-Python是一个Python绑定库,旨在解决计算机视觉问题。 24 | 25 | Python是一种由Guido van Rossum开发的通用编程语言,它很快就变得非常流行,主要是因为它的简单性和代码可读性。它使程序员能够用更少的代码行表达思想,而不会降低可读性。 26 | 27 | 与C / C++等语言相比,Python速度较慢。也就是说,Python可以使用C / C++轻松扩展,这使我们可以在C / C++中编写计算密集型代码,并创建可用作Python模块的Python包装器。这给我们带来了两个好处:首先,代码与原始C / C++代码一样快(因为它是在后台工作的实际C++代码),其次,在Python中编写代码比使用C / C++更容易。OpenCV-Python是原始OpenCV C++实现的Python包装器。 28 | 29 | OpenCV-Python使用Numpy,这是一个高度优化的数据库操作库,具有MATLAB风格的语法。所有OpenCV数组结构都转换为Numpy数组。这也使得与使用Numpy的其他库(如SciPy和Matplotlib)集成更容易。 30 | 31 | ### OpenCV-Python教程 32 | 33 | OpenCV引入了一组新的教程,它将指导你完成OpenCV-Python中提供的各种功能。本指南主要关注OpenCV 3.x版本(尽管大多数教程也适用于OpenCV 2.x)。 34 | 35 | 建议事先了解Python和Numpy,因为本指南不涉及它们。为了使用OpenCV-Python编写优化代码,必须熟练使用Numpy。 36 | 37 | 本教程最初由Abid Rahman K.在Alexander Mordvintsev的指导下作为Google Summer of Code 2013计划的一部分启动。 38 | 39 | ### OpenCV需要你!!! 40 | 41 | 由于OpenCV是一个开源计划,欢迎所有人为图书馆,文档和教程做出贡献。如果你在本教程中发现任何错误(从一个小的拼写错误到代码或概念中的一个令人震惊的错误),请随意通过在GitHub中克隆OpenCV并提交拉取请求来纠正它。 OpenCV开发人员将检查你的请求,给你重要的反馈,并且(一旦通过审核者的批准),它将合并到OpenCV中。然后你将成为一个开源贡献者:-) 42 | 43 | 随着新模块被添加到OpenCV-Python,本教程将不得不进行扩展。如果你熟悉特定算法并且可以编写包含算法基本理论和显示示例用法的代码的教程,请执行此操作。 44 | 45 | 记住,我们在一起可以使这个项目取得圆满成功! 46 | -------------------------------------------------------------------------------- /10.Object Detection/README.md: -------------------------------------------------------------------------------- 1 | # OpenCV-Python 2 | The Opencv-Python tutorial Chinese translation 3 | *** 4 | -------------------------------------------------------------------------------- /11.OpenCV-Python Bindings/README.md: -------------------------------------------------------------------------------- 1 | # OpenCV-Python 2 | The Opencv-Python tutorial Chinese translation 3 | *** 4 | -------------------------------------------------------------------------------- /12.Appendix/README.md: -------------------------------------------------------------------------------- 1 | # OpenCV-Python 2 | The Opencv-Python tutorial Chinese translation 3 | *** 4 | -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | 4 | img = cv.imread('messi5.jpg',0) 5 | cv.imshow('image',img) 6 | k = cv.waitKey(0) 7 | if k == 27: # wait for ESC key to exit 8 | cv.destroyAllWindows() 9 | elif k == ord('s'): # wait for 's' key to save and exit 10 | cv.imwrite('messigray.png',img) 11 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo2.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | from matplotlib import pyplot as plt 4 | 5 | img = cv.imread('messi5.jpg',0) 6 | plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') 7 | plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis 8 | plt.show() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo3.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | 4 | cap = cv.VideoCapture(0) 5 | 6 | while(True): 7 | # Capture frame-by-frame 8 | ret, frame = cap.read() 9 | # Our operations on the frame come here 10 | gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) 11 | # Display the resulting frame 12 | cv.imshow('frame',gray) 13 | if cv.waitKey(1) & 0xFF == ord('q'): 14 | break 15 | # When everything done, release the capture 16 | cap.release() 17 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo4.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | 4 | cap = cv.VideoCapture('vtest.avi') 5 | 6 | while(cap.isOpened()): 7 | ret, frame = cap.read() 8 | gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) 9 | cv.imshow('frame',gray) 10 | if cv.waitKey(1) & 0xFF == ord('q'): 11 | break 12 | 13 | cap.release() 14 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo5.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | 4 | cap = cv.VideoCapture(0) 5 | # Define the codec and create VideoWriter object 6 | fourcc = cv.VideoWriter_fourcc(*'XVID') 7 | out = cv.VideoWriter('output.avi',fourcc, 20.0, (640,480)) 8 | while(cap.isOpened()): 9 | ret, frame = cap.read() 10 | if ret==True: 11 | frame = cv.flip(frame,0) 12 | # write the flipped frame 13 | out.write(frame) 14 | cv.imshow('frame',frame) 15 | if cv.waitKey(1) & 0xFF == ord('q'): 16 | break 17 | else: 18 | break 19 | # Release everything if job is finished 20 | cap.release() 21 | out.release() 22 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo6.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | 4 | # Create a black image 5 | img = np.zeros((512,512,3), np.uint8) 6 | 7 | # Draw a diagonal blue line with thickness of 5 px 8 | cv.line(img,(0,0),(511,511),(255,0,0),5) 9 | cv.rectangle(img,(384,0),(510,128),(0,255,0),3) 10 | cv.circle(img,(447,63), 63, (0,0,255), -1) 11 | cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1) 12 | pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32) 13 | pts = pts.reshape((-1,1,2)) 14 | cv.polylines(img,[pts],True,(0,255,255)) 15 | font = cv.FONT_HERSHEY_SIMPLEX 16 | cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA) 17 | 18 | winname = 'example' 19 | cv.namedWindow(winname) 20 | 21 | while(1): 22 | cv.imshow(winname, img) 23 | if cv.waitKey(1) & 0xFF == ord('q'): 24 | break 25 | 26 | cv.destroyWindow(winname) -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo7.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | # mouse callback function 4 | def draw_circle(event,x,y,flags,param): 5 | if event == cv.EVENT_LBUTTONDBLCLK: 6 | cv.circle(img,(x,y),100,(255,0,0),-1) 7 | # Create a black image, a window and bind the function to window 8 | img = np.zeros((512,512,3), np.uint8) 9 | cv.namedWindow('image') 10 | cv.setMouseCallback('image',draw_circle) 11 | while(1): 12 | cv.imshow('image',img) 13 | if cv.waitKey(20) & 0xFF == 27: 14 | break 15 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo8.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | drawing = False # true if mouse is pressed 4 | mode = True # if True, draw rectangle. Press 'm' to toggle to curve 5 | ix,iy = -1,-1 6 | # mouse callback function 7 | def draw_circle(event,x,y,flags,param): 8 | global ix,iy,drawing,mode 9 | if event == cv.EVENT_LBUTTONDOWN: 10 | drawing = True 11 | ix,iy = x,y 12 | elif event == cv.EVENT_MOUSEMOVE: 13 | if drawing == True: 14 | if mode == True: 15 | cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) 16 | else: 17 | cv.circle(img,(x,y),5,(0,0,255),-1) 18 | elif event == cv.EVENT_LBUTTONUP: 19 | drawing = False 20 | if mode == True: 21 | cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) 22 | else: 23 | cv.circle(img,(x,y),5,(0,0,255),-1) 24 | img = np.zeros((512,512,3), np.uint8) 25 | cv.namedWindow('image') 26 | cv.setMouseCallback('image',draw_circle) 27 | while(1): 28 | cv.imshow('image',img) 29 | k = cv.waitKey(1) & 0xFF 30 | if k == ord('m'): 31 | mode = not mode 32 | elif k == 27: 33 | break 34 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/demo9.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 as cv 3 | def nothing(x): 4 | pass 5 | # Create a black image, a window 6 | img = np.zeros((300,512,3), np.uint8) 7 | cv.namedWindow('image') 8 | # create trackbars for color change 9 | cv.createTrackbar('R','image',0,255,nothing) 10 | cv.createTrackbar('G','image',0,255,nothing) 11 | cv.createTrackbar('B','image',0,255,nothing) 12 | # create switch for ON/OFF functionality 13 | switch = '0 : OFF \n1 : ON' 14 | cv.createTrackbar(switch, 'image',0,1,nothing) 15 | while(1): 16 | cv.imshow('image',img) 17 | k = cv.waitKey(1) & 0xFF 18 | if k == 27: 19 | break 20 | # get current positions of four trackbars 21 | r = cv.getTrackbarPos('R','image') 22 | g = cv.getTrackbarPos('G','image') 23 | b = cv.getTrackbarPos('B','image') 24 | s = cv.getTrackbarPos(switch,'image') 25 | if s == 0: 26 | img[:] = 0 27 | else: 28 | img[:] = [b,g,r] 29 | if cv.waitKey(1) & 0xFF == ord('q'): 30 | break 31 | 32 | cv.destroyAllWindows() 33 | 34 | -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/Code/messi5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/2.Gui Features in OpenCV/Code/messi5.jpg -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/README.md: -------------------------------------------------------------------------------- 1 | # 第二章:OpenCV中的Gui相关功能 2 | 3 | 本章节你将学习如何显示和保存图像和视频、控制鼠标事件和创建轨迹栏。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## 一、图像处理入门 10 | 11 | *** 12 | 13 | ### 目标: 14 | 15 | * 在本小节你将学习如何读取图像、如何显示图像,还有如何保存图像 16 | * 你将学习以下几个函数:cv.imread(), cv.imshow() , cv.imwrite() 17 | * 之后,你将学习如何试用Matplotlib显示图像 18 | 19 | ### 1. 读取图像 20 | 使用cv.imread()函数用于读取图像,其中函数的第一个参数为要读取的图像名称,此图像应该处在Python代码文件的工作目录中,或者应给出完整的文件路径。第二个参数是一个标志,以下几种参数分别指定了应该读取图像的方式。 21 | * cv.IMREAD_COLOR:以彩色模式加载图像,任何图像的透明度都将被忽略。这是默认参数。 22 | * cv.IMREAD_GRAYSCALE:以灰度模式加载图像。 23 | * cv.IMREAD_UNCHANGED:包括alpha通道的加载图像模式。 24 | 25 | **注意:或者你可以简单的传递1、0或者-1来替代上面三个标志。** 26 | 27 | 参考以下代码: 28 | 29 | ```python 30 | import numpy as np 31 | import cv2 as cv 32 | # Load an color image in grayscale 33 | img = cv.imread('messi5.jpg',0) 34 | ``` 35 | 36 | **注意:如果加载图像的路径有错误,它并不会报错,而是返回给你一个None值。** 37 | 38 | ### 2. 显示图像 39 | 使用cv.imshow()函数用于在窗口中显示图像,窗口会自动适合图像大小。其中函数的第一个参数是窗口的名称,以字符串类型表示。第二个参数是要加载的图像。你可以显示多个图像窗口,只要它们的窗口名称不同就可以。 40 | 41 | 参考以下代码: 42 | 43 | ```python 44 | cv.imshow('image',img) 45 | cv.waitKey(0) 46 | cv.destroyAllWindows() 47 | ``` 48 | 49 | 窗口将如下图所示: 50 | 51 | ![image1](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/2.Gui%20Features%20in%20OpenCV/image/image1.png) 52 | 53 | cv.waitKey()是一个键盘事件函数,它的参数是以毫秒为单位的时间。该函数等待参数时间,如果时间之内有键盘事件触发则程序继续,如果函数参数设置为0,则无限时间的等待键盘事件触发。它也可以设置为检测指定按键的触发,比如等待按键a的触发,我们将在下面讨论。 54 | 55 | **注意:这个函数除了可以等待键盘事件的触发之外还可以处理很多其他的GUI事件,所以你必须把它放在显示图像函数之后。** 56 | 57 | cv.destroyAllWindow()函数用于关闭我们所创建的所有显示图像的窗口,如果想要关闭任何特定的窗口,请使用cv.destroyWindow()函数,其中把要关闭的窗口名称作为参数传递。 58 | 59 | **注意:一种特殊的情况是,你也可以先创建一个窗口,之后再加载图像。这种情况下你可以自行决定窗口的大小,你可以使用cv.nameWindow()函数进行窗口大小的调整。默认函数参数是cv.WINDOW_AUTOSIZE,你可以将其改成cv.WINDOW_NORMAL,这样你就可以自行调整窗口大小了。当图像尺寸太大或者需要添加轨迹条时,调整窗口大小将会非常有用。** 60 | 61 | 参考以下代码: 62 | 63 | ```python 64 | cv.namedWindow('image', cv.WINDOW_NORMAL) 65 | cv.imshow('image',img) 66 | cv.waitKey(0) 67 | cv.destroyAllWindows() 68 | ``` 69 | 70 | ### 3. 保存图像 71 | 使用cv.imwrite()函数用于保存图像。其中第一个函数是文件名,第二个函数是你要保存的图像。 72 | 73 | 参考一下代码: 74 | 75 | ```python 76 | cv.imwrite('messigray.png',img) 77 | ``` 78 | 79 | 这行代码将Python代码文件的工作目录中保存PNG格式的图像。 80 | 81 | ### 4. 总结以上三条 82 | 下面的代码程序将加载灰度图像,显示图像,如果按's'并退出则保存图像,或者按ESC键直接退出而不保存。 83 | 84 | 参考一下代码: 85 | 86 | ```python 87 | import numpy as np 88 | import cv2 as cv 89 | img = cv.imread('messi5.jpg',0) 90 | cv.imshow('image',img) 91 | k = cv.waitKey(0) 92 | if k == 27: # wait for ESC key to exit 93 | cv.destroyAllWindows() 94 | elif k == ord('s'): # wait for 's' key to save and exit 95 | cv.imwrite('messigray.png',img) 96 | cv.destroyAllWindows() 97 | ``` 98 | 99 | **注意:如果你使用的是64位计算机,则必须将k = cv.waitKey(0)修改为:k = cv.waitKey(0) & 0xFF** 100 | 101 | ### 5.使用Matplotlib 102 | 103 | Matplotlib是Python的绘图库,为你提供各种绘图方法。 你将在即将发表的文章中看到它们。 在这里,你将学习如何使用Matplotlib显示图像。 你可以使用Matplotlib缩放图像,保存等。 104 | 105 | 参考以下代码: 106 | 107 | ```python 108 | import numpy as np 109 | import cv2 as cv 110 | from matplotlib import pyplot as plt 111 | img = cv.imread('messi5.jpg',0) 112 | plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') 113 | plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis 114 | plt.show() 115 | ``` 116 | 117 | 窗口将如下图所示: 118 | 119 | ![image2](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/2.Gui%20Features%20in%20OpenCV/image/image2.png) 120 | 121 | Matplotlib提供了大量的绘图选项。有关更多详细信息,请参阅Matplotlib文档。我们将在学习过程中看到一些。 122 | 123 | **注意:OpenCV加载的彩色图像处于BGR模式。但Matplotlib以RGB模式显示。因此,如果使用OpenCV读取图像,则Matplotlib中的彩色图像将无法正确显示。请参阅练习了解更多详情。** 124 | 125 | ## 二、视频处理入门 126 | 127 | *** 128 | 129 | ### 目标: 130 | 131 | * 在本小节你将学习读取视频、显示视频和保存视频 132 | * 你将学习用摄像头捕获视频并显示 133 | * 你将学习以下几个函数:cv.VideoCapture(), cv.VideoWriter() 134 | 135 | ### 1.用摄像头捕获视频 136 | 137 | 通常,我们需要用摄像头来捕获直播画面。OpenCV为此提供了一些非常简单的函数接口。下面我们来尝试用摄像头来捕获视频画面(此刻我使用的是笔记本电脑的内置网络摄像头)并将画面转化成灰度图像显示出来。这只是一项非常简单的任务。 138 | 139 | 如果要捕获视频,首先要做的是创建一个VideoCapture对象,它的参数可以是设备索引或者是视频文件的名称。设备索引就是指设备所对应的设备号,通常你只连接一个摄像头,所以参数只传递0(或-1)就可以。你可以传递参数1来选择你连接的第二个摄像头,以此类推。之后,你需要逐帧捕获并显示。最后,不要忘记关闭捕获。 140 | 141 | 参考一下代码: 142 | 143 | ```python 144 | import numpy as np 145 | import cv2 as cv 146 | cap = cv.VideoCapture(0) 147 | while(True): 148 | # Capture frame-by-frame 149 | ret, frame = cap.read() 150 | # Our operations on the frame come here 151 | gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) 152 | # Display the resulting frame 153 | cv.imshow('frame',gray) 154 | if cv.waitKey(1) & 0xFF == ord('q'): 155 | break 156 | # When everything done, release the capture 157 | cap.release() 158 | cv.destroyAllWindows() 159 | ``` 160 | 161 | cap.read()返回一个bool值(True / False)。如果读取帧正确,则它将为True。因此,你可以通过检查此返回值来检查视频的结尾。 162 | 163 | 有时可能不能成功的初始化摄像头设备。这种情况下上面的代码会报错。你可以使用cap.isOpened(),来检查是否成功初始化了。如果返回值是True,那就没有问题。否则就要使用函数 cap.open()。 164 | 165 | 你还可以使用cap.get(propld)方法访问此视频的某些功能,其中propId是0到18之间的数字。每个数字表示视频的属性(如果它适用于该视频),完整详细的信息你可以在这里看到:[cv::VideoCapture::get()](https://docs.opencv.org/3.4.1/d8/dfe/classcv_1_1VideoCapture.html#aa6480e6972ef4c00d74814ec841a2939).其中一些值可以使用cap.set(propId,value)进行修改。其中参数value是你想要的新值。 166 | 167 | 例如,我可以通过cap.get(cv.CAP_PROP_FRAME_WIDTH)和cap.get(cv.CAP_PROP_FRAME_HEIGHT)来分别检查帧宽和高度。它返回给我默认值640x480。但如果我想将其修改为320x240,只需使用ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,32))和ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)后即可改变。 168 | 169 | **注意:如果收到报错信息,请确保其他使用摄像头的程序在正常工作(如Linux中的Cheese)。** 170 | 171 | ### 2.播放视频文件 172 | 173 | 它与从相机捕获视频图像原理相同,只需将设备索引更改为视频文件的名字。同时在显示帧时,请给cv.waitKey()函数传递适当的时间参数。如果它太小,视频将非常快,如果它太高,视频将会很慢(这就是你可以用慢动作显示视频)。在正常情况下,25毫秒就可以了。 174 | 175 | 参考以下代码: 176 | 177 | ```python 178 | import numpy as np 179 | import cv2 as cv 180 | cap = cv.VideoCapture('vtest.avi') 181 | while(cap.isOpened()): 182 | ret, frame = cap.read() 183 | gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) 184 | cv.imshow('frame',gray) 185 | if cv.waitKey(1) & 0xFF == ord('q'): 186 | break 187 | cap.release() 188 | cv.destroyAllWindows() 189 | ``` 190 | 191 | **注意:确保安装了正确版本的ffmpeg或gstreamer。 有时候,使用Video Capture是一个令人头疼的问题,主要原因是错误安装了ffmpeg/gstreamer。** 192 | 193 | ### 3.保存视频 194 | 195 | 目前为止我们可以捕获视频,并且逐帧显示并进行处理,现在我们希望保存该视频。对于图片的话是很简单进行保存的,但是对于视频,我们还需要做更多的工作。 196 | 197 | 这次,我们创建一个VideoWriter对象,我们应该指定输出文件名(例如:output.avi)。然后我们应该指定FourCC代码(下一段中的详细信息)。然后应该传递每秒帧数(fps)和帧大小。最后一个是isColor标志。如果是True,则每一帧是彩色图像,否则每一帧是灰度图像。 198 | 199 | [FourCC](https://en.wikipedia.org/wiki/FourCC)是用于指定视频编解码器的4字节代码。可以在[fourcc.org](http://www.fourcc.org/codecs.php)中找到可用代码列表,它取决于平台。以下编解码器对我来说是有用的: 200 | * 在Fedora中:DIVX,XVID,MJPG,X264,WMV1,WMV2。(XVID更为可取.MJPG会产生高大小的视频.X264提供非常小的视频) 201 | * 在Windows中:DIVX(更多要测试和添加) 202 | * 在OSX中:MJPG(.mp4),DIVX(.avi),X264(.mkv)。 203 | 204 | 在从相机捕获图像之后,在垂直方向上翻转每一帧之后逐帧保存。 205 | 206 | 参考以下代码: 207 | 208 | ```python 209 | import numpy as np 210 | import cv2 as cv 211 | cap = cv.VideoCapture(0) 212 | # Define the codec and create VideoWriter object 213 | fourcc = cv.VideoWriter_fourcc(*'XVID') 214 | out = cv.VideoWriter('output.avi',fourcc, 20.0, (640,480)) 215 | while(cap.isOpened()): 216 | ret, frame = cap.read() 217 | if ret==True: 218 | frame = cv.flip(frame,0) 219 | # write the flipped frame 220 | out.write(frame) 221 | cv.imshow('frame',frame) 222 | if cv.waitKey(1) & 0xFF == ord('q'): 223 | break 224 | else: 225 | break 226 | # Release everything if job is finished 227 | cap.release() 228 | out.release() 229 | cv.destroyAllWindows() 230 | ``` 231 | 232 | ## 三、在OpenCV中的绘制函数 233 | 234 | *** 235 | 236 | ### 目标: 237 | 238 | * 在本小节你将学习用OpenCV绘制不同的几何图形 239 | * 你将学习以下几个函数:cv.line(), cv.circle() , cv.rectangle(), cv.ellipse(), cv.putText() 240 | 241 | 在上述所有函数中你将看到以下几个常见的参数: 242 | 243 | * img:用于设置要绘制形状的图像 244 | * color:用于设置绘制图案的颜色。对于BGR图像,将其用元组传递,例如:(255,0,0)为蓝色。对于灰度图像,只需传递标量值。 245 | * thickness:用于设置线条或圆形等的厚度。如果是- 1则在图案内生成闭合图案并填充颜色。这个参数的默认厚度为1。 246 | * lineType:用于设置线条的类型,有8型连接,抗锯齿等。默认情况是8型连接。cv2.LINE_AA为抗锯齿,这样看起来会非常平滑。 247 | 248 | ### 1. 绘制直线 249 | 250 | 要绘制线条,你需要传递线条的起点和终点坐标。我们将创建一个黑色图像,并在其上从左上角到右下角绘制一条蓝线。 251 | 参考以下代码: 252 | 253 | ```python 254 | import numpy as np 255 | import cv2 as cv 256 | # Create a black image 257 | img = np.zeros((512,512,3), np.uint8) 258 | # Draw a diagonal blue line with thickness of 5 px 259 | cv.line(img,(0,0),(511,511),(255,0,0),5) 260 | ``` 261 | 262 | ### 2. 绘制矩形 263 | 264 | 要绘制矩形,你需要传递矩形的左上角和右下角的坐标。这次我们将在图像的右上角绘制一个绿色矩形。 265 | 参考一下代码: 266 | 267 | ```python 268 | cv.rectangle(img,(384,0),(510,128),(0,255,0),3) 269 | ``` 270 | 271 | ### 3. 绘制圆形 272 | 273 | 要绘制圆形,你需要传递其圆点坐标和半径,我们将在上面绘制的矩形内绘制一个圆。 274 | 参考一下代码: 275 | 276 | ```python 277 | cv.circle(img,(447,63), 63, (0,0,255), -1) 278 | ``` 279 | 280 | ### 4. 绘制椭圆 281 | 282 | 要绘制椭圆,我们需要传递四个参数,第一个是椭圆中心位置(x,y),第二个是长轴长度和断轴长度(a,b),第三个是椭圆在逆时针方向上的旋转角度,第四个是startAngle和endAngle表示从主轴顺时针方向测量的椭圆弧的起点和终点,即给出值0和360给出完整的椭圆,给出值180则画出半个椭圆。 283 | 参考一下代码: 284 | 285 | ```python 286 | cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1) 287 | 288 | ``` 289 | 290 | ### 5. 绘制多边形 291 | 292 | 要绘制多边形,首先需要顶点坐标。 将这些点转换为ROWSx1x2的数组,其中ROWS是顶点数,它应该是int32类型。在这里,我们绘制一个带有四个黄色顶点的小多边形。 293 | 参考一下代码: 294 | 295 | ```python 296 | pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32) 297 | pts = pts.reshape((-1,1,2)) 298 | cv.polylines(img,[pts],True,(0,255,255)) 299 | ``` 300 | 301 | **注意:如果第三个参数为False,则绘制所有点的相连图形而不是闭合图形。cv.polylines()可用于绘制多条线。 只需创建要绘制的所有行的列表并将其传递给函数。 所有线条都将单独绘制。 绘制一组行比为每行调用cv.line()要好得多,速度更快。** 302 | 303 | ### 6. 向图像中添加文字 304 | 305 | 要将文本放入图像中,你需要传递以下几个参数:第一个是你要写入的文本数据,第二个是你要放置的位置(即文本数据的左下角),第三个是字体类型(检查cv.putText()文档以获取支持的字体),的四个是字体大小,之后还有一些常规的参数,比如颜色、粗细、线型等,为了更好看,建议使用lineType = cv.LINE_AA作为线型参数的值。 306 | 307 | 我们将在图像上编写白色的OpenCV字样。 308 | 参考以下代码: 309 | 310 | ```python 311 | font = cv.FONT_HERSHEY_SIMPLEX 312 | cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA) 313 | ``` 314 | 315 | ### 7. 结果 316 | 317 | 是时候看看我们所绘制图案的结果了,正如文章之间所讲述的那样,通过显示图像将上面六个绘制结果显示出来。 318 | 窗口将如下图所示: 319 | 320 | ![image3](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/2.Gui%20Features%20in%20OpenCV/image/image3.png) 321 | 322 | ## 四、鼠标作为画笔 323 | 324 | *** 325 | 326 | ### 目标: 327 | 328 | * 在本小节你将学习用OpenCV控制鼠标事件 329 | * 你将学习以下几个函数:cv.setMouseCallback() 330 | 331 | ### 一个简单的示例 332 | 333 | 这里我们来创建一个简单的程序,他会在图片上你双击过的位置绘制一个圆圈。首先我们来创建一个鼠标事件回调函数,但鼠标事件发生是他就会被执行。鼠标事件可以是鼠标上的任何动作,比如左键按下,左键松开,左键双击等。我们可以通过鼠标事件获得与鼠标对应的图片上的坐标。根据这些信息我们可以做任何我们想做的事。你可以通过执行下列代码查看所有被支持的鼠标事件: 334 | 335 | ```python 336 | import cv2 as cv 337 | events = [i for i in dir(cv) if 'EVENT' in i] 338 | print( events ) 339 | ``` 340 | 341 | 所有的鼠标事件回调函数都有一个统一的格式,他们所不同的地方仅仅是被调用后的功能。我们只需要鼠标事件回调函数做一件事:在双击过的地方绘制一个圆形。下面是代码,可以通过注释理解代码: 342 | 343 | ```python 344 | import numpy as np 345 | import cv2 as cv 346 | # mouse callback function 347 | def draw_circle(event,x,y,flags,param): 348 | if event == cv.EVENT_LBUTTONDBLCLK: 349 | cv.circle(img,(x,y),100,(255,0,0),-1) 350 | # Create a black image, a window and bind the function to window 351 | img = np.zeros((512,512,3), np.uint8) 352 | cv.namedWindow('image') 353 | cv.setMouseCallback('image',draw_circle) 354 | while(1): 355 | cv.imshow('image',img) 356 | if cv.waitKey(20) & 0xFF == 27: 357 | break 358 | cv.destroyAllWindows() 359 | ``` 360 | 361 | ### 一个更高级的示例 362 | 现在我们来创建一个更好的程序。这次我们的程序要完成的任务是根据我们选择的模式在拖动鼠标时绘制矩形或者是圆圈(就像画图程序中一样)。所以我们的回调函数包含两部分,一部分画矩形,一部分画圆圈。这是一个典型的例子他可以帮助我们更好理解与构建人机交互式程序,比如物体跟踪,图像分割等。 363 | 参考以下代码: 364 | 365 | ```python 366 | import cv2 as cv 367 | drawing = False # true if mouse is pressed 368 | mode = True # if True, draw rectangle. Press 'm' to toggle to curve 369 | ix,iy = -1,-1 370 | # mouse callback function 371 | def draw_circle(event,x,y,flags,param): 372 | global ix,iy,drawing,mode 373 | if event == cv.EVENT_LBUTTONDOWN: 374 | drawing = True 375 | ix,iy = x,y 376 | elif event == cv.EVENT_MOUSEMOVE: 377 | if drawing == True: 378 | if mode == True: 379 | cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) 380 | else: 381 | cv.circle(img,(x,y),5,(0,0,255),-1) 382 | elif event == cv.EVENT_LBUTTONUP: 383 | drawing = False 384 | if mode == True: 385 | cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) 386 | else: 387 | cv.circle(img,(x,y),5,(0,0,255),-1) 388 | ``` 389 | 390 | 接下来,我们必须将此鼠标回调函数绑定到OpenCV窗口。在主循环中,我们应该把按键'm'设置为切换绘制矩形还是圆形。 391 | 参考以下代码: 392 | 393 | ```python 394 | img = np.zeros((512,512,3), np.uint8) 395 | cv.namedWindow('image') 396 | cv.setMouseCallback('image',draw_circle) 397 | while(1): 398 | cv.imshow('image',img) 399 | k = cv.waitKey(1) & 0xFF 400 | if k == ord('m'): 401 | mode = not mode 402 | elif k == 27: 403 | break 404 | cv.destroyAllWindows() 405 | ``` 406 | 407 | ## 五、轨迹栏作为调色板 408 | 409 | *** 410 | 411 | ### 目标: 412 | 413 | * 在本小节你将学习把轨道栏绑定到OpenCV窗口中 414 | * 你将学习以下几个函数:cv.getTrackbarPos(), cv.createTrackbar() 415 | 416 | ### 代码示例 417 | 418 | 在这里,我们将创建一个简单的应用程序,完成显示指定的颜色。你有一个显示颜色的窗口和三个轨道栏,分别用于指定B,G,R各颜色。你可以滑动轨迹栏并相应地更改窗口所显示的颜色。默认情况下,初始颜色将设置为黑色。 419 | 420 | 对于cv.getTrackbarPos()函数,第一个参数是轨道栏名称,第二个参数是它所附加的窗口名称,第三个参数是默认值,第四个参数是最大值,第五个参数是执行的回调函数每次轨迹栏值都会发生变化。回调函数始终具有默认参数,即轨迹栏位置。在我们的例子中,函数什么都不做,所以我们简单地跳过。 421 | 422 | 轨迹栏的另一个重要应用是将其用作按钮或开关。默认情况下,OpenCV没有按钮功能。因此,你可以使用跟踪栏来获得此类功能。在我们的应用程序中,我们创建了一个开关,其中应用程序仅在开关打开时有效,否则屏幕始终为黑色。 423 | 参考一下代码: 424 | 425 | ```python 426 | import numpy as np 427 | import cv2 as cv 428 | def nothing(x): 429 | pass 430 | # Create a black image, a window 431 | img = np.zeros((300,512,3), np.uint8) 432 | cv.namedWindow('image') 433 | # create trackbars for color change 434 | cv.createTrackbar('R','image',0,255,nothing) 435 | cv.createTrackbar('G','image',0,255,nothing) 436 | cv.createTrackbar('B','image',0,255,nothing) 437 | # create switch for ON/OFF functionality 438 | switch = '0 : OFF \n1 : ON' 439 | cv.createTrackbar(switch, 'image',0,1,nothing) 440 | while(1): 441 | cv.imshow('image',img) 442 | k = cv.waitKey(1) & 0xFF 443 | if k == 27: 444 | break 445 | # get current positions of four trackbars 446 | r = cv.getTrackbarPos('R','image') 447 | g = cv.getTrackbarPos('G','image') 448 | b = cv.getTrackbarPos('B','image') 449 | s = cv.getTrackbarPos(switch,'image') 450 | if s == 0: 451 | img[:] = 0 452 | else: 453 | img[:] = [b,g,r] 454 | if cv.waitKey(1) & 0xFF == ord('q'): 455 | break 456 | 457 | cv.destroyAllWindows() 458 | ``` 459 | 460 | 窗口将如下图所示: 461 | 462 | ![image4](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/2.Gui%20Features%20in%20OpenCV/image/image4.png) 463 | 464 | -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/image/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/2.Gui Features in OpenCV/image/image1.png -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/image/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/2.Gui Features in OpenCV/image/image2.png -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/image/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/2.Gui Features in OpenCV/image/image3.png -------------------------------------------------------------------------------- /2.Gui Features in OpenCV/image/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/2.Gui Features in OpenCV/image/image4.png -------------------------------------------------------------------------------- /3.Core Operations/Code/demo1.py: -------------------------------------------------------------------------------- 1 | import cv2 as cv 2 | import numpy as np 3 | from matplotlib import pyplot as plt 4 | BLUE = [255,0,0] 5 | img1 = cv.imread('opencv-logo.png') 6 | replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE) 7 | reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT) 8 | reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101) 9 | wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP) 10 | constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE) 11 | plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL') 12 | plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE') 13 | plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT') 14 | plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101') 15 | plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP') 16 | plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT') 17 | plt.show() -------------------------------------------------------------------------------- /3.Core Operations/Code/demo2.py: -------------------------------------------------------------------------------- 1 | import cv2 as cv 2 | import numpy as np 3 | 4 | img1 = cv.imread('ml.png') 5 | img2 = cv.imread('opencv-logo.png') 6 | dst = cv.addWeighted(img1,0.7,img2,0.3,0) 7 | 8 | while(1): 9 | cv.imshow('dst',dst) 10 | if cv.waitKey(1) & 0xFF == ord('q'): 11 | break 12 | 13 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /3.Core Operations/Code/demo3.py: -------------------------------------------------------------------------------- 1 | import cv2 as cv 2 | import numpy as np 3 | 4 | # Load two images 5 | img1 = cv.imread('messi5.jpg') 6 | img2 = cv.imread('opencv-logo-white.png') 7 | # I want to put logo on top-left corner, So I create a ROI 8 | rows,cols,channels = img2.shape 9 | roi = img1[0:rows, 0:cols ] 10 | # Now create a mask of logo and create its inverse mask also 11 | img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY) 12 | ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY) 13 | mask_inv = cv.bitwise_not(mask) 14 | # Now black-out the area of logo in ROI 15 | img1_bg = cv.bitwise_and(roi,roi,mask = mask_inv) 16 | # Take only region of logo from logo image. 17 | img2_fg = cv.bitwise_and(img2,img2,mask = mask) 18 | # Put logo in ROI and modify the main image 19 | dst = cv.add(img1_bg,img2_fg) 20 | img1[0:rows, 0:cols ] = dst 21 | 22 | while(1): 23 | cv.imshow('res',img1) 24 | if cv.waitKey(1) & 0xFF == ord('q'): 25 | break 26 | 27 | cv.destroyAllWindows() -------------------------------------------------------------------------------- /3.Core Operations/Code/demo4.py: -------------------------------------------------------------------------------- 1 | e1 = cv.getTickCount() 2 | # your code execution 3 | e2 = cv.getTickCount() 4 | time = (e2 - e1)/ cv.getTickFrequency() 5 | img1 = cv.imread('messi5.jpg') 6 | e1 = cv.getTickCount() 7 | for i in xrange(5,49,2): 8 | img1 = cv.medianBlur(img1,i) 9 | e2 = cv.getTickCount() 10 | t = (e2 - e1)/cv.getTickFrequency() 11 | print( t ) 12 | # Result I got is 0.521107655 seconds -------------------------------------------------------------------------------- /3.Core Operations/Code/demo5.py: -------------------------------------------------------------------------------- 1 | # check if optimization is enabled 2 | In [5]: cv.useOptimized() 3 | Out[5]: True 4 | In [6]: %timeit res = cv.medianBlur(img,49) 5 | 10 loops, best of 3: 34.9 ms per loop 6 | # Disable it 7 | In [7]: cv.setUseOptimized(False) 8 | In [8]: cv.useOptimized() 9 | Out[8]: False 10 | In [9]: %timeit res = cv.medianBlur(img,49) 11 | 10 loops, best of 3: 64.1 ms per loop -------------------------------------------------------------------------------- /3.Core Operations/Code/demo6.py: -------------------------------------------------------------------------------- 1 | # check if optimization is enabled 2 | In [5]: cv.useOptimized() 3 | Out[5]: True 4 | In [6]: %timeit res = cv.medianBlur(img,49) 5 | 10 loops, best of 3: 34.9 ms per loop 6 | # Disable it 7 | In [7]: cv.setUseOptimized(False) 8 | In [8]: cv.useOptimized() 9 | Out[8]: False 10 | In [9]: %timeit res = cv.medianBlur(img,49) 11 | 10 loops, best of 3: 64.1 ms per loop 12 | 13 | In [35]: %timeit z = cv.countNonZero(img) 14 | 100000 loops, best of 3: 15.8 us per loop 15 | In [36]: %timeit z = np.count_nonzero(img) 16 | 1000 loops, best of 3: 370 us per loop 17 | -------------------------------------------------------------------------------- /3.Core Operations/Code/messi5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Code/messi5.jpg -------------------------------------------------------------------------------- /3.Core Operations/Code/ml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Code/ml.png -------------------------------------------------------------------------------- /3.Core Operations/Code/opencv-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Code/opencv-logo-white.png -------------------------------------------------------------------------------- /3.Core Operations/Code/opencv-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Code/opencv-logo.png -------------------------------------------------------------------------------- /3.Core Operations/Image/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Image/image1.png -------------------------------------------------------------------------------- /3.Core Operations/Image/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Image/image2.png -------------------------------------------------------------------------------- /3.Core Operations/Image/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Image/image3.png -------------------------------------------------------------------------------- /3.Core Operations/Image/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/3.Core Operations/Image/image4.png -------------------------------------------------------------------------------- /3.Core Operations/README.md: -------------------------------------------------------------------------------- 1 | # 第三章:OpenCV核心操作 2 | 3 | 本章节你将学习图像的基本操作,如像素编辑、几何变换、代码优化和一些数学工具等。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## 一、图像的基本操作 10 | 11 | *** 12 | 13 | ### 目标: 14 | 15 | 本章节你需要学习以下内容: 16 | 17 | * 获取并修改图像的像素值 18 | * 获取图像的属性 19 | * 设置感兴趣区域 20 | * 图像的拆分和合并 21 | 22 | 本节中的几乎所有操作主要与Numpy而不是OpenCV有关。使用OpenCV编写更好的优化代码需要先熟悉Numpy。 23 | 24 | **注意:示例将在Python终端中显示,因为大多数只是单行代码** 25 | 26 | ### 1.获取并修改图像的像素值 27 | 28 | 首先我们先加载一章彩色图像: 29 | 30 | ```python 31 | >>> import numpy as np 32 | >>> import cv2 as cv 33 | >>> img = cv.imread('messi5.jpg') 34 | ``` 35 | 36 | 之后你可以通过行和列的坐标值获取该像素点的像素值。对于BGR图像,它返回一个蓝色,绿色,红色值的数组。对于灰度图像,仅返回相应的强度值。 37 | 38 | ```python 39 | >>> px = img[100,100] 40 | >>> print( px ) 41 | [157 166 200] 42 | # accessing only blue pixel 43 | >>> blue = img[100,100,0] 44 | >>> print( blue ) 45 | 157 46 | ``` 47 | 48 | 你可以用同样的方法修改像素点的像素值: 49 | 50 | ```python 51 | >>> img[100,100] = [255,255,255] 52 | >>> print( img[100,100] ) 53 | [255 255 255] 54 | ``` 55 | 56 | **注意:Numpy是一个用于快速阵列计算的优化库。因此,简单地访问每个像素值并对其进行修改将非常缓慢,并且不推荐这样做。上述方法通常用于选择数组的区域,比如前5行和后3列。对于单个像素访问,Numpy数组方法array.item()和array.itemset()被认为是更好的选择,但它们总是返回标量。如果要获取所有B,G,R值,则需要单独调用array.item()。** 57 | 58 | 更好的像素获取和编辑方法: 59 | 60 | ```python 61 | # accessing RED value 62 | >>> img.item(10,10,2) 63 | 59 64 | # modifying RED value 65 | >>> img.itemset((10,10,2),100) 66 | >>> img.item(10,10,2) 67 | 100 68 | ``` 69 | 70 | ### 2.获取图像的属性 71 | 72 | 图像属性包括行数,列数和通道数,图像数据类型,像素数等。 73 | 74 | 使用img.shape可以获取图像的形状。它返回一组行,列和通道的元组(如果图像是彩色的): 75 | 76 | ```python 77 | >>> print( img.shape ) 78 | (342, 548, 3) 79 | ``` 80 | 81 | **注意:如果图像是灰度图像,则返回的元组仅包含行数和列数,因此检查加载的图像是灰度还是颜色是一种很好的方法。** 82 | 83 | 使用img.size获取的像素总数: 84 | 85 | ```python 86 | >>> print( img.size ) 87 | 562248 88 | ``` 89 | 90 | 使用img.dtype获取图像数据类型: 91 | 92 | ```python 93 | >>> print( img.dtype ) 94 | uint8 95 | ``` 96 | 97 | **注意:img.dtype在调试时非常重要,因为OpenCV-Python代码中的大量错误是由无效的数据类型引起的。** 98 | 99 | ### 3.图像ROI 100 | 101 | 有时你需要对一幅图像的特定区域进行操作。例如我们要检测一副图像中眼睛的位置,我们首先应该在图像中找到脸,再在脸的区域中找眼睛,而不是直接在一整幅图像中搜索。这样会提高程序的准确性(因为眼睛总在脸上)和性能(因为我们在很小的区域内搜索)。 102 | 103 | ROI 也是使用 Numpy 索引来获得的。现在我们选择球的部分并把他拷贝到图像的其他区域。 104 | 105 | ```python 106 | >>> ball = img[280:340, 330:390] 107 | >>> img[273:333, 100:160] = ball 108 | ``` 109 | 110 | 窗口将如下图所示: 111 | 112 | ![image1](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/3.Core%20Operations/Image/image1.png) 113 | 114 | ### 4.图像通道的查分和合并 115 | 有时需要在B,G,R通道图像上单独工作。在这种情况下,需要将BGR图像分割为单个通道。或者在其他情况下,可能需要将这些单独的通道合并到BGR图像。你可以通过以下方式完成: 116 | 117 | ```python 118 | >>> b,g,r = cv.split(img) 119 | >>> img = cv.merge((b,g,r)) 120 | ``` 121 | 122 | 或者: 123 | 124 | ```python 125 | >>> b = img[:,:,0] 126 | ``` 127 | 128 | 假设你要将所有红色像素设置为零,则无需先拆分通道。使用Numpy索引更快: 129 | 130 | ```python 131 | >>> img[:,:,2] = 0 132 | ``` 133 | 134 | **注意:cv.split()是一项代价高昂的操作(就消耗时间而言)。所以只有在你需要时才这样做。否则使用Numpy索引。** 135 | 136 | ### 5.制作图像边框 137 | 138 | 如果要在图像周围创建边框,比如相框,可以使用cv.copyMakeBorder()。但它有更多卷积运算,零填充等应用。该函数需要以下参数: 139 | 140 | * src 输入图像 141 | * top, bottom, left, right 对应边界的像素数目。 142 | * borderType 要添加那种类型的边界,类型如下: 143 | – cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要下一个参数(value)。 144 | – cv2.BORDER_REFLECT 边界元素的镜像。比如: fedcba|abcde-fgh|hgfedcb 145 | – cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba 146 | – cv2.BORDER_REPLICATE 重复最后一个元素。例如: aaaaaa|abcdefgh|hhhhhhh 147 | – cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh|abcdefgh|abcdefg 148 | * value 边界颜色,如果边界的类型是 cv2.BORDER_CONSTANT 149 | 150 | 下面是一个示例代码,演示了所有这些边框类型,以便更好地理解: 151 | 152 | ```python 153 | import cv2 as cv 154 | import numpy as np 155 | from matplotlib import pyplot as plt 156 | BLUE = [255,0,0] 157 | img1 = cv.imread('opencv-logo.png') 158 | replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE) 159 | reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT) 160 | reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101) 161 | wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP) 162 | constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE) 163 | plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL') 164 | plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE') 165 | plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT') 166 | plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101') 167 | plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP') 168 | plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT') 169 | plt.show() 170 | ``` 171 | 172 | 窗口将如下图所示(图像与matplotlib一起显示。因此RED和BLUE通道将互换): 173 | 174 | ![image2](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/3.Core%20Operations/Image/image2.png) 175 | 176 | ## 二、图像的算术运算 177 | 178 | *** 179 | 180 | ### 目标: 181 | * 本小节你将学习对图像的几种运算,如加法、减法、按位运算等 182 | * 你将学习以下几个函数: cv.add(), cv.addWeighted() 183 | 184 | ### 1.图像的加法 185 | 186 | 你可以使用OpenCV的cv.add()函数把两幅图像相加,或者可以简单地通过numpy操作添加两个图像,如res = img1 + img2。两个图像应该具有相同的大小和类型,或者第二个图像可以是标量值。 187 | 188 | **注意:OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算。** 189 | 190 | 参考以下代码: 191 | 192 | ```python 193 | >>> x = np.uint8([250]) 194 | >>> y = np.uint8([10]) 195 | >>> print( cv.add(x,y) ) # 250+10 = 260 => 255 196 | [[255]] 197 | >>> print( x+y ) # 250+10 = 260 % 256 = 4 198 | [4] 199 | ``` 200 | 201 | 这种差别在你对两幅图像进行加法时会更加明显。OpenCV 的结果会更好一点。所以我们尽量使用 OpenCV 中的函数。 202 | 203 | ### 2.图像的混合 204 | 205 | 这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。图像混合的计算公式如下: 206 | 207 | >g(x) = (1−α)f0(x) + αf1(x) 208 | 209 | 通过修改 α 的值(0 → 1),可以实现非常炫酷的混合。 210 | 211 | 现在我们把两幅图混合在一起。第一幅图的权重是0.7,第二幅图的权重是0.3。函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。 212 | 213 | >dst = α⋅img1 + β⋅img2 + γ 214 | 215 | 这里γ取为零。 216 | 217 | 参考以下代码: 218 | 219 | ```python 220 | img1 = cv.imread('ml.png') 221 | img2 = cv.imread('opencv-logo.png') 222 | dst = cv.addWeighted(img1,0.7,img2,0.3,0) 223 | cv.imshow('dst',dst) 224 | cv.waitKey(0) 225 | cv.destroyAllWindows() 226 | ``` 227 | 228 | 窗口将如下图显示: 229 | 230 | ![image3](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/3.Core%20Operations/Image/image3.png) 231 | 232 | ### 3.图像按位操作 233 | 234 | 这里包括的按位操作有:AND,OR,NOT,XOR 等。当我们提取图像的一部分,选择非矩形ROI时这些操作会很有用(你会在后续章节中看到)。下面的例子就是教给我们如何改变一幅图的特定区域。我想把OpenCV的标志放到另一幅图像上。如果我使用图像的加法,图像的颜色会改变,如果使用图像的混合,会得到一个透明的效果,但是我不希望它透明。如果它是矩形我可以像上一章那样使用ROI。但是OpenCV标志不是矩形。所以我们可以通过下面的按位运算实现: 235 | 236 | ```python 237 | # Load two images 238 | img1 = cv.imread('messi5.jpg') 239 | img2 = cv.imread('opencv-logo-white.png') 240 | # I want to put logo on top-left corner, So I create a ROI 241 | rows,cols,channels = img2.shape 242 | roi = img1[0:rows, 0:cols ] 243 | # Now create a mask of logo and create its inverse mask also 244 | img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY) 245 | ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY) 246 | mask_inv = cv.bitwise_not(mask) 247 | # Now black-out the area of logo in ROI 248 | img1_bg = cv.bitwise_and(roi,roi,mask = mask_inv) 249 | # Take only region of logo from logo image. 250 | img2_fg = cv.bitwise_and(img2,img2,mask = mask) 251 | # Put logo in ROI and modify the main image 252 | dst = cv.add(img1_bg,img2_fg) 253 | img1[0:rows, 0:cols ] = dst 254 | cv.imshow('res',img1) 255 | cv.waitKey(0) 256 | cv.destroyAllWindows() 257 | ``` 258 | 259 | 窗口将如下图显示。左面的图像是我们创建的模板,右边的是最终结果。为了帮助大家理解,我把上面程序的中间结果也显示了出来,特别是img1_bg和img2_fg。 260 | 261 | ![image4](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/3.Core%20Operations/Image/image4.png) 262 | 263 | ## 三、程序性能评估及优化 264 | *** 265 | 266 | ### 目标: 267 | 268 | 在图像处理中,由于每秒需要处理大量操作,因此处理图像的代码必须不仅要能给出正确的结果,同时还必须要快。所以在本小节中,你将学习: 269 | 270 | * 衡量代码的性能。 271 | * 一些优化代码性能的技巧。 272 | * 你将学习以下几个函数:cv.getTickCount, cv.getTickFrequency 273 | 274 | 除了OpenCV库之外,Python还提供了一个time模块,有助于测量执行时间。另一个profile模块可以获得有关代码的详细报告,例如代码中每个函数所花费的时间,调用函数的次数等。如果你使用的是IPython,所有这些功能都以一个有好的方式整合到一起。我们将看到一些重要的内容,有关更多详细信息,请查看“其他资源”部分中的链接。 275 | 276 | ### 1.使用 OpenCV 衡量程序效率 277 | 278 | cv.getTickCount函数返回参考事件(如机器开启时刻)到调用此函数的时钟周期数。因此,如果在函数执行之前和之后都调用它,则会获得用于执行函数的时钟周期数。 279 | 280 | cv.getTickFrequency函数返回时钟周期的频率,或每秒钟的时钟周期数。所以,要想获得函数的执行时间,你可以执行以下操作: 281 | 282 | ```python 283 | e1 = cv.getTickCount() 284 | # your code execution 285 | e2 = cv.getTickCount() 286 | time = (e2 - e1)/ cv.getTickFrequency() 287 | ``` 288 | 289 | 我们将展示以下示例示例,下面的例子使用从5到49几个不同大小的核进行中值滤波。(不要考虑结果会是什么样的,这不是我们的目的): 290 | 291 | ```python 292 | img1 = cv.imread('messi5.jpg') 293 | e1 = cv.getTickCount() 294 | for i in xrange(5,49,2): 295 | img1 = cv.medianBlur(img1,i) 296 | e2 = cv.getTickCount() 297 | t = (e2 - e1)/cv.getTickFrequency() 298 | print( t ) 299 | # Result I got is 0.521107655 seconds 300 | ``` 301 | 302 | **注意:你可以使用time模块的函数执行相同操作来替代cv.getTickCount,使用time.time()函数,然后取两次结果的时间差。** 303 | 304 | ### 2.OpenCV中的默认优化 305 | 306 | 许多OpenCV的功能都使用SSE2,AVX等进行了优化。它还包含了一些未经优化的代码。因此,如果我们的系统支持这些功能,我们应该利用它们(几乎所有现代处理器都支持它们),编译时是默认启用优化。因此,OpenCV运行的代码就是已优化代码(如果已启用),否则运行未优化代码。 你可以使用cv.useOptimized()来检查它是否已启用/禁用优化,并使用cv.setUseOptimized())来启用/禁用它。让我们看一个简单的例子。 307 | 308 | ```python 309 | # check if optimization is enabled 310 | In [5]: cv.useOptimized() 311 | Out[5]: True 312 | In [6]: %timeit res = cv.medianBlur(img,49) 313 | 10 loops, best of 3: 34.9 ms per loop 314 | # Disable it 315 | In [7]: cv.setUseOptimized(False) 316 | In [8]: cv.useOptimized() 317 | Out[8]: False 318 | In [9]: %timeit res = cv.medianBlur(img,49) 319 | 10 loops, best of 3: 64.1 ms per loop 320 | ``` 321 | 322 | 优化的中值滤波比未优化的版本快2倍。如果检查其来源,你可以看到中值滤波是经过SIMD优化的。因此,你可以使用它来在代码顶部启用优化(请记住它默认启用)。 323 | 324 | ### 3.检测IPython中的性能 325 | 326 | 有时你可能需要比较两个类似操作的性能。IPython提供了一个魔术命令timeit来执行此操作。 它可以让代码运行几次以获得更准确的结果。它们也适用于测量单行代码。 327 | 328 | 例如,你想知道以下哪个加法操作更快吗? 329 | >x = 5; y = x ** 2 330 | >x = 5; y = x * x 331 | >x = np.uint8([5]); y = x * x 332 | >y = np.square(x) 333 | 我们将在IPython shell中使用timeit得到答案。 334 | 335 | ```python 336 | In [10]: x = 5 337 | In [11]: %timeit y=x**2 338 | 10000000 loops, best of 3: 73 ns per loop 339 | In [12]: %timeit y=x*x 340 | 10000000 loops, best of 3: 58.3 ns per loop 341 | In [15]: z = np.uint8([5]) 342 | In [17]: %timeit y=z*z 343 | 1000000 loops, best of 3: 1.25 us per loop 344 | In [19]: %timeit y=np.square(z) 345 | 1000000 loops, best of 3: 1.16 us per loop 346 | ``` 347 | 348 | 你可以看到,x = 5; y = x * x是最快的,与Numpy相比快了约20倍。如果你也考虑创建阵列,它可能会快达100倍。很酷对不对 (Numpy开发者正在研究这个问题) 349 | 350 | **注意:Python标量操作比Numpy标量操作更快。因此对于包含一个或两个元素的操作,Python标量优于Numpy数组。当阵列的大小稍大时,Numpy会占据优势。** 351 | 352 | 我们将再尝试一个例子。 这次,我们将比较同一图像的cv.countNonZero()和np.count_nonzero()的性能。 353 | ```python 354 | In [35]: %timeit z = cv.countNonZero(img) 355 | 100000 loops, best of 3: 15.8 us per loop 356 | In [36]: %timeit z = np.count_nonzero(img) 357 | 1000 loops, best of 3: 370 us per loop 358 | ``` 359 | 360 | 你可以看到,OpenCV的执行性能比Numpy快将近25倍。 361 | 362 | **注意:通常,OpenCV函数比Numpy函数更快。因此对于相同的操作,OpenCV功能是首选。但是可能也有例外,尤其是当使用Numpy对视图而不是复制数组时。** 363 | 364 | ### 4.更多的IPython命令 365 | 366 | 还有几个魔法命令可以用来检测程序的执行效率,profiling,line profiling,memory measurement等。他们都有完善的文档。所以这里只提供了超链接。感兴趣的读者可以自己学习一下。 367 | 368 | ### 5.性能优化技术 369 | 370 | 有几种技术和编码方法可以利用Python和Numpy的最大性能。此处仅注明相关的内容,并提供重要来源的链接。这里要注意的主要是,首先尝试以简单的方式实现算法。一旦工作,对其进行分析,找到瓶颈并进行优化。 371 | 372 | 1. 尽量避免在Python中使用循环,尤其是双层/三层嵌套循环等。它们本身就很慢。 373 | 2. 将算法/代码尽量使用向量化操作,因为Numpy和OpenCV针对向量运算进行了优化。 374 | 3. 利用高速缓存一致性。 375 | 4. 除非需要,否则不要复制数组。尝试使用视图去替代复制数组。数组复制是一项非常浪费资源的操作。 376 | 377 | 即使在完成所有这些操作之后,如果你的代码仍然很慢,或者使用大型循环是不可避免的,请使用其他库(如Cython)来加快速度。 378 | -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image1.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image10.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image11.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image12.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image13.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image14.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image15.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image16.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image17.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image18.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image19.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image2.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image20.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image21.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image22.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image23.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image24.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image25.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image26.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image27.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image28.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image29.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image3.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image30.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image31.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image32.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image33.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image34.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image35.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image36.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image37.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image38.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image39.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image4.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image40.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image41.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image42.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image43.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image44.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image45.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image46.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image47.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image48.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image49.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image5.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image50.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image51.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image52.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image53.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image54.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image55.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image56.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image57.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image58.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image59.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image6.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image60.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image61.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image61.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image62.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image63.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image63.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image64.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image65.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image66.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image67.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image67.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image68.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image68.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image69.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image69.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image7.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image70.gif -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image71.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image72.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image73.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image74.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image74.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image75.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image76.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image77.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image77.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image78.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image79.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image79.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image8.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image80.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image81.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image82.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image82.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image83.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image83.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image84.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image84.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image85.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image85.png -------------------------------------------------------------------------------- /4.Image Processing in OpenCV/Image/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/4.Image Processing in OpenCV/Image/image9.png -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image1.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image10.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image11.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image12.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image13.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image14.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image15.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image16.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image17.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image18.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image19.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image2.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image20.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image21.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image22.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image23.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image24.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image3.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image4.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image5.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image6.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image7.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image8.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/Image/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/5.Feature Detection and Description/Image/image9.jpg -------------------------------------------------------------------------------- /5.Feature Detection and Description/README.md: -------------------------------------------------------------------------------- 1 | # 第五章:特征提取与描述 2 | 3 | 本章节你将学习图像的主要特征、Harris角点检测、Shi-Tomasi角点检测、SIFT、SURF、特征匹配等OpenCV图像特征提取与描述的相关内容。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## 一、理解图像特征 10 | 11 | *** 12 | 13 | ### 目标: 14 | 15 | 本章节你需要学习以下内容: 16 | 17 | *在本章中,我们将尝试了解哪些是图像的特征,理解为什么图像特征很重要,理解为什么角点很重要等等。 18 | 19 | ### 解释 20 | 21 | 相信大多数人都玩过拼图游戏。你会得到许多零零散散的碎片,然后需要正确地组装它们以形成一个大的完整的图像。问题是,你是怎么做到的?如何将相同的理论应用到计算机程序中,以便计算机可以玩拼图游戏?如果计算机可以玩拼图游戏,为什么我们不能给计算机提供很多真实自然景观的真实图像,并告诉它将所有这些图像拼接成一个大的单个图像?如果计算机可以将几个零散图像拼接成一个,那么如何提供大量建筑物或任何结构的图片并告诉计算机从中创建3D模型呢? 22 | 23 | 问题和想象力可以是无边无际的,但这一切都取决于最基本的问题:你是如何玩拼图游戏的?你如何将大量的混乱图像片段排列成一个大的完整的图像?如何将大量零散图像拼接成整体图像? 24 | 25 | 答案是,我们正在寻找独特的特定模式或特定功能,可以轻松跟踪并轻松比较。如果我们找到这样一个特征的定义,我们可能会发现很难用文字表达,但我们知道它们是什么。如果有人要求你指出可以在多个图像之间进行比较的一个好的功能,你可以指出一个。这就是为什么即使是小孩子也可以简单地玩这些游戏。我们在图像中搜索这些特征,找到它们,在其他图像中查找相同的特征并拼凑它们。(在拼图游戏中,我们更多地关注不同图像的连续性)。所有这些能力都是我们天生所具备的。 26 | 27 | 因此,我们的一个基本问题扩展到更多,但变得更具体。这些功能是什么?(答案对于计算机也应该是可以理解的。) 28 | 29 | 很难说人类如何找到这些特征。这已经在我们的大脑中编程。但是如果我们深入研究一些图片并搜索不同的图案,我们会发现一些有趣的东西。例如,拍下图片: 30 | 31 | ![image1](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image1.jpg) 32 | 33 | 图像非常简单。在图像的顶部,给出了六个小图像补丁。你的问题是在原始图像中找到这些补丁的确切位置。你能找到多少正确的结果? 34 | 35 | A和B是平坦的表面,它们分布在很多区域。很难找到这些补丁的确切位置。 36 | 37 | C和D要简单得多。它们是建筑物的边缘。你可以找到一个大概的位置,但确切的位置仍然很困难。这是因为沿着边缘的模式是相同的。然而,在边缘,它是不同的。因此,与平坦区域相比,边缘是更好的特征,但是不够好(用于比较边缘的连续性在拼图中是好的)。 38 | 39 | 最后,E和F是建筑物的一些角点。它们很容易找到。因为在角点,无论你移动这个补丁,它都会有所不同。所以它们可以被认为是很好的功能。所以现在我们进入更简单(和广泛使用的图像)以便更好地理解。 40 | 41 | ![image2](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image2.jpg) 42 | 43 | 就像上面一样,蓝色斑块是平坦的区域,很难找到和跟踪。无论你移动蓝色补丁,它看起来都一样。黑色贴片有边缘。如果沿垂直方向(即沿着渐变方向)移动它会改变。沿边缘移动(平行于边缘),看起来一样。对于红色补丁,它是一个角点。无论你移动补丁,它看起来都不同,意味着它是独一无二的。所以基本上,角点被认为是图像中的好特征。(不仅仅是角点,在某些情况下,blob被认为是很好的特征)。 44 | 45 | 所以现在我们回答了我们的问题,“这些功能是什么?”。但接下来的问题就出现了。我们如何找到它们?或者我们如何找到角点?我们以直观的方式回答了这一点,即在图像中寻找在其周围的所有区域中移动(少量)时具有最大变化的区域。在接下来的章节中,这将被投射到计算机语言中。因此,查找这些图像特征称为特征检测。 46 | 47 | 我们在图像中找到了这些功能。一旦找到它,你应该能够在其他图像中找到相同的内容。这是怎么做到的?我们用一个区域围绕这个特征,我们用自己的话解释它,比如“上部是蓝天,下部是建筑物的区域,那个建筑物上有玻璃等”,你在另一个地方寻找相同的区域图片。基本上,你正在描述该功能。类似地,计算机还应该描述特征周围的区域,以便它可以在其他图像中找到它。所谓的描述称为特征描述。获得这些功能及其描述后,你可以在所有图像中找到相同的功能并对齐它们,将它们拼接在一起或做任何你想做的事情。 48 | 49 | 因此,在本单元中,我们正在寻找OpenCV中的不同算法来查找功能,描述功能,匹配它们等。 50 | 51 | ## 二、Harris角点检测 52 | 53 | *** 54 | 55 | ### 目标: 56 | 57 | 本章节你需要学习以下内容: 58 | 59 | *我们将了解Harris Corner Detection背后的概念。 60 | *我们将看到函数:cv.cornerHarris(),cv.cornerSubPix() 61 | 62 | ### 1、理论 63 | 64 | 在上一节我们已经知道了角点的一个特性:向任何方向移动变化都很大。Chris_Harris 和 Mike_Stephens 早在 1988 年的文章《A CombinedCorner and Edge Detector》中就已经提出了焦点检测的方法,被称为Harris 角点检测。他把这个简单的想法转换成了数学形式。将窗口向各个方向移动(u,v)然后计算所有差异的总和。表示如下: 65 | 66 | $$E(u,v) = \sum_{x,y} \underbrace{w(x,y)}_\text{window function} \, [\underbrace{I(x+u,y+v)}_\text{shifted intensity}-\underbrace{I(x,y)}_\text{intensity}]^2$$ 67 | 68 | 窗口函数可以是正常的矩形窗口也可以是对每一个像素给予不同权重的高斯窗口。 69 | 70 | 角点检测中要使 E (µ,ν) 的值最大。这就是说必须使方程右侧的第二项的取值最大。对上面的等式进行泰勒级数展开然后再通过几步数学换算(可以参考其他标准教材),我们得到下面的等式: 71 | 72 | $$E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} M \begin{bmatrix} u \\ v \end{bmatrix}$$ 73 | 74 | 其中: 75 | 76 | $$M = \sum_{x,y} w(x,y) \begin{bmatrix}I_x I_x & I_x I_y \\ I_x I_y & I_y I_y \end{bmatrix}$$ 77 | 78 | 这里,$I_x$和$I_y$分别是x和y方向上的图像导数。(可以使用函数cv.Sobel()轻松找到)。 79 | 80 | 然后是主要部分。在此之后,他们创建了一个分数,基本上是一个等式,它将确定一个窗口是否可以包含一个角点。 81 | 82 | $$R = det(M) - k(trace(M))^2$$ 83 | 84 | 其中: 85 | 86 | * $R = det(M) - k(trace(M))^2$ 87 | * $trace(M) = \lambda_1 + \lambda_2$ 88 | * $\lambda_1$和$\lambda_2$是M的本征值 89 | 90 | 因此,这些特征值的值决定区域是角点,边缘还是平坦。 91 | 92 | * 当$|R|$很小,当$\lambda_1$和$\lambda_2$很小时,该区域是平坦的。 93 | * 当$R<0$时,在$\lambda_1 >> \lambda_2$时发生,反之亦然,该区域是边缘。 94 | * 当R很大时,当$\lambda_1$和$\lambda_2$大并且$\lambda_1 \sim \lambda_2$时发生,该区域是拐角。 95 | * 96 | 它可以用下面这张很好理解的图片表示: 97 | 98 | ![image3](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image3.jpg) 99 | 100 | 因此Harris角点检测的结果是一个由角点分数构成的灰度图像。选取适当的阈值对结果图像进行二值化我们就检测到了图像中的角点。我们将用一个简单的图片来演示一下。 101 | 102 | ### 2、OpenCV中的Harris角点探测器 103 | 104 | 为此,OpenCV具有函数cv.cornerHarris()。它的参数是: 105 | 106 | * img - 输入图像,应该是灰度和float32类型。 107 | * blockSize - 考虑角点检测的邻域大小 108 | * ksize - 使用的Sobel衍生物的孔径参数。 109 | * k - 方程中的Harris检测器自由参数。 110 | * 111 | 请参阅以下示例: 112 | 113 | ```python 114 | import numpy as np 115 | import cv2 as cv 116 | 117 | filename = 'chessboard.png' 118 | img = cv.imread(filename) 119 | gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 120 | 121 | gray = np.float32(gray) 122 | dst = cv.cornerHarris(gray,2,3,0.04) 123 | 124 | #result is dilated for marking the corners, not important 125 | dst = cv.dilate(dst,None) 126 | 127 | # Threshold for an optimal value, it may vary depending on the image. 128 | img[dst>0.01*dst.max()]=[0,0,255] 129 | 130 | cv.imshow('dst',img) 131 | if cv.waitKey(0) & 0xff == 27: 132 | cv.destroyAllWindows() 133 | ``` 134 | 135 | 以下是三个结果: 136 | 137 | ![image4](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image4.jpg) 138 | 139 | ### 3、具有亚像素精度的角点 140 | 141 | 有时,你可能需要以最高精度找到角点。OpenCV附带了一个函数cv.cornerSubPix(),它进一步细化了以亚像素精度检测到的角点。以下是一个例子。像往常一样,我们需要先找到Harris的角点。然后我们传递这些角的质心(角点处可能有一堆像素,我们采用它们的质心)来细化它们。Harris角以红色像素标记,精致角以绿色像素标记。对于此函数,我们必须定义何时停止迭代的标准。我们在指定的迭代次数或达到一定精度后停止它,以先发生者为准。我们还需要定义它将搜索角点的邻域大小。 142 | 143 | ```python 144 | import numpy as np 145 | import cv2 as cv 146 | 147 | filename = 'chessboard2.jpg' 148 | img = cv.imread(filename) 149 | gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 150 | 151 | # find Harris corners 152 | gray = np.float32(gray) 153 | dst = cv.cornerHarris(gray,2,3,0.04) 154 | dst = cv.dilate(dst,None) 155 | ret, dst = cv.threshold(dst,0.01*dst.max(),255,0) 156 | dst = np.uint8(dst) 157 | 158 | # find centroids 159 | ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst) 160 | 161 | # define the criteria to stop and refine the corners 162 | criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.001) 163 | corners = cv.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria) 164 | 165 | # Now draw them 166 | res = np.hstack((centroids,corners)) 167 | res = np.int0(res) 168 | img[res[:,1],res[:,0]]=[0,0,255] 169 | img[res[:,3],res[:,2]] = [0,255,0] 170 | 171 | cv.imwrite('subpixel5.png',img) 172 | ``` 173 | 174 | 下面是结果,其中一些重要位置显示在缩放窗口中以显示: 175 | 176 | ![image5](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image5.jpg) 177 | 178 | ## 三、Shi-Tomasi角点探测器和适合于跟踪的图像特征 179 | 180 | *** 181 | 182 | ### 目标: 183 | 184 | 本章节你需要学习以下内容: 185 | 186 | *我们将了解另一个角点探测器:Shi-Tomasi角点探测器 187 | *我们将看到函数:cv.goodFeaturesToTrack() 188 | 189 | ### 1、理论 190 | 191 | 在上一小节,我们看到了Harris角点检测。1994年晚些时候,J.Shi和C.Tomasi在他们的论文《Good Features to Track》中做了一个小修改,与Harris角点检测相比显示出更好的结果。Harris角点探测器的评分功能由下式给出: 192 | 193 | $$R = \lambda_1 \lambda_2 - k(\lambda_1+\lambda_2)^2$$ 194 | 195 | 除此之外,Shi-Tomasi提出: 196 | 197 | $$R = min(\lambda_1, \lambda_2)$$ 198 | 199 | 如果它大于阈值,则将其视为拐角。如果我们像在Harris角点检测器中那样在$\lambda_1 - \lambda_2$空间中绘制它,我们得到如下图像: 200 | 201 | ![image6](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image6.jpg) 202 | 203 | 从图中可以看出,只有当$\lambda_1$和$\lambda_2$高于最小值λmin时,它才被视为一个角(绿色区域)。 204 | 205 | ### 2、代码实现 206 | 207 | OpenCV有一个函数cv.goodFeaturesToTrack()。 它通过Shi-Tomasi方法(或Harris角点检测,如果你指定它)在图像中找到N个最强角。像往常一样,图像应该是灰度图像。然后指定要查找的角点数。然后指定质量等级,该等级是0-1之间的值,表示低于每个人被拒绝的角点的最低质量。然后我们提供检测到的角之间的最小欧氏距离。 208 | 209 | 利用所有这些信息,该函数可以在图像中找到角点。低于质量水平的所有角点都被拒绝。然后它根据质量按降序对剩余的角进行排序。然后功能占据第一个最强的角点,抛弃最小距离范围内的所有角点并返回N个最强的角点。 210 | 211 | 在下面的示例中,我们将尝试找到25个最佳角点: 212 | 213 | ```python 214 | import numpy as np 215 | import cv2 as cv 216 | from matplotlib import pyplot as plt 217 | 218 | img = cv.imread('blox.jpg') 219 | gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 220 | 221 | corners = cv.goodFeaturesToTrack(gray,25,0.01,10) 222 | corners = np.int0(corners) 223 | 224 | for i in corners: 225 | x,y = i.ravel() 226 | cv.circle(img,(x,y),3,255,-1) 227 | 228 | plt.imshow(img),plt.show() 229 | ``` 230 | 231 | 结果如下图所示: 232 | 233 | ![image7](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image7.jpg) 234 | 235 | 我们以后会发现这个函数很适合在目标跟踪中使用。 236 | 237 | ## 四、介绍SIFT(Scale-Invariant Feature Trans-form) 238 | 239 | *** 240 | 241 | ### 目标: 242 | 243 | 本章节你需要学习以下内容: 244 | 245 | *我们将了解SIFT算法的概念 246 | *我们将学习如何找到SIFT关键点和描述符。 247 | 248 | ### 1、理论 249 | 250 | 在上一小节中,我们看到了一些角点探测器,如Harris角点探测器等。它们具有旋转不变的特性,这意味着,即使图像旋转,我们也可以找到相同的角点。很明显,因为角落在旋转的图像中也是角点。但是缩放呢?如果缩放图像,则角点可能不是角点。例如,检查下面的简单图像。当在同一窗口中放大时,小窗口内的小图像中的角是平坦的。所以Harris的角点不是规模不变的。 251 | 252 | ![image8](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image8.jpg) 253 | 254 | 因此,2004年,不列颠哥伦比亚大学D.Lowe在他的论文中提出了一种新的算法,尺度不变特征变换(SIFT),从尺度不变关键点的独特图像特征,提取关键点并计算其描述符。(本文易于理解并被认为是SIFT上最好的材料。所以这个解释只是本文的简短摘要)。 255 | 256 | SIFT算法主要涉及四个步骤。我们将逐一看到它们。 257 | 258 | #### (1)尺度空间极值检测 259 | 260 | 从上图我们可以很明显的看出来在不同的尺度空间不能使用相同的窗口检测极值点。对小的角点要用小的窗口,对大的角点只能使用大的窗口。为了达到这个目的我们要使用尺度空间滤波器。(尺度空间滤波器可以使用一些列具有不同方差$\sigma$的高斯卷积核构成)。使用具有不同方差值$\sigma$的高斯拉普拉斯算子(LoG)对图像进行卷积,LoG 由于具有不同的方差值$\sigma$所以可以用来检测不同大小的斑点(当 LoG 的方差$\sigma$与斑点直径相等时能够使斑点完全平滑)。简单来说方差$\sigma$就是一个尺度变换因子。例如,上图中使用一个小方差$\sigma$的高斯卷积核是可以很好的检测出小的角点,而使用大方差$\sigma$的高斯卷积核时可以很好的检测除大的角点。所以我们可以在尺度空间和二维平面中检测到局部最大值,如$(x,y,\sigma)$, 这表示在$\sigma$尺度中$(x,y)$点可能是一个关键点。(高斯方差的大小与窗口的大小存在一个倍数关系:窗口大小等于 6 倍方差加 1,所以方差的大小也决定了窗口大小) 261 | 262 | 但是这个 LoG 的计算量非常大,所以 SIFT 算法使用高斯差分算子(DoG)来对 LoG 做近似。这里需要再解释一下图像金字塔,我们可以通过减少采样(如只取奇数行或奇数列)来构成一组图像尺寸(1,0.5,0.25 等)不同的金字塔,然后对这一组图像中的每一张图像使用具有不同方差$\sigma$的高斯卷积核构建出具有不同分辨率的图像金字塔(不同的尺度空间)。DoG 就是这组具有不同分辨率的图像金字塔中相邻的两层之间的差值。如下图所示: 263 | 264 | ![image9](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image9.jpg) 265 | 266 | 在 DoG 搞定之后,就可以在不同的尺度空间和 2D 平面中搜索局部最大值了。对于图像中的一个像素点而言,它需要与自己周围的 8 邻域,以及尺度空间中上下两层中的相邻的 18(2x9)个点相比。如果是局部最大值,它就可能是一个关键点。基本上来说关键点是图像在相应尺度空间中的最好代表。如下图所示: 267 | 268 | ![image10](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image10.jpg) 269 | 270 | 该算法的作者在文章中给出了 SIFT 参数的经验值:octaves=4(通过降低采样从而减小图像尺寸,构成尺寸减小的图像金字塔,尺度空间为 5,也就是每个尺寸使用 5 个不同方差的高斯核进行卷积,初始方差是 1.6,$\sigma=1.6$,$k=\sqrt{2}$等作为最优值。 271 | 272 | #### (2)关键点(极值点)定位 273 | 274 | 一旦找到关键点,我们就要对它们进行修正从而得到更准确的结果。可以使用尺度空间的泰勒级数展开来获得极值的准确位置,如果极值点的灰度值小于阈值(0.03)就会被忽略掉。在 OpenCV 中这种阈值被称为contrastThreshold。 275 | 276 | DoG 算法对边界非常敏感,所以我们必须要把边界去除。前面我们讲的Harris 算法除了可以用于角点检测之外还可以用于检测边界。作者就是使用了同样的思路。作者使用 2x2 的 Hessian 矩阵计算主曲率。从 Harris 角点检测的算法中,我们知道当一个特征值远远大于另外一个特征值时检测到的是边界。 277 | 278 | 所以他们使用了一个简单的函数,如果比例高于阈值(OpenCV 中称为边界阈值),这个关键点就会被忽略。文章中给出的边界阈值为 10。 279 | 280 | 所以低对比度的关键点和边界关键点都会被去除掉,剩下的就是我们感兴趣的关键点了。 281 | 282 | #### (3)为关键点(极值点)指定方向参数 283 | 284 | 现在我们要为每一个关键点赋予一个反向参数,这样它才会具有旋转不变性。获取关键点(所在尺度空间)的邻域,然后计算这个区域的梯度级和方向。根据计算得到的结果创建一个含有 36 个 bins(每 10 度一个 bin)的方向直方图。(使用当前尺度空间$\sigma$值的 1.5 倍为方差的圆形高斯窗口和梯度级做权重)。直方图中的峰值为主方向参数,如果其他的任何柱子的高度高于峰值的80% 被认为是辅方向。这就会在相同的尺度空间相同的位置构建除具有不同方向的关键点。这对于匹配的稳定性会有所帮助。 285 | 286 | #### (4)关键点描述符 287 | 288 | 新的关键点描述符被创建了。选取与关键点周围一个 16x16 的邻域,把它分成 16 个 4x4 的小方块,为每个小方块创建一个具有 8 个 bin 的方向直方图。总共加起来有 128 个 bin。由此组成长为 128 的向量就构成了关键点描述符。除此之外还要进行几个测量以达到对光照变化,旋转等的稳定性。 289 | 290 | #### (5)关键点匹配 291 | 292 | 下一步就可以采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。取第一个图的某个关键点,通过遍历找到第二幅图像中的距离最近的那个关键点。但有些情况下,第二个距离最近的关键点与第一个距离最近的关键点靠的太近。这可能是由于噪声等引起的。此时要计算最近距离与第二近距离的比值。如果比值大于 0.8,就忽略掉。这会去除 90% 的错误匹配,同时只去除 5% 的正确匹配。如文章所说。 293 | 这就是 SIFT 算法的摘要。非常推荐你阅读原始文献,这会加深你对算法的理解。请记住这个算法是受专利保护的。所以这个算法包含在 OpenCV 中的收费模块中。 294 | 295 | ### 2、OpenCV中的SIFT 296 | 297 | 现在让我们来看看 OpenCV 中关于 SIFT 的函数吧。让我们从关键点检测和绘制开始吧。首先我们要创建对象。我们可以使用不同的参数,这并不是必须的,关于参数的解释可以查看文档。 298 | 299 | ```python 300 | import numpy as np 301 | import cv2 as cv 302 | 303 | img = cv.imread('home.jpg') 304 | gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY) 305 | 306 | sift = cv.xfeatures2d.SIFT_create() 307 | kp = sift.detect(gray,None) 308 | 309 | img=cv.drawKeypoints(gray,kp,img) 310 | 311 | cv.imwrite('sift_keypoints.jpg',img) 312 | ``` 313 | 314 | 函数 sift.detect() 可以在图像中找到关键点。如果你只想在图像中的一个区域搜索的话,也可以创建一个掩模图像作为参数使用。返回的关键点是一个带有很多不同属性的特殊结构体,这些属性中包含它的坐标(x,y),有意义的邻域大小,确定其方向的角度、指定关键点强度的响应等。 315 | 316 | OpenCV也提供了绘制关键点的函数:cv2.drawKeyPoints(),它可以在关键点的部位绘制一个小圆圈。如果你设置参数为cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,就会绘制代表关键点大小的圆圈甚至可以绘制除关键点的方向。见下面的例子。 317 | 318 | ```python 319 | img=cv.drawKeypoints(gray,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 320 | cv.imwrite('sift_keypoints.jpg',img) 321 | ``` 322 | 323 | 结果如下图所示: 324 | 325 | ![image11](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image11.jpg) 326 | 327 | 现在要计算描述符,OpenCV提供了两种方法。 328 | 329 | 1. 由于你已经找到了关键点,因此可以调用sift.compute()来计算我们找到的关键点的描述符。例如:kp,des = sift.compute(灰色,kp) 330 | 2. 如果你没有找到关键点,请使用函数sift.detectAndCompute()在一个步骤中直接查找关键点和描述符。 331 | 332 | 我们将看到第二种方法: 333 | 334 | ```python 335 | sift = cv.xfeatures2d.SIFT_create() 336 | kp, des = sift.detectAndCompute(gray,None) 337 | ``` 338 | 339 | 这里kp是关键点列表,des是形状为$Number\_of\_Keypoints \times 128$的numpy数组。 340 | 341 | 所以我们得到了关键点,描述符等。现在我们想看看如何匹配不同图像中的关键点。 我们将在接下来的章节中学习。 342 | 343 | ## 五、介绍SURF(Speeded-Up Robust Features) 344 | 345 | *** 346 | 347 | ### 目标: 348 | 349 | 本章节你需要学习以下内容: 350 | 351 | *我们将看到SURF的基础知识 352 | *我们将在OpenCV中看到SURF功能 353 | 354 | ### 1、理论 355 | 356 | 在上一节中我们学习了使用 SIFT 算法进行关键点检测和描述。但是这种算法的执行速度比较慢,人们需要速度更快的算法。在 2006 年Bay,H.,Tuytelaars,T. 和 Van Gool,L 共同提出了 SURF(加速稳健特征)算法。跟它的名字一样,这是个算法是加速版的 SIFT。 357 | 358 | 在 SIFT 中,Lowe 在构建尺度空间时使用 DoG 对 LoG 进行近似。SURF则更进一步,使用盒子滤波器(box_filter)对 LoG 进行近似。下图显示了这种近似。在进行卷积计算时可以利用积分图 像(积分图像的一大特点是:计算图像中某个窗口内所有像素和时,计算量的大小与窗口大小无关),是盒子滤波器的一大优点。而且这种计算可以在不同尺度空间同时进行。同样 SURF 算法计算关键点的尺度和位置是也是依赖与 Hessian 矩阵行列式的。 359 | 360 | ![image12](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image12.jpg) 361 | 362 | 为了保证特征矢量具有选装不变形,需要对于每一个特征点分配一个主要方向。需要以特征点为中心,以 6s(s 为特征点的尺度)为半径的圆形区域内,对图像进行 Harr 小波相应运算。这样做实际就是对图像进行梯度运算,但是利用积分图像,可以提高计算图像梯度的效率,为了求取主方向值,需哟啊设计一个以方向为中心,张角为 60 度的扇形滑动窗口,以步长为 0.2 弧度左右旋转这个滑动窗口,并对窗口内的图像 Haar 小波的响应值进行累加。主方向为最大的 Haar 响应累加值对应的方向。在很多应用中根本就不需要旋转不变性,所以没有必要确定它们的方向,如果不计算方向的话,又可以使算法提速。SURF 提供了成为 U-SURF 的功能,它具有更快的速度,同时保持了对$\pm 15^{\circ}$旋转的稳定性。OpenCV 对这两种模式同样支持,只需要对参数upright 进行设置,当 upright 为 0 时计算方向,为 1 时不计算方向,同时速度更快。 363 | 364 | ![image13](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image13.jpg) 365 | 366 | 生成特征点的特征矢量需要计算图像的 Haar 小波响应。在一个矩形的区域内,以特征点为中心,沿主方向将 20s * 20s 的图像划分成 4 * 4 个子块,每个子块利用尺寸 2s 的 Haar 小波模版进行响应计算,然后对响应值进行统计,组成向量$v=( \sum{d_x}, \sum{d_y}, \sum{|d_x|}, \sum{|d_y|})$。这个描述符的长度为 64。降低的维度可以加速计算和匹配,但又能提供更容易区分的特征。 367 | 368 | 为了增加特征点的独特性,SURF 还提供了一个加强版 128 维的特征描述符。当$d_y>0$和$d_y<0$时分别对$d_x$和$|d_x|$的和进行计算,计算$d_y$和$|d_x|$时也进行区分,这样获得特征就会加倍,但又不会增加计算的复杂度。OpenCV 同样提供了这种功能,当参数 extended 设置为 1 时为 128 维,当参数为 0 时为 64 维,默认情况为 128 维。 369 | 370 | 另一个重要的改进是使用拉普拉斯算子(Hessian矩阵的迹线)作为潜在兴趣点。它不会增加计算成本,因为它已经在检测期间计算出来。拉普拉斯的标志将黑暗背景上的明亮斑点与相反情况区分开来。在匹配阶段,我们只比较具有相同类型对比度的特征(如下图所示)。这种最小的信息允许更快的匹配,而不会降低描述符的性能。 371 | 372 | ![image14](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image14.jpg) 373 | 374 | 简单来说 SURF 算法采用了很多方法来对每一步进行优化从而提高速度。分析显示在结果效果相当的情况下 SURF 的速度是 SIFT 的 3 倍。SURF 善于处理具有模糊和旋转的图像,但是不善于处理视角变化和关照变化。 375 | 376 | ### 2、OpenCV中的SURF 377 | 378 | OpenCV就像SIFT一样提供SURF功能。首先使用一些可选条件(如64/128-dim描述符,Upright/Normal SURF等)初始化一个SURF对象。所有详细信息都在文档中进行了详细说明。然后就像我们在SIFT中所做的那样,我们可以使用SURF.detect(),SURF.compute()等来查找关键点和描述符。 379 | 380 | 首先,我们将看到一个关于如何查找SURF关键点和描述符并绘制它的简单演示。所有示例都显示在Python终端中,因为它只与SIFT相同 381 | 382 | ```python 383 | >>> img = cv.imread('fly.png',0) 384 | 385 | # Create SURF object. You can specify params here or later. 386 | # Here I set Hessian Threshold to 400 387 | >>> surf = cv.xfeatures2d.SURF_create(400) 388 | 389 | # Find keypoints and descriptors directly 390 | >>> kp, des = surf.detectAndCompute(img,None) 391 | 392 | >>> len(kp) 393 | 699 394 | ``` 395 | 396 | 1199个关键点太多,无法在图片中显示。我们将它减少到大约50以将其绘制在图像上。在匹配时,我们可能需要所有这些功能,但现在不需要。所以我们增加了Hessian阈值。 397 | 398 | ```python 399 | # Check present Hessian threshold 400 | >>> print( surf.getHessianThreshold() ) 401 | 400.0 402 | 403 | # We set it to some 50000. Remember, it is just for representing in picture. 404 | # In actual cases, it is better to have a value 300-500 405 | >>> surf.setHessianThreshold(50000) 406 | 407 | # Again compute keypoints and check its number. 408 | >>> kp, des = surf.detectAndCompute(img,None) 409 | 410 | >>> print( len(kp) ) 411 | 47 412 | ``` 413 | 414 | 现在小于50了。让我们在图像上绘制它。 415 | 416 | ```python 417 | >>> img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4) 418 | >>> plt.imshow(img2),plt.show() 419 | ``` 420 | 421 | 请参阅下面的结果。你可以看到SURF更像是斑点探测器。它可以探测到蝴蝶翅膀上的白色斑点。你可以使用其他图像进行测试。 422 | 423 | ![image15](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image15.jpg) 424 | 425 | 现在我们尝试一下U-SURF,它不会检测关键点的方向。 426 | 427 | ```python 428 | # Check upright flag, if it False, set it to True 429 | >>> print( surf.getUpright() ) 430 | False 431 | 432 | >>> surf.setUpright(True) 433 | 434 | # Recompute the feature points and draw it 435 | >>> kp = surf.detect(img,None) 436 | >>> img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4) 437 | 438 | >>> plt.imshow(img2),plt.show() 439 | ``` 440 | 441 | 结果如下。所有的关键点的朝向都是一致的。它比前面的快很多。如果你的工作对关键点的朝向没有特别的要求(如全景图拼接)等,这种方法会更快。 442 | 443 | ![image16](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image16.jpg) 444 | 445 | 最后,我们检查描述符大小,如果它只有64-dim,则将其更改为128。 446 | 447 | ```python 448 | # Find size of descriptor 449 | >>> print( surf.descriptorSize() ) 450 | 64 451 | 452 | # That means flag, "extended" is False. 453 | >>> surf.getExtended() 454 | False 455 | 456 | # So we make it to True to get 128-dim descriptors. 457 | >>> surf.setExtended(True) 458 | >>> kp, des = surf.detectAndCompute(img,None) 459 | >>> print( surf.descriptorSize() ) 460 | 128 461 | >>> print( des.shape ) 462 | (47, 128) 463 | ``` 464 | 465 | 接下来要做的就是匹配了,我们会在后面讨论。 466 | 467 | ## 六、角点检测的FAST算法 468 | 469 | *** 470 | 471 | ### 目标: 472 | 473 | 本章节你需要学习以下内容: 474 | 475 | *我们将了解FAST算法的基础知识 476 | *我们将使用OpenCV功能为FAST算法找到角点 477 | 478 | ### 1、理论 479 | 480 | 我们看到了几个特征探测器,其中很多都非常好用。但从实时应用程序的角度来看,它们还不够快。一个最好的例子是具有有限计算资源的SLAM(同步构建与地图定位)移动机器人。 481 | 482 | 为了解决这个问题,Edward Rosten 和 Tom Drummond 在 2006 年提出里 FAST 算法。我们下面将会对此算法进行一个简单的介绍。你可以参考原始文献获得更多细节(本节中的所有图像都是曲子原始文章)。 483 | 484 | #### (1)使用 FAST 算法进行特征提取 485 | 486 | 1. 在图像中选取一个像素点 p,来判断它是不是关键点。$I_p$等于像素点 p的灰度值。 487 | 488 | 2. 选择适当的阈值 t。 489 | 490 | 3. 如下图所示在像素点 p 的周围选择 16 个像素点进行测试。 491 | 492 | ![image17](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image17.jpg) 493 | 494 | 4. 如果在这 16 个像素点中存在 n 个连续像素点的灰度值都高于$I_p + t$,或者低于$I_p - t$,那么像素点 p 就被认为是一个角点。如上图中的虚线所示,n 选取的值为 12。 495 | 496 | 5. 为了获得更快的效果,还采用了而外的加速办法。首先对候选点的周围每个 90 度的点:1,9,5,13 进行测试(先测试 1 和 19, 如果它们符合阈值要求再测试 5 和 13)。如果 p 是角点,那么这四个点中至少有 3 个要符合阈值要求。如果不是的话肯定不是角点,就放弃。对通过这步测试的点再继续进行测试(是否有 12 的点符合阈值要求)。这个检测器的效率很高,但是它有如下几条缺点: 497 | 498 | * 当 n<12 时它不会丢弃很多候选点 (获得的候选点比较多)。 499 | * 像素的选取不是最优的,因为它的效果取决与要解决的问题和角点的分布情况。 500 | * 高速测试的结果被抛弃 501 | * 检测到的很多特征点都是连在一起的 502 | 503 | 前 3 个问题可以通过机器学习的方法解决,最后一个问题可以使用非最大值抑制的方法解决。 504 | 505 | #### (2)机器学习的角点检测器 506 | 507 | 1. 选择一组训练图片(最好是跟最后应用相关的图片) 508 | 509 | 2. 使用 FAST 算法找出每幅图像的特征点 510 | 511 | 3. 对每一个特征点,将其周围的 16 个像素存储构成一个向量。对所有图像都这样做构建一个特征向量 P 512 | 513 | 4. 每一个特征点的 16 像素点都属于下列三类中的一种。 514 | 515 | ![image18](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image18.jpg) 516 | 517 | 5. 根据这些像素点的分类,特征向量 P 也被分为 3 个子集:P d ,P s ,P b 518 | 519 | 6. 定义一个新的布尔变量$K_p$,如果 p 是角点就设置为 Ture,如果不是就设置为 False。 520 | 521 | 7. 使用 ID3 算法(决策树分类器)使用变量$K_p$查询每个子集,以获得有关真实类的知识。它选择x,其产生关于候选像素是否是拐角的最多信息,通过$K_p$的熵测量。 522 | 523 | 8. 这递归地应用于所有子集,直到其熵为零。 524 | 525 | 9. 将构建好的决策树运用于其他图像的快速的检测。 526 | 527 | #### (3)非极大值抑制 528 | 529 | 使用极大值抑制的方法可以解决检测到的特征点相连的问题 530 | 531 | 1. 对所有检测到到特征点构建一个打分函数 V。V 就是像素点 p 与周围 16个像素点差值的绝对值之和。 532 | 533 | 2. 计算临近两个特征点的打分函数 V。 534 | 535 | 3. 忽略 V 值最低的特征点 536 | 537 | #### (4)总结 538 | 539 | FAST 算法比其它角点检测算法都快。但是在噪声很高时不够稳定,这是由阈值决定的。 540 | 541 | ### 2、OpenCV中的FAST特征检测器 542 | 543 | 它被称为OpenCV中的任何其他特征检测器。如果需要,你可以指定阈值,是否应用非最大抑制,要使用的邻域等。 544 | 545 | 对于邻域,定义了三个标志,cv.FAST_FEATURE_DETECTOR_TYPE_5_8,cv.FAST_FEATURE_DETECTOR_TYPE_7_12和cv.FAST_FEATURE_DETECTOR_TYPE_9_16。下面是一个关于如何检测和绘制FAST特征点的简单代码。 546 | 547 | ```python 548 | import numpy as np 549 | import cv2 as cv 550 | from matplotlib import pyplot as plt 551 | 552 | img = cv.imread('simple.jpg',0) 553 | 554 | # Initiate FAST object with default values 555 | fast = cv.FastFeatureDetector_create() 556 | 557 | # find and draw the keypoints 558 | kp = fast.detect(img,None) 559 | img2 = cv.drawKeypoints(img, kp, None, color=(255,0,0)) 560 | 561 | # Print all default params 562 | print( "Threshold: {}".format(fast.getThreshold()) ) 563 | print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) ) 564 | print( "neighborhood: {}".format(fast.getType()) ) 565 | print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) ) 566 | 567 | cv.imwrite('fast_true.png',img2) 568 | 569 | # Disable nonmaxSuppression 570 | fast.setNonmaxSuppression(0) 571 | kp = fast.detect(img,None) 572 | 573 | print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) ) 574 | 575 | img3 = cv.drawKeypoints(img, kp, None, color=(255,0,0)) 576 | 577 | cv.imwrite('fast_false.png',img3) 578 | ``` 579 | 580 | 结果如下图所示。第一张图片显示fAST with nonmaxSuppression,第二张图片显示没有nonmaxSuppression: 581 | 582 | ![image19](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image19.jpg) 583 | 584 | ## 七、BRIEF(Binary Robust Independent Elementary Features) 585 | 586 | *** 587 | 588 | ### 目标: 589 | 590 | 本章节你需要学习以下内容: 591 | 592 | *我们将看到BRIEF算法的基础知识 593 | 594 | ### 1、理论 595 | 596 | 我们知道 SIFT 算法使用的是 128 维向量作为描述符。由于它是使用的浮点数,所以要使用 512 个字节。同样 SURF 算法最少使用 256 个字节(64 维描述符)。创建一个包含上千个特征的向量需要消耗大量的内存,在嵌入式等资源有限的设备上这样是不可行的。匹配时还会消耗更多的内存和时间。 597 | 598 | 但是在实际的匹配过程中如此多的维度是没有必要的。我们可以使用 PCA,LDA 等方法来进行降维。甚至可以使用 LSH(局部敏感哈希)将 SIFT 浮点数的描述符转换成二进制字符串。对这些字符串再使用汉明距离进行匹配。汉明距离的计算只需要进行 XOR 位运算以及位计数,这种计算很适合在现代的CPU 上进行。但我们还是要先找到描述符才能使用哈希,这不能解决最初的内存消耗问题。 599 | 600 | BRIEF 应运而生。它不去计算描述符而是直接找到一个二进制字符串。这种算法使用的是已经平滑后的图像,它会按照一种特定的方式选取一组像素点对 $n_d$(x,y),然后在这些像素点对之间进行灰度值对比。例如,第一个点对的灰度值分别为 p 和 q。如果 p 小于 q,结果就是 1,否则就是 0。就这样对 n d个点对进行对比得到一个$n_d$维的二进制字符串。 601 | 602 | n d 可以是 128,256,512。OpenCV 对这些都提供了支持,但在默认情况下是 256(OpenC 是使用字节表示它们的,所以这些值分别对应与 16,32,64)。当我们获得这些二进制字符串之后就可以使用汉明距离对它们进行匹配了。 603 | 604 | 非常重要的一点是:BRIEF 是一种特征描述符,它不提供查找特征的方法。所以我们不得不使用其他特征检测器,比如 SIFT 和 SURF 等。原始文献推荐使用 CenSurE 特征检测器,这种算法很快。而且 BRIEF 算法对 CenSurE关键点的描述效果要比 SURF 关键点的描述更好。 605 | 简单来说 BRIEF 是一种对特征点描述符计算和匹配的快速方法。这种算法可以实现很高的识别率,除非出现平面内的大旋转。 606 | 607 | ### 2、OpenCV中的BRIEF 608 | 609 | 下面的代码显示了在CenSurE检测器的帮助下计算BRIEF描述符。(CenSurE探测器在OpenCV中称为STAR探测器) 610 | 611 | 请注意,你需要opencv contrib才能使用它。 612 | 613 | ```python 614 | import numpy as np 615 | import cv2 as cv 616 | from matplotlib import pyplot as plt 617 | 618 | img = cv.imread('simple.jpg',0) 619 | 620 | # Initiate FAST detector 621 | star = cv.xfeatures2d.StarDetector_create() 622 | 623 | # Initiate BRIEF extractor 624 | brief = cv.xfeatures2d.BriefDescriptorExtractor_create() 625 | 626 | # find the keypoints with STAR 627 | kp = star.detect(img,None) 628 | 629 | # compute the descriptors with BRIEF 630 | kp, des = brief.compute(img, kp) 631 | 632 | print( brief.descriptorSize() ) 633 | print( des.shape ) 634 | ``` 635 | 636 | 函数brief.getDescriptorSize()给出了以字节为单位的$n_d$大小。默认情况下为32。下一个是匹配,这将在另一章中完成。 637 | 638 | ## 八、ORB (Oriented FAST and Rotated BRIEF) 639 | 640 | *** 641 | 642 | ### 目标: 643 | 644 | 本章节你需要学习以下内容: 645 | 646 | *我们将看到ORB算法的基础知识 647 | 648 | ### 1、理论 649 | 650 | 作为OpenCV爱好者,关于ORB最重要的是它来自“OpenCV Labs”。这个算法由Ethan Rublee,Vincent Rabaud,Kurt Konolige和Gary R. Bradski在他们的论文ORB中提出:2011年是SIFT或SURF的有效替代方案。如标题所述,它是计算中SIFT和SURF的一个很好的替代方案。成本,匹配性能和主要是专利。是的,SIFT和SURF已获得专利,你应该支付它们的使用费用。但ORB不是!!! 651 | 652 | ORB基本上是FAST关键点检测器和Brief描述符的融合,具有许多修改以增强性能。首先,它使用FAST查找关键点,然后应用Harris角点测量来查找其中的前N个点。它还使用金字塔来生成多尺度特征。但有一个问题是,FAST不计算方向。那么旋转不变性呢?作者提出了以下修改。 653 | 654 | 它计算贴片的强度加权质心,位于中心的角落。从该角点到质心的矢量方向给出了方向。为了改善旋转不变性,用x和y计算矩,该x和y应该在半径为r的圆形区域中,其中r是贴片的大小。 655 | 656 | 现在对于描述符,ORB使用简要描述符。但我们已经看到,Brief在轮换方面表现不佳。因此,ORB所做的是根据关键点的方向“引导”Brief。对于位置$(x_i, y_i)$处的n个二进制测试的任何特征集,定义2×n矩阵,其包含这些像素的坐标。然后使用贴片的方向$\theta$,找到其旋转矩阵并旋转S以获得转向(旋转)版本$S_\theta$。 657 | 658 | ORB将角度离散为$2 \pi /30$(12度)的增量,并构建预先计算的简要模式的查找表。只要关键点方向θ在视图之间是一致的,将使用正确的点集$S_\theta$来计算其描述符。 659 | 660 | BRIEF具有一个重要特性,即每个位特征具有较大的方差,平均值接近0.5。但是一旦它沿着关键点方向定向,它就会失去这个属性并变得更加分散。高差异使得特征更具辨别力,因为它对输入有不同的响应。另一个理想的特性是使测试不相关,因为每次测试都会对结果产生影响。为了解决所有这些问题,ORB在所有可能的二进制测试中运行一个贪婪的搜索,以找到具有高方差和意味着接近0.5的那些,以及不相关的。结果称为rBRIEF。 661 | 662 | 对于描述符匹配,使用改进传统LSH的多探测LSH。该论文称ORB比SURF快得多,SIFT和ORB描述符比SURF更好。ORB是用于全景拼接等的低功率设备的不错选择。 663 | 664 | ### 2、OpenCV中的ORB 665 | 666 | 像往常一样,我们必须使用函数cv.ORB()或使用feature2d公共接口创建一个ORB对象。它有许多可选参数。最有用的是nFeatures,表示要保留的最大要素数量(默认为500),scoreType表示Harris得分或FAST得分是否对要素进行排名(默认情况下为Harris得分)等。另一个参数WTA_K决定点数 生成面向简要描述符的每个元素。 默认情况下它是2,即一次选择两个点。在这种情况下,为了匹配,使用NORM_HAMMING距离。如果WTA_K为3或4,需要3或4个点来产生BRIEF描述符,则匹配距离由NORM_HAMMING2定义。 667 | 668 | 下面是一个简单的代码,显示了ORB的用法。 669 | 670 | ```python 671 | import numpy as np 672 | import cv2 as cv 673 | from matplotlib import pyplot as plt 674 | 675 | img = cv.imread('simple.jpg',0) 676 | 677 | # Initiate ORB detector 678 | orb = cv.ORB_create() 679 | 680 | # find the keypoints with ORB 681 | kp = orb.detect(img,None) 682 | 683 | # compute the descriptors with ORB 684 | kp, des = orb.compute(img, kp) 685 | 686 | # draw only keypoints location,not size and orientation 687 | img2 = cv.drawKeypoints(img, kp, None, color=(0,255,0), flags=0) 688 | plt.imshow(img2), plt.show() 689 | ``` 690 | 691 | 结果如下图所示: 692 | 693 | ![image20](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image20.jpg) 694 | 695 | ORB功能匹配,我们将在另一章中讲解。 696 | 697 | ## 九、特征匹配 698 | 699 | *** 700 | 701 | ### 目标: 702 | 703 | 本章节你需要学习以下内容: 704 | 705 | *我们将要学习在图像间进行特征匹配 706 | *使用 OpenCV 中的蛮力(Brute-Force)匹配和 FLANN 匹配 707 | 708 | ### 1、蛮力(Brute-Force)匹配基础 709 | 710 | 蛮力匹配器很简单。首先在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行(描述符)距离测试,最后返回距离最近的关键点。 711 | 712 | 对于BF匹配器,首先我们必须使用cv.BFMatcher()创建一个BFMatcher对象。它需要两个可选的参数,第一个是normType,它指定要使用的距离测量,默认情况下,它是cv.NORM_L2,它适用于SIFT,SURF等(cv.NORM_L1也在那里)。对于基于二进制字符串的描述符,如ORB,BRIEF,BRISK等,应使用cv.NORM_HAMMING,它使用汉明距离作为度量。如果ORB使用WTA_K==3或4,则应使用cv.NORM_HAMMING2。 713 | 714 | 第二个参数是布尔变量crossCheck,默认为false。如果为真,则Matcher仅返回具有值(i,j)的那些匹配,使得集合A中的第i个描述符具有集合B中的第j个描述符作为最佳匹配,反之亦然。也就是说,两组中的两个特征应该相互匹配。它提供了一致的结果,是D.Lowe在SIFT论文中提出的比率测试的一个很好的替代方案。 715 | 716 | 一旦创建,两个重要的方法是BFMatcher.match()和BFMatcher.knnMatch()。第一个返回最佳匹配。第二种方法返回k个最佳匹配,其中k由用户指定。当我们需要做更多的工作时,它可能是有用的。 717 | 718 | 就像我们使用cv.drawKeypoints()来绘制关键点一样,cv.drawMatches()帮助我们绘制匹配项。它水平堆叠两个图像,并从第一个图像到第二个图像绘制线条,显示最佳匹配。还有cv.drawMatchesKnn,它绘制了所有k个最佳匹配。如果k = 2,它将为每个关键点绘制两条匹配线。因此,如果我们想要有选择地绘制它,我们必须传递一个掩码。 719 | 720 | 让我们看一下每个SURF和ORB的一个例子(两者都使用不同的距离测量)。 721 | 722 | #### (1)与ORB描述符的强力匹配 723 | 724 | 在这里,我们将看到一个关于如何匹配两个图像之间的特征的简单示例。在这种情况下,我有一个查询图像和一个目标图像。我们将尝试使用特征匹配在目标图像中查找查询图像。(图片为/samples/c/box.png和/samples/c/box_in_scene.png) 725 | 726 | 我们使用ORB描述符来匹配功能。所以让我们从加载图像,查找描述符等开始。 727 | 728 | ```python 729 | import numpy as np 730 | import cv2 as cv 731 | import matplotlib.pyplot as plt 732 | 733 | img1 = cv.imread('box.png',0) # queryImage 734 | img2 = cv.imread('box_in_scene.png',0) # trainImage 735 | 736 | # Initiate ORB detector 737 | orb = cv.ORB_create() 738 | 739 | # find the keypoints and descriptors with ORB 740 | kp1, des1 = orb.detectAndCompute(img1,None) 741 | kp2, des2 = orb.detectAndCompute(img2,None) 742 | ``` 743 | 744 | 接下来,我们使用距离测量cv.NORM_HAMMING创建一个BFMatcher对象(因为我们使用的是ORB),并且启用了crossCheck以获得更好的结果。然后我们使用Matcher.match()方法在两个图像中获得最佳匹配。我们按照距离的升序对它们进行排序,以便最佳匹配(低距离)出现在前面。然后我们只绘制前10场比赛(太多了看不清,如果愿意的话你可以多画几条) 745 | 746 | ```python 747 | # create BFMatcher object 748 | bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True) 749 | 750 | # Match descriptors. 751 | matches = bf.match(des1,des2) 752 | 753 | # Sort them in the order of their distance. 754 | matches = sorted(matches, key = lambda x:x.distance) 755 | 756 | # Draw first 10 matches. 757 | img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2) 758 | 759 | plt.imshow(img3),plt.show() 760 | ``` 761 | 762 | 结果如下图所示: 763 | 764 | ![image21](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image21.jpg) 765 | 766 | #### (2)这个Matcher对象是什么? 767 | 768 | matches = bf.match(des1,des2)行的结果是DMatch对象的列表。此DMatch对象具有以下属性: 769 | 770 | * DMatch.distance - 描述符之间的距离。越低越好。 771 | * DMatch.trainIdx - 列车描述符中描述符的索引 772 | * DMatch.queryIdx - 查询描述符中描述符的索引 773 | * DMatch.imgIdx - 火车图像的索引。 774 | 775 | #### (3)对 SIFT 描述符进行蛮力匹配和比值测试 776 | 777 | 这一次,我们将使用BFMatcher.knnMatch()来获得最佳匹配。在这个例子中,我们将采用k = 2,以便我们可以在他的论文中应用D.Lowe解释的比率测试。 778 | 779 | ```python 780 | import numpy as np 781 | import cv2 as cv 782 | from matplotlib import pyplot as plt 783 | 784 | img1 = cv.imread('box.png',0) # queryImage 785 | img2 = cv.imread('box_in_scene.png',0) # trainImage 786 | 787 | # Initiate SIFT detector 788 | sift = cv.SIFT() 789 | 790 | # find the keypoints and descriptors with SIFT 791 | kp1, des1 = sift.detectAndCompute(img1,None) 792 | kp2, des2 = sift.detectAndCompute(img2,None) 793 | 794 | # BFMatcher with default params 795 | bf = cv.BFMatcher() 796 | matches = bf.knnMatch(des1,des2, k=2) 797 | 798 | # Apply ratio test 799 | good = [] 800 | for m,n in matches: 801 | if m.distance < 0.75*n.distance: 802 | good.append([m]) 803 | 804 | # cv.drawMatchesKnn expects list of lists as matches. 805 | img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2) 806 | 807 | plt.imshow(img3),plt.show() 808 | ``` 809 | 810 | 结果如下图所示: 811 | 812 | ![image22](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image22.jpg) 813 | 814 | ### 2、FLANN匹配 815 | 816 | FLANN 是快速最近邻搜索包(Fast_Library_for_Approximate_Nearest_Neighbors)的简称。它是一个对大数据集和高维特征进行最近邻搜索的算法的集合,而且这些算法都已经被优化过了。在面对大数据集时它的效果要好于 BFMatcher。我们将看到基于FLANN的匹配器的第二个示例。 817 | 818 | 对于基于FLANN的匹配器,我们需要传递两个字典,指定要使用的算法和其他相关参数等。首先是IndexParams。对于各种算法,要传递的信息在FLANN文档中进行了解。总而言之,对于像SIFT,SURF等算法,你可以传递以下内容: 819 | 820 | ```python 821 | FLANN_INDEX_KDTREE = 1 822 | index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) 823 | ``` 824 | 825 | 但使用 ORB 时,我们要传入的参数如下。注释掉的值是文献中推荐使用的,但是它们并不适合所有情况,其他值的效果可能会更好。 826 | 827 | ```python 828 | FLANN_INDEX_LSH = 6 829 | index_params= dict(algorithm = FLANN_INDEX_LSH, 830 | table_number = 6, # 12 831 | key_size = 12, # 20 832 | multi_probe_level = 1) #2 833 | ``` 834 | 835 | 第二个字典是SearchParams。它指定应递归遍历索引中的树的次数。值越高,精度越高,但也需要更多时间。如果要更改该值,请传递search_params = dict(checks = 100)。 836 | 837 | 有了这些信息,我们就可以开始工作了。 838 | 839 | ```python 840 | import numpy as np 841 | import cv2 as cv 842 | from matplotlib import pyplot as plt 843 | 844 | img1 = cv.imread('box.png',0) # queryImage 845 | img2 = cv.imread('box_in_scene.png',0) # trainImage 846 | 847 | # Initiate SIFT detector 848 | sift = cv.SIFT() 849 | 850 | # find the keypoints and descriptors with SIFT 851 | kp1, des1 = sift.detectAndCompute(img1,None) 852 | kp2, des2 = sift.detectAndCompute(img2,None) 853 | 854 | # FLANN parameters 855 | FLANN_INDEX_KDTREE = 1 856 | index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) 857 | search_params = dict(checks=50) # or pass empty dictionary 858 | 859 | flann = cv.FlannBasedMatcher(index_params,search_params) 860 | 861 | matches = flann.knnMatch(des1,des2,k=2) 862 | 863 | # Need to draw only good matches, so create a mask 864 | matchesMask = [[0,0] for i in xrange(len(matches))] 865 | 866 | # ratio test as per Lowe's paper 867 | for i,(m,n) in enumerate(matches): 868 | if m.distance < 0.7*n.distance: 869 | matchesMask[i]=[1,0] 870 | 871 | draw_params = dict(matchColor = (0,255,0), 872 | singlePointColor = (255,0,0), 873 | matchesMask = matchesMask, 874 | flags = 0) 875 | 876 | img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params) 877 | 878 | plt.imshow(img3,),plt.show() 879 | ``` 880 | 881 | 结果如下图所示: 882 | 883 | ![image23](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image23.jpg) 884 | 885 | ## 十、特征匹配+ Homography查找对象 886 | 887 | *** 888 | 889 | ### 目标: 890 | 891 | 本章节你需要学习以下内容: 892 | 893 | *我们将联合使用特征提取和 calib3d 模块中的 findHomography 在复杂图像中查找已知对象。 894 | 895 | ### 1、基础 896 | 897 | 还记得上一节我们做了什么吗?我们使用一个查询图像,在其中找到一些特征点(关键点),我们又在另一幅图像中也找到了一些特征点,最后对这两幅图像之间的特征点进行匹配。简单来说就是:我们在一张杂乱的图像中找到了一个对象(的某些部分)的位置。这些信息足以帮助我们在目标图像中准确的找到(查询图像)对象。 898 | 899 | 为了达到这个目的我们可以使用 calib3d 模块中的 cv2.findHomography()函数。如果将这两幅图像中的特征点集传给这个函数,他就会找到这个对象的透视图变换。然后我们就可以使用函数 cv2.perspectiveTransform() 找到这个对象了。至少要 4 个正确的点才能找到这种变换。 900 | 901 | 我们已经知道在匹配过程可能会有一些错误,而这些错误会影响最终结果。为了解决这个问题,算法使用 RANSAC 和 LEAST_MEDIAN(可以通过参数来设定)。所以好的匹配提供的正确的估计被称为 inliers,剩下的被称为outliers。cv2.findHomography() 返回一个掩模,这个掩模确定了 inlier 和outlier 点。 902 | 903 | 让我们来搞定它吧! 904 | 905 | ### 2、代码实现 906 | 907 | 首先,像往常一样,让我们在图像中找到SIFT特征并应用比率测试来找到最佳匹配。 908 | 909 | ```python 910 | import numpy as np 911 | import cv2 as cv 912 | from matplotlib import pyplot as plt 913 | 914 | MIN_MATCH_COUNT = 10 915 | 916 | img1 = cv.imread('box.png',0) # queryImage 917 | img2 = cv.imread('box_in_scene.png',0) # trainImage 918 | 919 | # Initiate SIFT detector 920 | sift = cv.xfeatures2d.SIFT_create() 921 | 922 | # find the keypoints and descriptors with SIFT 923 | kp1, des1 = sift.detectAndCompute(img1,None) 924 | kp2, des2 = sift.detectAndCompute(img2,None) 925 | 926 | FLANN_INDEX_KDTREE = 1 927 | index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) 928 | search_params = dict(checks = 50) 929 | 930 | flann = cv.FlannBasedMatcher(index_params, search_params) 931 | matches = flann.knnMatch(des1,des2,k=2) 932 | 933 | # store all the good matches as per Lowe's ratio test. 934 | good = [] 935 | for m,n in matches: 936 | if m.distance < 0.7*n.distance: 937 | good.append(m) 938 | ``` 939 | 940 | 现在我们设置一个条件,即至少10个匹配(由MIN_MATCH_COUNT定义)才去查找目标。否则只是显示一条消息,说明没有足够的匹配。 941 | 942 | 如果找到了足够的匹配,我们要提取两幅图像中匹配点的坐标。把它们传入到函数中计算透视变换。一旦我们找到 3x3 的变换矩阵,就可以使用它将查询图像的四个顶点(四个角)变换到目标图像中去了。然后再绘制出来。 943 | 944 | ```python 945 | if len(good)>MIN_MATCH_COUNT: 946 | src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) 947 | dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) 948 | 949 | M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC,5.0) 950 | matchesMask = mask.ravel().tolist() 951 | 952 | h,w,d = img1.shape 953 | pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2) 954 | dst = cv.perspectiveTransform(pts,M) 955 | 956 | img2 = cv.polylines(img2,[np.int32(dst)],True,255,3, cv.LINE_AA) 957 | else: 958 | print( "Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT) ) 959 | matchesMask = None 960 | ``` 961 | 962 | 最后,我们绘制内部函数(如果成功找到对象)或匹配关键点(如果失败)。 963 | 964 | ```python 965 | draw_params = dict(matchColor = (0,255,0), # draw matches in green color 966 | singlePointColor = None, 967 | matchesMask = matchesMask, # draw only inliers 968 | flags = 2) 969 | 970 | img3 = cv.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params) 971 | 972 | plt.imshow(img3, 'gray'),plt.show() 973 | ``` 974 | 975 | 请参阅下面的结果。 对象在杂乱图像中标记为白色: 976 | 977 | ![image24](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/5.Feature%20Detection%20and%20Description/Image/image24.jpg) -------------------------------------------------------------------------------- /6.Video Analysis /Image/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image1.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image10.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image11.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image12.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image2.gif -------------------------------------------------------------------------------- /6.Video Analysis /Image/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image3.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image4.gif -------------------------------------------------------------------------------- /6.Video Analysis /Image/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image5.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image6.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image7.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image8.jpg -------------------------------------------------------------------------------- /6.Video Analysis /Image/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/6.Video Analysis /Image/image9.jpg -------------------------------------------------------------------------------- /6.Video Analysis /README.md: -------------------------------------------------------------------------------- 1 | # 第六章:视频分析 2 | 3 | 本章节你将学习Meanshift和Camshift、光流和背景消除等OpenCV视频分析的相关内容。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## 一、Meanshift和Camshift 10 | 11 | *** 12 | 13 | ### 目标: 14 | 15 | 本章节你需要学习以下内容: 16 | 17 | *我们将学习Meanshift和Camshift算法来查找和跟踪视频中的对象。 18 | 19 | ### 1、Meanshift 20 | 21 | Meanshift 算法的基本原理是和很简单的。假设我们有一堆点(比如直方图反向投影得到的点),和一个小的圆形窗口,我们要完成的任务就是将这个窗口移动到最大灰度密度处(或者是点最多的地方)。就像下面给出的图像所示: 22 | 23 | ![image1](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image1.jpg) 24 | 25 | 初始窗口是蓝色的“C1”,它的圆心为蓝色方框“C1_o”,而窗口中所有点质心却是“C1_r”(小的蓝色圆圈),很明显圆心和点的质心没有重合。所以移动圆心 C1_o 到质心 C1_r,这样我们就得到了一个新的窗口。这时又可以找到新窗口内所有点的质心,大多数情况下还是不重合的,所以重复上面的操作:将新窗口的中心移动到新的质心。就这样不停的迭代操作直到窗口的中心和其所包含点的质心重合为止(或者有一点小误差)。按照这样的操作我们的窗口最终会落在像素值(和)最大的地方。如上图所示“C2”是窗口的最后位址,我们可以看出来这个窗口中的像素点最多。整个过程如下图所示: 26 | 27 | ![image2](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image2.gif) 28 | 29 | 所以我们通常会通过直方图反投影图像和初始目标位置。当物体移动时,显然移动反映在直方图反投影图像中。因此,meanshift算法将窗口移动到具有最大密度的新位置。 30 | 31 | ### 2、OpenCV 中的 Meanshift 32 | 33 | 要在 OpenCV 中使用 Meanshift 算法首先我们要对目标对象进行设置,计算目标对象的直方图,这样在执行 meanshift 算法时我们就可以将目标对象反向投影到每一帧中去了。另外我们还需要提供窗口的起始位置。在这里我们值计算 H(Hue)通道的直方图,同样为了避免低亮度造成的影响,我们使用函数 cv2.inRange()将低亮度的值忽略掉。 34 | 35 | ```python 36 | import numpy as np 37 | import cv2 as cv 38 | 39 | cap = cv.VideoCapture('slow.flv') 40 | 41 | # take first frame of the video 42 | ret,frame = cap.read() 43 | 44 | # setup initial location of window 45 | r,h,c,w = 250,90,400,125 # simply hardcoded the values 46 | track_window = (c,r,w,h) 47 | 48 | # set up the ROI for tracking 49 | roi = frame[r:r+h, c:c+w] 50 | hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV) 51 | mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) 52 | roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180]) 53 | cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX) 54 | 55 | # Setup the termination criteria, either 10 iteration or move by atleast 1 pt 56 | term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 ) 57 | 58 | while(1): 59 | ret ,frame = cap.read() 60 | if ret == True: 61 | hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) 62 | dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1) 63 | 64 | # apply meanshift to get the new location 65 | ret, track_window = cv.meanShift(dst, track_window, term_crit) 66 | 67 | # Draw it on image 68 | x,y,w,h = track_window 69 | img2 = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2) 70 | cv.imshow('img2',img2) 71 | 72 | k = cv.waitKey(60) & 0xff 73 | if k == 27: 74 | break 75 | else: 76 | cv.imwrite(chr(k)+".jpg",img2) 77 | 78 | else: 79 | break 80 | 81 | cv.destroyAllWindows() 82 | cap.release() 83 | ``` 84 | 85 | 我使用的视频中的三个帧如下: 86 | 87 | ![image3](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image3.jpg) 88 | 89 | ### 3、Camshift 90 | 91 | 你认真看上面的结果了吗?这里面还有一个问题。我们的窗口的大小是固定的,而汽车由远及近(在视觉上)是一个逐渐变大的过程,固定的窗口是不合适的。所以我们需要根据目标的大小和角度来对窗口的大小和角度进行修订。OpenCVLabs 为我们带来的解决方案(1988 年):一个被叫做 CAMshift 的算法(连续自适应手段移位),由Gary Bradsky于1988年发表在他的论文“用于感知用户界面的计算机视觉面部跟踪”中。 92 | 93 | Camshift算法首先应用meanshift。一旦meanshift收敛,它就会更新窗口的大小,$s = 2 \times \sqrt{\frac{M_{00}}{256}}$。它还计算最佳拟合椭圆的方向。同样,它将新的缩放搜索窗口和先前的窗口位置应用于meanshift。继续该过程直到满足所需的准确度。 94 | 95 | ![image4](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image4.gif) 96 | 97 | ### 4、OpenCV 中的 Camshift 98 | 99 | 它与meanshift几乎相同,但它返回一个旋转的矩形(这是我们的结果)和box参数(用于在下一次迭代中作为搜索窗口传递)。请参阅以下代码: 100 | 101 | ```python 102 | import numpy as np 103 | import cv2 as cv 104 | 105 | cap = cv.VideoCapture('slow.flv') 106 | 107 | # take first frame of the video 108 | ret,frame = cap.read() 109 | 110 | # setup initial location of window 111 | r,h,c,w = 250,90,400,125 # simply hardcoded the values 112 | track_window = (c,r,w,h) 113 | 114 | # set up the ROI for tracking 115 | roi = frame[r:r+h, c:c+w] 116 | hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV) 117 | mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) 118 | roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180]) 119 | cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX) 120 | 121 | # Setup the termination criteria, either 10 iteration or move by atleast 1 pt 122 | term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 ) 123 | 124 | while(1): 125 | ret ,frame = cap.read() 126 | if ret == True: 127 | hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) 128 | dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1) 129 | 130 | # apply meanshift to get the new location 131 | ret, track_window = cv.CamShift(dst, track_window, term_crit) 132 | 133 | # Draw it on image 134 | pts = cv.boxPoints(ret) 135 | pts = np.int0(pts) 136 | img2 = cv.polylines(frame,[pts],True, 255,2) 137 | cv.imshow('img2',img2) 138 | 139 | k = cv.waitKey(60) & 0xff 140 | if k == 27: 141 | break 142 | else: 143 | cv.imwrite(chr(k)+".jpg",img2) 144 | 145 | else: 146 | break 147 | 148 | cv.destroyAllWindows() 149 | cap.release() 150 | ``` 151 | 152 | 结果的三个框架如下所示: 153 | 154 | ![image5](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image5.jpg) 155 | 156 | ## 二、光流 157 | 158 | *** 159 | 160 | ### 目标: 161 | 162 | 本章节你需要学习以下内容: 163 | 164 | *我们将了解光流的概念及 Lucas-Kanade 光流法。 165 | *我们将使用cv.calcOpticalFlowPyrLK()等函数来跟踪视频中的特征点。 166 | 167 | ### 1、光流 168 | 169 | 由于目标对象或者摄像机的移动造成的图像对象在连续两帧图像中的移动被称为光流。它是一个 2D 向量场,可以用来显示一个点从第一帧图像到第二帧图像之间的移动。如下图所示(维基百科关于光流的文章)。 170 | 171 | ![image6](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image6.jpg) 172 | 173 | 上图显示了一个点在连续的五帧图像间的移动。箭头表示光流场向量。光流在很多领域中都很有用: 174 | 175 | * 由运动重建结构 176 | * 视频压缩 177 | * 视频防抖等等 178 | 179 | 光流是基于以下假设下工作的: 180 | 181 | 1. 在连续的两帧图像之间(目标对象的)像素的灰度值不改变。 182 | 2. 相邻像素具有相似的运动。 183 | 184 | 考虑第一帧中的像素$I(x,y,t)$,它在dt时间之后移动距离$(dx,dy)$。根据第一条假设:灰度值不变。所以我们可以得到: 185 | 186 | $$I(x,y,t) = I(x+dx, y+dy, t+dt)$$ 187 | 188 | 然后对等号右侧采用泰勒级数展开,删除相同项并两边除以dt得到以下等式: 189 | 190 | $$f_x u + f_y v + f_t = 0 \;$$ 191 | 192 | 其中: 193 | 194 | $$f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial y}$$ 195 | 196 | $$u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt}$$ 197 | 198 | 上边的等式叫做光流方程。其中 $f_x$ 和 $f_y$ 是图像梯度,同样 $f_t$ 是时间方向的梯度。但(u,v)是不知道的。我们不能在一个等式中求解两个未知数。有几个方法可以帮我们解决这个问题,其中的一个是 Lucas-Kanade 法。 199 | 200 | ### 2、Lucas-Kanade方法 201 | 202 | 现在我们要使用第二条假设,邻域内的所有点都有相似的运动。LucasKanade 法就是利用一个 3x3 邻域中的 9 个点具有相同运动的这一点。这样我们就可以找到$(f_x, f_y, f_t)$这 9 个点的光流方程,用它们组成一个具有两个未知数 9 个等式的方程组,这是一个约束条件过多的方程组。一个好的解决方法就是使用最小二乘拟合。下面就是求解结果: 203 | 204 | $$\begin{bmatrix} u \\ v \end{bmatrix} = \begin{bmatrix} \sum_{i}{f_{x_i}}^2 & \sum_{i}{f_{x_i} f_{y_i} } \\ \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2 \end{bmatrix}^{-1} \begin{bmatrix} - \sum_{i}{f_{x_i} f_{t_i}} \\ - \sum_{i}{f_{y_i} f_{t_i}} \end{bmatrix}$$ 205 | 206 | (你会发现上边的逆矩阵与 Harris 角点检测器非常相似,这说明角点很适合被用来做跟踪) 207 | 208 | 从使用者的角度来看,想法很简单,我们取跟踪一些点,然后我们就会获得这些点的光流向量。但是还有一些问题。直到现在我们处理的都是很小的运动。如果有大的运动怎么办呢?图像金字塔。我们可以使用图像金字塔的顶层,此时小的运动被移除,大的运动装换成了小的运动,现在再使用 Lucas-Kanade算法,我们就会得到尺度空间上的光流。 209 | 210 | ### 3、Lucas-KanadeOpenCV中的Lucas-Kanade光流 211 | 212 | O上述所有过程都被 OpenCV 打包成了一个函数:cv2.calcOpticalFlowPyrLK()。现在我们使用这个函数创建一个小程序来跟踪视频中的一些点。要跟踪那些点呢?我们使用函数 cv2.goodFeatureToTrack() 来确定要跟踪的点。我们首先在视频的第一帧图像中检测一些 Shi-Tomasi 角点,然后我们使用 LucasKanade 算法迭代跟踪这些角点。我们要给函数 cv2.calcOpticlaFlowPyrLK()传入前一帧图像和其中的点,以及下一帧图像。函数将返回带有状态数的点,如果状态数是 1,那说明在下一帧图像中找到了这个点(上一帧中角点),如果状态数是 0,就说明没有在下一帧图像中找到这个点。我们再把这些点作为参数传给函数,如此迭代下去实现跟踪。代码如下: 213 | 214 | ```python 215 | import numpy as np 216 | import cv2 as cv 217 | 218 | cap = cv.VideoCapture('slow.flv') 219 | 220 | # params for ShiTomasi corner detection 221 | feature_params = dict( maxCorners = 100, 222 | qualityLevel = 0.3, 223 | minDistance = 7, 224 | blockSize = 7 ) 225 | 226 | # Parameters for lucas kanade optical flow 227 | lk_params = dict( winSize = (15,15), 228 | maxLevel = 2, 229 | criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03)) 230 | 231 | # Create some random colors 232 | color = np.random.randint(0,255,(100,3)) 233 | 234 | # Take first frame and find corners in it 235 | ret, old_frame = cap.read() 236 | old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY) 237 | p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params) 238 | 239 | # Create a mask image for drawing purposes 240 | mask = np.zeros_like(old_frame) 241 | 242 | while(1): 243 | ret,frame = cap.read() 244 | frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) 245 | 246 | # calculate optical flow 247 | p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) 248 | 249 | # Select good points 250 | good_new = p1[st==1] 251 | good_old = p0[st==1] 252 | 253 | # draw the tracks 254 | for i,(new,old) in enumerate(zip(good_new,good_old)): 255 | a,b = new.ravel() 256 | c,d = old.ravel() 257 | mask = cv.line(mask, (a,b),(c,d), color[i].tolist(), 2) 258 | frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1) 259 | img = cv.add(frame,mask) 260 | 261 | cv.imshow('frame',img) 262 | k = cv.waitKey(30) & 0xff 263 | if k == 27: 264 | break 265 | 266 | # Now update the previous frame and previous points 267 | old_gray = frame_gray.copy() 268 | p0 = good_new.reshape(-1,1,2) 269 | 270 | cv.destroyAllWindows() 271 | cap.release() 272 | ``` 273 | 274 | ((上面的代码没有对返回角点的正确性进行检查。图像中的一些特征点甚至在丢失以后,光流还会找到一个预期相似的点。所以为了实现稳定的跟踪,我们应该每个一定间隔就要进行一次角点检测。OpenCV 的官方示例中带有这样一个例子,它是每 5 帧进行一个特征点检测。它还对光流点使用反向检测来选取好的点进行跟踪。示例为/samples/python2/lk_track.py) 275 | 276 | 结果如下图所示: 277 | 278 | ![image7](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image7.jpg) 279 | 280 | ### 4、OpenCV中的密集光流 281 | 282 | Lucas-Kanade 法是计算一些特征点的光流(我们上面的例子使用的是Shi-Tomasi 算法检测到的角点)。OpenCV 还提供了一种计算稠密光流的方法。它会图像中的所有点的光流。这是基于 Gunner_Farneback 的算法(2003 年)。 283 | 284 | 下面的例子就是使用上面的算法计算稠密光流。结果是一个带有光流向量(u,v)的双通道数组。通过计算我们能得到光流的大小和方向。我们使用颜色对结果进行编码以便于更好的观察。方向对应于 H(Hue)通道,大小对应于 V(Value)通道。代码如下: 285 | 286 | ```python 287 | import cv2 as cv 288 | import numpy as np 289 | cap = cv.VideoCapture("vtest.avi") 290 | 291 | ret, frame1 = cap.read() 292 | prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY) 293 | hsv = np.zeros_like(frame1) 294 | hsv[...,1] = 255 295 | 296 | while(1): 297 | ret, frame2 = cap.read() 298 | next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY) 299 | 300 | flow = cv.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0) 301 | 302 | mag, ang = cv.cartToPolar(flow[...,0], flow[...,1]) 303 | hsv[...,0] = ang*180/np.pi/2 304 | hsv[...,2] = cv.normalize(mag,None,0,255,cv.NORM_MINMAX) 305 | bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR) 306 | 307 | cv.imshow('frame2',bgr) 308 | k = cv.waitKey(30) & 0xff 309 | if k == 27: 310 | break 311 | elif k == ord('s'): 312 | cv.imwrite('opticalfb.png',frame2) 313 | cv.imwrite('opticalhsv.png',bgr) 314 | prvs = next 315 | 316 | cap.release() 317 | cv.destroyAllWindows() 318 | ``` 319 | 320 | 请看下面的结果: 321 | 322 | ![image8](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image8.jpg) 323 | 324 | OpenCV 的官方示例中有一个更高级的稠密光流算法,具体请参阅/samples/python2/opt_flow.py。 325 | 326 | ## 三、背景消除 327 | 328 | *** 329 | 330 | ### 目标: 331 | 332 | 本章节你需要学习以下内容: 333 | 334 | *我们将熟悉OpenCV中可用的背景消除方法。 335 | 336 | ### 1、基础 337 | 338 | 在很多基础应用中背景检出都是一个非常重要的步骤。例如顾客统计,使用一个静态摄像头来记录进入和离开房间的人数,或者是交通摄像头,需要提取交通工具的信息等。在所有的这些例子中,首先要将人或车单独提取出来。技术上来说,我们需要从静止的背景中提取移动的前景。 339 | 340 | 如果你有一张背景(仅有背景不含前景)图像,比如没有顾客的房间,没有交通工具的道路等,那就好办了。我们只需要在新的图像中减去背景就可以得到前景对象了。但是在大多数情况下,我们没有这样的(背景)图像,所以我们需要从我们有的图像中提取背景。如果图像中的交通工具还有影子的话,那这个工作就更难了,因为影子也在移动,仅仅使用减法会把影子也当成前景。真是一件很复杂的事情。 341 | 342 | 为了实现这个目的科学家们已经提出了几种算法。OpenCV 中已经包含了其中三种比较容易使用的方法。我们将逐一学习到它们。 343 | 344 | #### (1)BackgroundSubtractorMOG 345 | 346 | 这是一个以混合高斯模型为基础的前景/背景分割算法。它是 P.KadewTraKuPong和 R.Bowden 在 2001 年提出的。它使用 K(K=3 或 5)个高斯分布混合对背景像素进行建模。使用这些颜色(在整个视频中)存在时间的长短作为混合的权重。背景的颜色一般持续的时间最长,而且更加静止。一个像素怎么会有分布呢?在 x,y 平面上一个像素就是一个像素没有分布,但是我们现在讲的背景建模是基于时间序列的,因此每一个像素点所在的位置在整个时间序列中就会有很多值,从而构成一个分布。 347 | 348 | 在编写代码时,我们需要使用函数:cv2.createBackgroundSubtractorMOG()创建一个背景对象。这个函数有些可选参数,比如要进行建模场景的时间长度,高斯混合成分的数量,阈值等。将他们全部设置为默认值。然后在整个视频中我们是需要使用 backgroundsubtractor.apply() 就可以得到前景的掩模了。 349 | 350 | 下面是一个简单的例子: 351 | 352 | ```python 353 | import numpy as np 354 | import cv2 as cv 355 | 356 | cap = cv.VideoCapture('vtest.avi') 357 | fgbg = cv.bgsegm.createBackgroundSubtractorMOG() 358 | 359 | while(1): 360 | ret, frame = cap.read() 361 | fgmask = fgbg.apply(frame) 362 | cv.imshow('frame',fgmask) 363 | k = cv.waitKey(30) & 0xff 364 | if k == 27: 365 | break 366 | 367 | cap.release() 368 | cv.destroyAllWindows() 369 | ``` 370 | 371 | (所有结果都显示在最后以供比较)。 372 | 373 | #### (2)BackgroundSubtractorMOG2 374 | 375 | 这个也是以高斯混合模型为基础的背景/前景分割算法。它是以 2004 年和 2006 年 Z.Zivkovic 的两篇文章为基础的。这个算法的一个特点是它为每一个像素选择一个合适数目的高斯分布。(上一个方法中我们使用是 K 高斯分布)。这样就会对由于亮度等发生变化引起的场景变化产生更好的适应。 376 | 377 | 和前面一样我们需要创建一个背景对象。但在这里我们我们可以选择是否检测阴影。如果 detectShadows = True(默认值),它就会检测并将影子标记出来,但是这样做会降低处理速度。影子会被标记为灰色。 378 | 379 | ```python 380 | import numpy as np 381 | import cv2 as cv 382 | 383 | cap = cv.VideoCapture('vtest.avi') 384 | 385 | fgbg = cv.createBackgroundSubtractorMOG2() 386 | 387 | while(1): 388 | ret, frame = cap.read() 389 | fgmask = fgbg.apply(frame) 390 | cv.imshow('frame',fgmask) 391 | k = cv.waitKey(30) & 0xff 392 | if k == 27: 393 | break 394 | 395 | cap.release() 396 | cv.destroyAllWindows() 397 | ``` 398 | 399 | (最后给出的结果) 400 | 401 | #### (3)BackgroundSubtractorGMG 402 | 403 | 此算法结合了静态背景图像估计和每个像素的贝叶斯分割。这是 2012 年Andrew_B.Godbehere,Akihiro_Matsukawa 和 Ken_Goldberg 在文章中提出的。 404 | 405 | 它使用前面很少的图像(默认为前 120 帧)进行背景建模。使用了概率前景估计算法(使用贝叶斯估计鉴定前景)。这是一种自适应的估计,新观察到的对象比旧的对象具有更高的权重,从而对光照变化产生适应。一些形态学操作如开运算闭运算等被用来除去不需要的噪音。在前几帧图像中你会得到一个黑色窗口。 406 | 407 | 对结果进行形态学开运算对与去除噪声很有帮助。 408 | 409 | ```python 410 | import numpy as np 411 | import cv2 as cv 412 | 413 | cap = cv.VideoCapture('vtest.avi') 414 | 415 | kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE,(3,3)) 416 | fgbg = cv.bgsegm.createBackgroundSubtractorGMG() 417 | 418 | while(1): 419 | ret, frame = cap.read() 420 | fgmask = fgbg.apply(frame) 421 | fgmask = cv.morphologyEx(fgmask, cv.MORPH_OPEN, kernel) 422 | cv.imshow('frame',fgmask) 423 | k = cv.waitKey(30) & 0xff 424 | if k == 27: 425 | break 426 | 427 | cap.release() 428 | cv.destroyAllWindows() 429 | ``` 430 | 431 | ### 2、结果 432 | 433 | #### (1)原始框架 434 | 435 | 下图显示了视频的第200帧 436 | 437 | ![image9](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image9.jpg) 438 | 439 | #### (2)BackgroundSubtractorMOG的结果 440 | 441 | ![image10](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image10.jpg) 442 | 443 | #### (3)BackgroundSubtractorMOG2的结果 444 | 445 | 灰色区域显示阴影区域。 446 | 447 | ![image11](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image11.jpg) 448 | 449 | #### (4)BackgroundSubtractorGMG的结果 450 | 451 | 通过形态开口消除噪音。 452 | 453 | ![image12](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/6.Video%20Analysis%20/Image/image12.jpg) -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image1.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image10.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image2.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image3.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image4.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image5.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image6.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image7.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image8.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/Image/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/7.Camera Calibration and 3D Reconstruction/Image/image9.jpg -------------------------------------------------------------------------------- /7.Camera Calibration and 3D Reconstruction/README.md: -------------------------------------------------------------------------------- 1 | # 第七章:摄像机标定和 3D 重构 2 | 3 | 本章节你将学习摄像机标定、姿态估计、对极集合和立体图像的深度图等OpenCV摄像机标定和3S重构的相关内容。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## 一、摄像机标定 10 | 11 | *** 12 | 13 | ### 目标: 14 | 15 | 本章节你需要学习以下内容: 16 | 17 | *我们将了解相机的畸变,相机的内部参数和外部参数等。 18 | *我们将学习如何找到这些参数,和对畸变图像进行修复等。 19 | 20 | ### 1、基础 21 | 22 | 如今市面上便宜的针孔摄像头会给图像带来了很多畸变。两种主要的畸变有两:径向畸变和切向畸变。 23 | 24 | 由于径向变形,直线会出现弯曲。当我们远离图像中心时,它的效果就会更加明显了。例如,下面显示了一个图像,其中棋盘的两个边缘用红线标记。但是你可以看到图像中边框不是直线而且与红线不重合。所有应该是直线的地方都变成突出的曲线。访问Distortion(光学)了解更多详情。 25 | 26 | ![image1](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image1.jpg) 27 | 28 | 这种畸变可以通过下面的方程组进行纠正: 29 | 30 | $$x_{distorted} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6)$$ 31 | 32 | $$y_{distorted} = y( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6)$$ 33 | 34 | 类似地,另一种失真是发生切向失真,因为图像拍摄镜头未完全平行于成像平面对齐。因此,图像中的某些区域可能看起来比预期的更近。它表示如下: 35 | 36 | $$x_{distorted} = x + [ 2p_1xy + p_2(r^2+2x^2)]$$ 37 | 38 | $$y_{distorted} = y + [ p_1(r^2+ 2y^2)+ 2p_2xy]$$ 39 | 40 | 简而言之,我们需要找到五个参数,称为失真系数,由下式给出: 41 | 42 | $$Distortion \; coefficients=(k_1 \hspace{10pt} k_2 \hspace{10pt} p_1 \hspace{10pt} p_2 \hspace{10pt} k_3)$$ 43 | 44 | 除此之外,我们还需要找到更多信息,比如摄像机的内部参数和外部参数。内部参数特定于相机。它包括焦距($f_x, f_y$),光学中心($c_x, c_y$)等信息。它也被称为相机矩阵,仅取决于相机,因此可以只计算一次,然后存储以备将来使用。它表示为3x3矩阵: 45 | 46 | $$camera \; matrix = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ]$$ 47 | 48 | 外部参数对应于旋转向量和平移向量,它可以将3D点的坐标转换到坐标系中。 49 | 50 | 在 3D 相关应用中,必须要先校正这些畸变。为了找到这些参数,我们必须要提供一些包含明显图案模式的样本图片(比如说棋盘)。我们可以在上面找到一些特殊点(如棋盘的四个角点)。我们起到这些特殊点在图片中的位置以及它们的真是位置。有了这些信息,我们就可以使用数学方法求解畸变系数。这就是整个故事的摘要了。为了得到更好的结果,我们至少需要 10 个这样的图案模式。 51 | 52 | ### 2、代码实现 53 | 54 | 如上所述,我们至少需要 10 图案模式来进行摄像机标定。OpenCV 自带了一些棋盘图像(/sample/cpp/left001.jpg--left14.jpg), 所以我们可以使用它们。为了便于理解,我们可以认为仅有一张棋盘图像。重要的是在进行摄像机标定时我们要输入一组 3D 真实世界中的点以及与它们对应 2D 图像中的点。2D 图像的点可以在图像中很容易的找到。(这些点在图像中的位置是棋盘上两个黑色方块相互接触的地方) 55 | 56 | 那么真实世界中的 3D 的点呢?这些图像来源与静态摄像机和棋盘不同的摆放位置和朝向。所以我们需要知道(X,Y,Z)的值。但是为了简单,我们可以说棋盘在 XY 平面是静止的,(所以 Z 总是等于 0)摄像机在围着棋盘移动。这种假设让我们只需要知道 X,Y 的值就可以了。现在为了求 X,Y 的值,我们只需要传入这些点(0,0),(1,0),(2,0)...,它们代表了点的位置。在这个例子中,我们的结果的单位就是棋盘(单个)方块的大小。但是如果我们知道单个方块的大小(加入说 30mm),我们输入的值就可以是(0,0),(30,0),(60,0)...,结果的单位就是 mm。(在本例中我们不知道方块的大小,因为不是我们拍的,所以只能用前一种方法了)。 57 | 58 | 3D 点被称为 对象点,2D 图像点被称为 图像点。 59 | 60 | #### (1)设置 61 | 62 | 为了找到棋盘的图案,我们要使用函数 cv2.findChessboardCorners()。我们还需要传入图案的类型,比如说 8x8 的格子或 5x5 的格子等。在本例中我们使用的恨死 7x8 的格子。(通常情况下棋盘都是 8x8 或者 7x7)。它会返回角点,如果得到图像的话返回值类型(Retval)就会是 True。这些角点会按顺序排列(从左到右,从上到下)。 63 | 64 | 其他:这个函数可能不会找出所有图像中应有的图案。所以一个好的方法是编写代码,启动摄像机并在每一帧中检查是否有应有的图案。在我们获得图案之后我们要找到角点并把它们保存成一个列表。在读取下一帧图像之前要设置一定的间隔,这样我们就有足够的时间调整棋盘的方向。继续这个过程直到我们得到足够多好的图案。就算是我们举得这个例子,在所有的 14 幅图像中也不知道有几幅是好的。所以我们要读取每一张图像从其中找到好的能用的。 65 | 66 | 其他:除了使用棋盘之外,我们还可以使用环形格子,但是要使用函数cv2.findCirclesGrid() 来找图案。据说使用环形格子只需要很少的图像就可以了。 67 | 68 | 在找到这些角点之后我们可以使用函数 cv2.cornerSubPix() 增加准确度。我们使用函数 cv2.drawChessboardCorners() 绘制图案。所有的这些步骤都被包含在下面的代码中了: 69 | 70 | ```python 71 | import numpy as np 72 | import cv2 as cv 73 | import glob 74 | 75 | # termination criteria 76 | criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001) 77 | 78 | # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) 79 | objp = np.zeros((6*7,3), np.float32) 80 | objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) 81 | 82 | # Arrays to store object points and image points from all the images. 83 | objpoints = [] # 3d point in real world space 84 | imgpoints = [] # 2d points in image plane. 85 | 86 | images = glob.glob('*.jpg') 87 | 88 | for fname in images: 89 | img = cv.imread(fname) 90 | gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) 91 | 92 | # Find the chess board corners 93 | ret, corners = cv.findChessboardCorners(gray, (7,6), None) 94 | 95 | # If found, add object points, image points (after refining them) 96 | if ret == True: 97 | objpoints.append(objp) 98 | 99 | corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria) 100 | imgpoints.append(corners) 101 | 102 | # Draw and display the corners 103 | cv.drawChessboardCorners(img, (7,6), corners2, ret) 104 | cv.imshow('img', img) 105 | cv.waitKey(500) 106 | 107 | cv.destroyAllWindows() 108 | ``` 109 | 110 | 其上绘制有图案的一幅图像如下所示: 111 | 112 | ![image2](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image2.jpg) 113 | 114 | #### (2)标定 115 | 116 | 在得到了这些对象点和图像点之后,我们已经准备好来做摄像机标定了。 117 | 118 | 我们要使用的函数是 cv2.calibrateCamera()。它会返回摄像机矩阵,畸变系数,旋转和变换向量等。 119 | 120 | ```python 121 | ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) 122 | ``` 123 | 124 | #### (3)畸变矫正 125 | 126 | 现在我们找到我们想要的东西了,我们可以找到一幅图像来对他进行校正了。OpenCV 提供了两种方法,我们都学习一下。不过在那之前我们可以使用从函数 cv2.getOptimalNewCameraMatrix() 得到的自由缩放系数对摄像机矩阵进行优化。如果缩放系数 alpha = 0,返回的非畸变图像会带有最少量的不想要的像素。它甚至有可能在图像角点去除一些像素。如果 alpha = 1,所有的像素都会被返回,还有一些黑图像。它还会返回一个 ROI 图像,我们可以用来对结果进行裁剪。 127 | 128 | 我们读取一个新的图像(left2.ipg) 129 | 130 | ```python 131 | img = cv.imread('left12.jpg') 132 | h, w = img.shape[:2] 133 | newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h)) 134 | ``` 135 | 136 | 使用 cv2.undistort() 这是最简单的方法。只需使用这个函数和上边得到的 ROI 对结果进行裁剪。 137 | 138 | ```python 139 | # undistort 140 | dst = cv.undistort(img, mtx, dist, None, newcameramtx) 141 | 142 | # crop the image 143 | x, y, w, h = roi 144 | dst = dst[y:y+h, x:x+w] 145 | cv.imwrite('calibresult.png', dst) 146 | ``` 147 | 148 | 使用 remapping 这应该属于“曲线救国”了。首先我们要找到从畸变图像到非畸变图像的映射方程。再使用重映射方程。 149 | 150 | ```python 151 | # undistort 152 | mapx, mapy = cv.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), 5) 153 | dst = cv.remap(img, mapx, mapy, cv.INTER_LINEAR) 154 | 155 | # crop the image 156 | x, y, w, h = roi 157 | dst = dst[y:y+h, x:x+w] 158 | cv.imwrite('calibresult.png', dst) 159 | ``` 160 | 161 | 两种方法都给出了相同的结果。 请看下面的结果: 162 | 163 | ![image3](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image3.jpg) 164 | 165 | ```python 166 | mean_error = 0 167 | for i in xrange(len(objpoints)): 168 | imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) 169 | error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2) 170 | mean_error += error 171 | 172 | print( "total error: {}".format(mean_error/len(objpoints)) ) 173 | ``` 174 | 175 | 你会发现结果图像中所有的边界都变直了。 176 | 177 | 现在我们可以使用 Numpy 提供写函数(np.savez,np.savetxt 等)将摄像机矩阵和畸变系数保存以便以后使用。 178 | 179 | ### 3、反向投影误差 180 | 181 | 我们可以利用反向投影误差对我们找到的参数的准确性进行估计。得到的结果越接近 0 越好。有了内部参数,畸变参数和旋转变换矩阵,我们就可以使用 cv2.projectPoints() 将对象点转换到图像点。然后就可以计算变换得到图像与角点检测算法的绝对差了。然后我们计算所有标定图像的误差平均值。 182 | 183 | ```python 184 | mean_error = 0 185 | for i in xrange(len(objpoints)): 186 | imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) 187 | error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2) 188 | mean_error += error 189 | 190 | print( "total error: {}".format(mean_error/len(objpoints)) ) 191 | ``` 192 | 193 | ## 二、姿态估计 194 | 195 | *** 196 | 197 | ### 目标: 198 | 199 | 本章节你需要学习以下内容: 200 | 201 | *我们将学习利用calib3d模块在图像中创建一些3D效果。 202 | 203 | ### 1、基础 204 | 205 | 在上一节的摄像机标定中,我们已经得到了摄像机矩阵,畸变系数等。有了这些信息我们就可以估计图像中图案的姿态,或物体在空间中的位置,比如目标对象是如何摆放,如何旋转等。对一个平面对象来说,我们可以假设 Z=0,这样问题就转化成摄像机在空间中是如何摆放(然后拍摄)的。所以,如果我们知道对象在空间中的姿态,我们就可以在图像中绘制一些 2D 的线条来产生 3D 的效果。我们来看一下怎么做吧。 206 | 207 | 我们的问题是,在棋盘的第一个角点绘制 3D 坐标轴(X,Y,Z 轴)。X轴为蓝色,Y 轴为绿色,Z 轴为红色。在视觉效果上来看,Z 轴应该是垂直与棋盘平面的。 208 | 209 | 首先,让我们从先前的校准结果中加载相机矩阵和畸变系数。 210 | 211 | ```python 212 | import numpy as np 213 | import cv2 as cv 214 | import glob 215 | # Load previously saved data 216 | with np.load('B.npz') as X: 217 | mtx, dist, _, _ = [X[i] for i in ('mtx','dist','rvecs','tvecs')] 218 | ``` 219 | 220 | 现在让我们创建一个函数,绘制它获取棋盘中的角(使用cv.findChessboardCorners()获得)和轴点来绘制3D轴。 221 | 222 | ```python 223 | def draw(img, corners, imgpts): 224 | corner = tuple(corners[0].ravel()) 225 | img = cv.line(img, corner, tuple(imgpts[0].ravel()), (255,0,0), 5) 226 | img = cv.line(img, corner, tuple(imgpts[1].ravel()), (0,255,0), 5) 227 | img = cv.line(img, corner, tuple(imgpts[2].ravel()), (0,0,255), 5) 228 | return img 229 | ``` 230 | 231 | 然后与前面的情况一样,我们创建终止标准,对象点(棋盘中的角点的3D点)和轴点。轴点是3D空间中用于绘制轴的点。我们绘制长度为3的轴(单位将以国际象棋方形尺寸表示,因为我们根据该尺寸校准)。所以我们的X轴是从(0,0,0)到(3,0,0)绘制的,同样。Y轴也一样。对于Z轴,它从(0,0,0)绘制到(0,0,-3)。负值表示它是朝着(垂直于)摄像机方向 232 | 233 | ```python 234 | criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001) 235 | objp = np.zeros((6*7,3), np.float32) 236 | objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) 237 | 238 | axis = np.float32([[3,0,0], [0,3,0], [0,0,-3]]).reshape(-1,3) 239 | ``` 240 | 241 | 很通常一样我们需要加载图像。搜寻 7x6 的格子,如果发现,我们就把它优化到亚像素级。然后使用函数:cv2.solvePnPRansac() 来计算旋转和变换。但我们有了变换矩阵之后,我们就可以利用它们将这些坐标轴点映射到图像平面中去。简单来说,我们在图像平面上找到了与 3D 空间中的点(3,0,0),(0,3,0),(0,0,3) 相对应的点。然后我们就可以使用我们的函数 draw() 从图像上的第一个角点开始绘制连接这些点的直线了。搞定!!! 242 | 243 | ```python 244 | for fname in glob.glob('left*.jpg'): 245 | img = cv.imread(fname) 246 | gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 247 | ret, corners = cv.findChessboardCorners(gray, (7,6),None) 248 | 249 | if ret == True: 250 | corners2 = cv.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria) 251 | 252 | # Find the rotation and translation vectors. 253 | ret,rvecs, tvecs = cv.solvePnP(objp, corners2, mtx, dist) 254 | 255 | # project 3D points to image plane 256 | imgpts, jac = cv.projectPoints(axis, rvecs, tvecs, mtx, dist) 257 | img = draw(img,corners2,imgpts) 258 | cv.imshow('img',img) 259 | k = cv.waitKey(0) & 0xFF 260 | if k == ord('s'): 261 | cv.imwrite(fname[:6]+'.png', img) 262 | 263 | cv.destroyAllWindows() 264 | ``` 265 | 266 | 看下面的一些结果。请注意,每个轴的长度为3个方格: 267 | 268 | ![image4](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image4.jpg) 269 | 270 | ### 三、渲染立方体 271 | 272 | 如果要绘制立方体,请按如下方式修改draw()函数和轴点。 273 | 274 | 修改了draw()函数: 275 | 276 | ```python 277 | def draw(img, corners, imgpts): 278 | imgpts = np.int32(imgpts).reshape(-1,2) 279 | 280 | # draw ground floor in green 281 | img = cv.drawContours(img, [imgpts[:4]],-1,(0,255,0),-3) 282 | 283 | # draw pillars in blue color 284 | for i,j in zip(range(4),range(4,8)): 285 | img = cv.line(img, tuple(imgpts[i]), tuple(imgpts[j]),(255),3) 286 | 287 | # draw top layer in red color 288 | img = cv.drawContours(img, [imgpts[4:]],-1,(0,0,255),3) 289 | 290 | return img 291 | ``` 292 | 293 | 修改了轴点。它们是3D空间中立方体的8个角: 294 | 295 | ```python 296 | axis = np.float32([[0,0,0], [0,3,0], [3,3,0], [3,0,0], 297 | [0,0,-3],[0,3,-3],[3,3,-3],[3,0,-3] ]) 298 | ``` 299 | 300 | 结果如下图所示: 301 | 302 | ![image5](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image5.jpg) 303 | 304 | 如果你对计算机图形学和增强现实等感兴趣,可以使用OpenGL渲染更复杂的图形。 305 | 306 | ## 三、对极几何 307 | 308 | *** 309 | 310 | ### 目标: 311 | 312 | 本章节你需要学习以下内容: 313 | 314 | *我们将了解多视角几何的基础知识 315 | *我们将看到什么是极点,极线,对极约束等。 316 | 317 | ### 1、基础 318 | 319 | 当我们使用针孔相机拍摄图像时,我们会丢失一些重要的信息,比如图像的深度。或者是图像中的每个点距离相机有多远,因为它是3D到2D的转换。因此一个重要的问题就产生了,使用这样的摄像机我们能否计算除深度信息呢?答案是我们需要使用多个摄像头。我们的眼睛以类似的方式工作,我们使用两个相机(两只眼睛)来判断物体的距离,称为立体视觉。那么让我们看看OpenCV在这个领域提供了什么。 320 | 321 | (《学习 OpenCV》一书有大量相关知识) 322 | 323 | 在进入深度图像之前,让我们先了解多视图几何中的一些基本概念。在本节中,我们将讨论极线几何。请参见下图,其中显示了使用两个相机拍摄同一场景图像的基本设置。 324 | 325 | ![image6](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image6.jpg) 326 | 327 | 如果我们仅使用左侧相机,则无法找到与图像中的点x对应的3D点,因为线OX上的每个点都投影到图像平面上的相同点。但是如果我们也考虑上右侧图像的话,直线 OX 上的点将投影到右侧图像上的不同位置(x')。所以根据这两幅图像,我们就可以使用三角测量计算出 3D 空间中的点到摄像机的距离(深度)。这就是整个思路。 328 | 329 | OX上不同点的投影在右平面(线l')上形成一条线。我们称它为对应于点x的极线。也就是说,要在右侧图像上找到点x,需要沿着此极线搜索。它应该在这个一维直线的某个地方(想象一下,要找到其他图像中的匹配点,你不需要搜索整个图像,只需沿着极线搜索。因此它提供了更好的性能和准确性)。这称为极线约束。类似地,所有点将在另一图像中具有其对应的极线。平面XOO'称为极线平面。 330 | 331 | O和O'是摄像机中心。从上面给出的设置中,可以看到右侧摄像机O'的投影在该点的左侧图像上看到,例如。它被称为极点。极点是通过摄像机中心和图像平面的线的交叉点。类似地,e'是左相机的极点。在某些情况下,你将无法在图像中找到极点,它们可能位于图像之外(这意味着,一台摄像机看不到另一台摄像机)。 332 | 333 | 所有的极线都通过它的极点。所以为了找到极点的位置,我们可以先找到多条极线,这些极线的交点就是极点。 334 | 335 | 所以在本小节中,我们的重点就是寻找极线和极点。但要找到它们,我们需要另外两个元素,本征矩阵(F)和基本矩阵(E)。本征矩阵包含了物理空间中两个摄像机相关的旋转和平移信息。如下图所示(本图来源自:学习 OpenCV): 336 | 337 | ![image7](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image7.jpg) 338 | 339 | 但我们更喜欢用像素坐标进行测量,对吧?基础矩阵 F 除了包含 E 的信息外还包含了两个摄像机的内参数。由于 F包含了这些内参数,因此它可以它在像素坐标系将两台摄像机关联起来。(如果使用是校正之后的图像并通过除以焦距进行了归一化,F=E)。简单来说,基础矩阵 F 将一副图像中的点映射到另一幅图像中的线(极线)上。这是通过匹配两幅图像上的点来实现的。要计算基础矩阵至少需要 8 个点(使用 8 点算法)。点越多越好,可以使用 RANSAC 算法得到更加稳定的结果。 340 | 341 | ### 2、代码实现 342 | 343 | 首先,我们需要在两个图像之间找到尽可能多的匹配,以找到基本矩阵。为此,我们使用SIFT描述符和基于FLANN的匹配器和比率测试。 344 | 345 | ```python 346 | import numpy as np 347 | import cv2 as cv 348 | from matplotlib import pyplot as plt 349 | 350 | img1 = cv.imread('myleft.jpg',0) #queryimage # left image 351 | img2 = cv.imread('myright.jpg',0) #trainimage # right image 352 | 353 | sift = cv.SIFT() 354 | 355 | # find the keypoints and descriptors with SIFT 356 | kp1, des1 = sift.detectAndCompute(img1,None) 357 | kp2, des2 = sift.detectAndCompute(img2,None) 358 | 359 | # FLANN parameters 360 | FLANN_INDEX_KDTREE = 1 361 | index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) 362 | search_params = dict(checks=50) 363 | 364 | flann = cv.FlannBasedMatcher(index_params,search_params) 365 | matches = flann.knnMatch(des1,des2,k=2) 366 | 367 | good = [] 368 | pts1 = [] 369 | pts2 = [] 370 | 371 | # ratio test as per Lowe's paper 372 | for i,(m,n) in enumerate(matches): 373 | if m.distance < 0.8*n.distance: 374 | good.append(m) 375 | pts2.append(kp2[m.trainIdx].pt) 376 | pts1.append(kp1[m.queryIdx].pt) 377 | ``` 378 | 379 | 现在我们有两张图片的最佳匹配列表。让我们找到基本矩阵。 380 | 381 | ```python 382 | pts1 = np.int32(pts1) 383 | pts2 = np.int32(pts2) 384 | F, mask = cv.findFundamentalMat(pts1,pts2,cv.FM_LMEDS) 385 | 386 | # We select only inlier points 387 | pts1 = pts1[mask.ravel()==1] 388 | pts2 = pts2[mask.ravel()==1] 389 | ``` 390 | 391 | 下一步我们要找到极线。我们会得到一个包含很多线的数组。所以我们要定义一个新的函数将这些线绘制到图像中。 392 | 393 | ```python 394 | def drawlines(img1,img2,lines,pts1,pts2): 395 | ''' img1 - image on which we draw the epilines for the points in img2 396 | lines - corresponding epilines ''' 397 | r,c = img1.shape 398 | img1 = cv.cvtColor(img1,cv.COLOR_GRAY2BGR) 399 | img2 = cv.cvtColor(img2,cv.COLOR_GRAY2BGR) 400 | for r,pt1,pt2 in zip(lines,pts1,pts2): 401 | color = tuple(np.random.randint(0,255,3).tolist()) 402 | x0,y0 = map(int, [0, -r[2]/r[1] ]) 403 | x1,y1 = map(int, [c, -(r[2]+r[0]*c)/r[1] ]) 404 | img1 = cv.line(img1, (x0,y0), (x1,y1), color,1) 405 | img1 = cv.circle(img1,tuple(pt1),5,color,-1) 406 | img2 = cv.circle(img2,tuple(pt2),5,color,-1) 407 | return img1,img2 408 | ``` 409 | 410 | 现在我们在两个图像中找到了极线并绘制它们。 411 | 412 | ```python 413 | # Find epilines corresponding to points in right image (second image) and 414 | # drawing its lines on left image 415 | lines1 = cv.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F) 416 | lines1 = lines1.reshape(-1,3) 417 | img5,img6 = drawlines(img1,img2,lines1,pts1,pts2) 418 | 419 | # Find epilines corresponding to points in left image (first image) and 420 | # drawing its lines on right image 421 | lines2 = cv.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F) 422 | lines2 = lines2.reshape(-1,3) 423 | img3,img4 = drawlines(img2,img1,lines2,pts2,pts1) 424 | 425 | plt.subplot(121),plt.imshow(img5) 426 | plt.subplot(122),plt.imshow(img3) 427 | plt.show() 428 | ``` 429 | 430 | 结果如下图所示; 431 | 432 | ![image8](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image8.jpg) 433 | 434 | 你可以在左侧图像中看到所有的极线都会聚合在右侧图像外部的一个点上,这个点就是极点。 435 | 436 | 为了得到更好的结果,我们应该使用分辨率比较高和很多非平面点的图像。 437 | 438 | ## 四、立体图像的深度图 439 | 440 | *** 441 | 442 | ### 目标: 443 | 444 | 本章节你需要学习以下内容: 445 | 446 | *我们将学习如何从立体图像创建深度图。 447 | 448 | ### 1、基础 449 | 450 | 在上一节中我们学习了对极约束的基本概念和相关术语。如果同一场景有两幅图像的话我们在直觉上就可以获得图像的深度信息。下面是的这幅图和其中的数学公式证明我们的直觉是对的。(图像来源 image courtesy) 451 | 452 | ![image9](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image9.jpg) 453 | 454 | 上图包含等效三角形。编写等效方程将产生以下结果: 455 | 456 | $$disparity = x - x' = \frac{Bf}{Z}$$ 457 | 458 | x 和 x' 分别是图像中的点到 3D 空间中的点和到摄像机中心的距离。B 是这两个摄像机之间的距离,f 是摄像机的焦距。上边的等式告诉我们点的深度与x 和 x' 的差成反比。所以根据这个等式我们就可以得到图像中所有点的深度图。 459 | 460 | 这样就可以找到两幅图像中的匹配点了。前面我们已经知道了对极约束可以使这个操作更快更准。一旦找到了匹配,就可以计算出 disparity 了。让我们看看在 OpenCV 中怎样做吧。 461 | 462 | ### 2、代码实现 463 | 464 | 下面的代码片段显示了创建视差图的简单过程。 465 | 466 | ```python 467 | import numpy as np 468 | import cv2 as cv 469 | from matplotlib import pyplot as plt 470 | 471 | imgL = cv.imread('tsukuba_l.png',0) 472 | imgR = cv.imread('tsukuba_r.png',0) 473 | 474 | stereo = cv.StereoBM_create(numDisparities=16, blockSize=15) 475 | disparity = stereo.compute(imgL,imgR) 476 | plt.imshow(disparity,'gray') 477 | plt.show() 478 | ``` 479 | 480 | 下图包含原始图像(左)及其视差图(右)。如图所见,结果受到高度噪音的污染。通过调整numDisparities和blockSize的值,你可以获得更好的结果。 481 | 482 | ![image10](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/7.Camera%20Calibration%20and%203D%20Reconstruction/Image/image10.jpg) -------------------------------------------------------------------------------- /8.Machine Learning/Image/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image1.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image10.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image11.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image12.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image13.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image14.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image15.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image16.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image17.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image2.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image3.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image4.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image5.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image6.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image7.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image8.jpg -------------------------------------------------------------------------------- /8.Machine Learning/Image/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/8.Machine Learning/Image/image9.jpg -------------------------------------------------------------------------------- /8.Machine Learning/README.md: -------------------------------------------------------------------------------- 1 | # 第八章:机器学习 2 | 3 | 本章节你将学习K-最邻近、支持向量机和K-Means聚类等OpenCV机器学习的相关内容。 4 | 5 | 更多内容请关注我的[GitHub库:TonyStark1997](https://github.com/TonyStark1997),如果喜欢,star并follow我! 6 | 7 | *** 8 | 9 | ## 一、K-最邻近 10 | 11 | *** 12 | 13 | ### 目标: 14 | 15 | 本章节你需要学习以下内容: 16 | 17 | *在本章中,我们将理解k-最近邻(kNN)算法的概念。 18 | *我们将使用我们在kNN上的知识来构建基本的OCR应用程序。 19 | *我们将尝试使用OpenCV附带的数字和字母数据。 20 | 21 | ### 1、了解k-最近邻 22 | 23 | #### (1)理论 24 | 25 | kNN是最简单的用于监督学习的分类算法之一。想法也很简单,就是找出测试数据在特征空间中的最近邻居。我们将用下图来介绍它。 26 | 27 | ![image1](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/8.Machine%20Learning/Image/image1.jpg) 28 | 29 | 上图中的对象可以分成两组,蓝色方块和红色三角。每一组也可以称为一个 类。我们可以把所有的这些对象看成是一个城镇中房子,而所有的房子分别属于蓝色和红色家族,而这个城镇就是所谓的特征空间。(你可以把一个特征空间看成是所有点的投影所在的空间。例如在一个 2D 的坐标空间中,每个数据都两个特征 x 坐标和 y 坐标,你可以在 2D 坐标空间中表示这些数据。如果每个数据都有 3 个特征呢,我们就需要一个 3D 空间。N 个特征就需要 N 维空间,这个 N 维空间就是特征空间。在上图中,我们可以认为是具有两个特征色2D 空间)。 30 | 31 | 现在城镇中来了一个新人,他的新房子用绿色圆盘表示。我们要根据他房子的位置把他归为蓝色家族或红色家族。我们把这过程成为 分类。我们应该怎么做呢?因为我们正在学习看 kNN,那我们就使用一下这个算法吧。 32 | 33 | 一个方法就是查看他最近的邻居属于那个家族,从图像中我们知道最近的是红色三角家族。所以他被分到红色家族。这种方法被称为简单 近邻,因为分类仅仅决定与它最近的邻居。 34 | 35 | 但是这里还有一个问题。红色三角可能是最近的,但如果他周围还有很多蓝色方块怎么办呢?此时蓝色方块对局部的影响应该大于红色三角。所以仅仅检测最近的一个邻居是不足的。所以我们检测 k 个最近邻居。谁在这 k 个邻居中占据多数,那新的成员就属于谁那一类。如果 k 等于 3,也就是在上面图像中检测 3 个最近的邻居。他有两个红的和一个蓝的邻居,所以他还是属于红色家族。但是如果 k 等于 7 呢?他有 5 个蓝色和 2 个红色邻居,现在他就会被分到蓝色家族了。k 的取值对结果影响非常大。更有趣的是,如果 k 等于 4呢?两个红两个蓝。这是一个死结。所以 k 的取值最好为奇数。这中根据 k 个最近邻居进行分类的方法被称为 kNN。 36 | 37 | 在 kNN 中我们考虑了 k 个最近邻居,但是我们给了这些邻居相等的权重,这样做公平吗?以 k 等于 4 为例,我们说她是一个死结。但是两个红色三角比两个蓝色方块距离新成员更近一些。所以他更应该被分为红色家族。那用数学应该如何表示呢?我们要根据每个房子与新房子的距离对每个房子赋予不同的权重。距离近的具有更高的权重,距离远的权重更低。然后我们根据两个家族的权重和来判断新房子的归属,谁的权重大就属于谁。这被称为 修改过的kNN。 38 | 39 | 那么你在这里看到的重要事情是什么? 40 | 41 | * 我们需要整个城镇中每个房子的信息。因为我们要测量新来者到所有现存房子的距离,并在其中找到最近的。如果那里有很多房子,就要占用很大的内存和更多的计算时间。 42 | 43 | * 训练和处理几乎不需要时间。 44 | 45 | 现在让我们在OpenCV中看到它。 46 | 47 | #### (2)OpenCV中的K-最邻近 48 | 49 | 我们这里来举一个简单的例子,和上面一样有两个类。下一节我们会有一个更好的例子。 50 | 51 | 这里我们将红色家族标记为 Class-0,蓝色家族标记为 Class-1。还要再创建 25 个训练数据,把它们非别标记为 Class-0 或者 Class-1。Numpy中随机数产生器可以帮助我们完成这个任务。 52 | 53 | 然后借助 Matplotlib 将这些点绘制出来。红色家族显示为红色三角蓝色家族显示为蓝色方块。 54 | 55 | ```python 56 | import cv2 as cv 57 | import numpy as np 58 | import matplotlib.pyplot as plt 59 | 60 | # Feature set containing (x,y) values of 25 known/training data 61 | trainData = np.random.randint(0,100,(25,2)).astype(np.float32) 62 | 63 | # Labels each one either Red or Blue with numbers 0 and 1 64 | responses = np.random.randint(0,2,(25,1)).astype(np.float32) 65 | 66 | # Take Red families and plot them 67 | red = trainData[responses.ravel()==0] 68 | plt.scatter(red[:,0],red[:,1],80,'r','^') 69 | 70 | # Take Blue families and plot them 71 | blue = trainData[responses.ravel()==1] 72 | plt.scatter(blue[:,0],blue[:,1],80,'b','s') 73 | 74 | plt.show() 75 | ``` 76 | 77 | 你可能会得到一个与上面类似的图形,但不会完全一样,因为你使用了随机数产生器,每次你运行代码都会得到不同的结果。 78 | 79 | 下面就是 kNN 算法分类器的初始化,我们要传入一个训练数据集,以及与训练数据对应的分类来训练 kNN 分类器(构建搜索树)。 80 | 81 | 最后要使用 OpenCV 中的 kNN 分类器,我们给它一个测试数据,让它来进行分类。在使用 kNN 之前,我们应该对测试数据有所了解。我们的数据应该是大小为数据数目乘以特征数目的浮点性数组。然后我们就可以通过计算找到测试数据最近的邻居了。我们可以设置返回的最近邻居的数目。返回值包括: 82 | 83 | 1. 由 kNN 算法计算得到的测试数据的类别标志(0 或 1)。如果你想使用最近邻算法,只需要将 k 设置为 1,k 就是最近邻的数目。 84 | 85 | 2. k 个最近邻居的类别标志。 86 | 87 | 3. 每个最近邻居到测试数据的距离。 88 | 89 | 让我们看看它是如何工作的。测试数据被标记为绿色。 90 | 91 | ```python 92 | newcomer = np.random.randint(0,100,(1,2)).astype(np.float32) 93 | plt.scatter(newcomer[:,0],newcomer[:,1],80,'g','o') 94 | 95 | knn = cv.ml.KNearest_create() 96 | knn.train(trainData, cv.ml.ROW_SAMPLE, responses) 97 | ret, results, neighbours ,dist = knn.findNearest(newcomer, 3) 98 | 99 | print( "result: {}\n".format(results) ) 100 | print( "neighbours: {}\n".format(neighbours) ) 101 | print( "distance: {}\n".format(dist) ) 102 | 103 | plt.show() 104 | ``` 105 | 106 | 我得到的结果如下: 107 | 108 | ```python 109 | result: [[ 1.]] 110 | neighbours: [[ 1. 1. 1.]] 111 | distance: [[ 53. 58. 61.]] 112 | ``` 113 | 114 | 这说明我们的测试数据有 3 个邻居,他们都是蓝色,所以它被分为蓝色家族。结果很明显,如下图所示: 115 | 116 | ![image2](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/8.Machine%20Learning/Image/image2.jpg) 117 | 118 | 如果我们有大量的数据要进行测试,可以直接传入一个数组。对应的结果同样也是数组。 119 | 120 | ```python 121 | # 10 new comers 122 | newcomers = np.random.randint(0,100,(10,2)).astype(np.float32) 123 | ret, results,neighbours,dist = knn.findNearest(newcomer, 3) 124 | # The results also will contain 10 labels. 125 | ``` 126 | 127 | ### 2、使用kNN对手写数据进行OCR 128 | 129 | #### (1)使用 kNN 对手写数字 OCR 130 | 131 | 我们的目的是创建一个可以对手写数字进行识别的程序。为了达到这个目的我们需要训练数据和测试数据。OpenCV附带一个images digits.png(在文件夹opencv/samples/data/中),其中有 5000 个手写数字(每个数字重复 500遍)。每个数字是一个 20x20 的小图。所以第一步就是将这个图像分割成 5000个不同的数字。我们在将拆分后的每一个数字的图像重排成一行含有 400 个像素点的新图像。这个就是我们的特征集,所有像素的灰度值。这是我们能创建的最简单的特征集。我们使用每个数字的前 250 个样本做训练数据,剩余的250 个做测试数据。让我们先准备一下: 132 | 133 | ```python 134 | import numpy as np 135 | import cv2 as cv 136 | from matplotlib import pyplot as plt 137 | 138 | img = cv.imread('digits.png') 139 | gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 140 | 141 | # Now we split the image to 5000 cells, each 20x20 size 142 | cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)] 143 | 144 | # Make it into a Numpy array. It size will be (50,100,20,20) 145 | x = np.array(cells) 146 | 147 | # Now we prepare train_data and test_data. 148 | train = x[:,:50].reshape(-1,400).astype(np.float32) # Size = (2500,400) 149 | test = x[:,50:100].reshape(-1,400).astype(np.float32) # Size = (2500,400) 150 | 151 | # Create labels for train and test data 152 | k = np.arange(10) 153 | train_labels = np.repeat(k,250)[:,np.newaxis] 154 | test_labels = train_labels.copy() 155 | 156 | # Initiate kNN, train the data, then test it with test data for k=1 157 | knn = cv.ml.KNearest_create() 158 | knn.train(train, cv.ml.ROW_SAMPLE, train_labels) 159 | ret,result,neighbours,dist = knn.findNearest(test,k=5) 160 | 161 | # Now we check the accuracy of classification 162 | # For that, compare the result with test_labels and check which are wrong 163 | matches = result==test_labels 164 | correct = np.count_nonzero(matches) 165 | accuracy = correct*100.0/result.size 166 | print( accuracy ) 167 | ``` 168 | 169 | 现在最基本的 OCR 程序已经准备好了,这个示例中我们得到的准确率为91%。改善准确度的一个办法是提供更多的训练数据,尤其是判断错误的那些数字。为了避免每次运行程序都要准备和训练分类器,我们最好把它保留,这样在下次运行是时,只需要从文件中读取这些数据开始进行分类就可以了。 170 | Numpy 函数 np.savetxt,np.load 等可以帮助我们搞定这些。 171 | 172 | ```python 173 | # save the data 174 | np.savez('knn_data.npz',train=train, train_labels=train_labels) 175 | 176 | # Now load the data 177 | with np.load('knn_data.npz') as data: 178 | print( data.files ) 179 | train = data['train'] 180 | train_labels = data['train_labels'] 181 | ``` 182 | 183 | 在我的系统中,占用的空间大概为 4.4M。由于我们现在使用灰度值(unint8)作为特征,在保存之前最好先把这些数据装换成 np.uint8 格式,这样就只需要占用 1.1M 的空间。在加载数据时再转会到 float32。 184 | 185 | #### (2)英文字母的 OCR 186 | 187 | 接下来我们来做英文字母的 OCR。和上面做法一样,但是数据和特征集有一些不同。现在 OpenCV 给出的不是图片了,而是一个数据文件(/samples/cpp/letter-recognition.data)。如果打开它的话,你会发现它有 20000 行,第一样看上去就像是垃圾。实际上每一行的第一列是我们的一个字母标记。接下来的 16 个数字是它的不同特征。这些特征来源于UCI Machine LearningRepository。你可以在此页找到更多相关信息。 188 | 189 | 有 20000 个样本可以使用,我们取前 10000 个作为训练样本,剩下的10000 个作为测试样本。我们应在先把字母表转换成 asc 码,因为我们不正直接处理字母。 190 | 191 | ```python 192 | import cv2 as cv 193 | import numpy as np 194 | import matplotlib.pyplot as plt 195 | 196 | # Load the data, converters convert the letter to a number 197 | data= np.loadtxt('letter-recognition.data', dtype= 'float32', delimiter = ',', 198 | converters= {0: lambda ch: ord(ch)-ord('A')}) 199 | 200 | # split the data to two, 10000 each for train and test 201 | train, test = np.vsplit(data,2) 202 | 203 | # split trainData and testData to features and responses 204 | responses, trainData = np.hsplit(train,[1]) 205 | labels, testData = np.hsplit(test,[1]) 206 | 207 | # Initiate the kNN, classify, measure accuracy. 208 | knn = cv.ml.KNearest_create() 209 | knn.train(trainData, cv.ml.ROW_SAMPLE, responses) 210 | ret, result, neighbours, dist = knn.findNearest(testData, k=5) 211 | 212 | correct = np.count_nonzero(result == labels) 213 | accuracy = correct*100.0/10000 214 | print( accuracy ) 215 | ``` 216 | 217 | 准确率达到了 93.22%。同样你可以通过增加训练样本的数量来提高准确率。 218 | 219 | ## 二、支持向量机 220 | 221 | *** 222 | 223 | ### 目标: 224 | 225 | 本章节你需要学习以下内容: 226 | 227 | *我们将看到对SVM的直观理解 228 | *我们将重新访问手写数据OCR,但是,使用SVM而不是kNN。 229 | 230 | ### 1、了解SVM 231 | 232 | 233 | 234 | ### 2、使用SVM对手写数据进行OCR 235 | 236 | 237 | 238 | ## 三、K-Means聚类 239 | 240 | *** 241 | 242 | ### 目标: 243 | 244 | 本章节你需要学习以下内容: 245 | 246 | *在本章中,我们将了解K-Means聚类的概念,它是如何工作的等等。 247 | *学习在OpenCV中使用cv.kmeans()函数进行数据聚类 248 | 249 | ### 1、了解K-Means聚类 250 | 251 | 252 | 253 | ### 2、在OpenCV中的K-Means聚类 254 | -------------------------------------------------------------------------------- /9.Computational Photography/README.md: -------------------------------------------------------------------------------- 1 | # OpenCV-Python 2 | The Opencv-Python tutorial Chinese translation 3 | *** 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![image](https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/master/image.png)OpenCV-Python 2 | The Opencv-Python tutorial Chinese translation 3 | *** 4 | 这个库的建立目的在于翻译[OpenCV-Python Tutorials](https://docs.opencv.org/3.4.1/d6/d00/tutorial_py_root.html),[OpenCV-Python Tutorials](https://docs.opencv.org/3.4.1/d6/d00/tutorial_py_root.html)是OpenCV官方的Python实现教程。 5 | 6 | 本人现 在读大二,也是刚刚开始学习OpenCV,刚刚开始时一直感觉无从下手,找到了官方文档之后发现内容非常翔实,完全不需要在市面上买OpenCV的各种指南书各种教程,只学习这个官方教程就完全足够了,唯一的缺点就是没有中文版。虽然说程序员的必备技能就是可以阅读英文文档,但是对于一些英语水平不足的爱好者却成为了入门OpenCV的最大困难。本人学识尚浅,英语也是我最大的软肋,所以我想在学习OpenCV的过程中顺便翻译一下这本官方教程,一是可以提高自己的英语水平和对于英文的阅读能力,二是可以为一些因为各种原因而阅读英文文档困难的OpenCV爱好者们或者年龄较小英语水平不够却对计算机视觉感兴趣小伙伴们提供一些便利,三是希望大家一起学习OpenCV,一起提高英语水平和Python编程水平。 7 | 8 | 这个GitHub库将全文翻译OpenCV-Python Tutorials 3.4.1版本的教程,这也是目前为止官方发布的最新版本库,之后随着OpenCV库的不断更新,这个库也会做相应的更新翻译。[OpenCV-Python Tutorials](https://docs.opencv.org/3.4.1/d6/d00/tutorial_py_root.html)全文包括以下十一个章节和一个附录,我将分成十二个文件夹陆续进行翻译: 9 | 10 | #### [Introduction to OpenCV](https://docs.opencv.org/3.4.1/da/df6/tutorial_py_table_of_contents_setup.html) #OpenCV简介 11 | * 本章节将介绍如何在不同系统平台安装配置OpenCV。 12 | 13 | #### [Gui Features in OpenCV](https://docs.opencv.org/3.4.1/dc/d4d/tutorial_py_table_of_contents_gui.html) #OpenCV中的Gui相关功能 14 | * 本章节你将学习如何显示和保存图像和视频、控制鼠标事件和创建轨迹栏。 15 | 16 | #### [Core Operations](https://docs.opencv.org/3.4.1/d7/d16/tutorial_py_table_of_contents_core.html) #OpenCV核心操作 17 | * 本章节你将学习图像的基本操作,如像素编辑、几何变换、代码优化和一些数学工具等。 18 | 19 | #### [Image Processing in OpenCV](https://docs.opencv.org/3.4.1/d2/d96/tutorial_py_table_of_contents_imgproc.html) #OpenCV中的图像处理 20 | * 本章节你将学习不同的图像处理功能。 21 | 22 | #### [Feature Detection and Description](https://docs.opencv.org/3.4.1/db/d27/tutorial_py_table_of_contents_feature2d.html) #特征检测和描述 23 | * 本章节中你将了解功能检测器和描述符。 24 | 25 | #### [Video Analysis](https://docs.opencv.org/3.4.1/d3/db0/tutorial_py_table_of_contents_video.html) #视频分析 26 | * 本章节中你将学习使用对象跟踪的视频的不同操作技巧。 27 | 28 | #### [Camera Calibration and 3D Reconstruction](https://docs.opencv.org/3.4.1/d9/db7/tutorial_py_table_of_contents_calib3d.html) #相机校准和3D重建 29 | * 本章节中你将了解相机校准和立体图像成像等。 30 | 31 | #### [Machine Learning](https://docs.opencv.org/3.4.1/d6/de2/tutorial_py_table_of_contents_ml.html) #机器学习 32 | * 本章节中你将学习如何用机器学习相关知识处理图像的功能。 33 | 34 | #### [Computational Photography](https://docs.opencv.org/3.4.1/d0/d07/tutorial_py_table_of_contents_photo.html) #计算摄影技术 35 | * 本章节中你将学习不同的计算摄影技术,如图像去噪等。 36 | 37 | #### [Object Detection](https://docs.opencv.org/3.4.1/d9/de5/tutorial_py_table_of_contents_objdetect.html) #物体检测 38 | * 本章节中你将学习对象检测技术,如人脸识别等。 39 | 40 | #### [penCV-Python Bindings](https://docs.opencv.org/3.4.1/df/da2/tutorial_py_table_of_contents_bindings.html) #OpenCV-Pyhon绑定 41 | * 本章节中你将了解如何生成OpenCV-Python绑定的。 42 | 43 | #### Appendix #附录一 44 | * 附录一将列出OpenCV-Python的所有教程中出现的Python类和函数的详细解释等 45 | 46 | *** 47 | 再一次说明,本人学识尚浅,学习OpenCV并没有多长时间,并且英语水平自认为不是很强,所以请希望广大阅读者多多包含,任何关于翻译和理解上的错误请及时对我批评指正,防止误导他人学习。希望大家可以一起学习OpenCV、一起提高阅读英文文档的水平。本库的文章将同步发表到我的CSDN上,方便大家阅读。 48 | 49 | 同时重申一下,本库请勿用于各种商业用途,如需转载请先联系作者,希望大家重视一下版权和作者的辛苦和用意,谢谢! 50 | -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyStark1997/OpenCV-Python/bd37f826349137d851c3a3b11741a2cfb640b26c/image.png --------------------------------------------------------------------------------