一、介绍
OpenCV(open source computer vision library)是一个基于BSD许可(开源)发行的跨平台计算机视觉库,它实现了图像处理和计算机视觉方面的很多通用算法,已成为计算机视觉领域最有力的研究工具。在这里我们要区分两个概念:图像处理和计算机视觉的区别:图像处理侧重于“处理”图像–如增强,还原,去噪,分割等等;而计算机视觉重点在于使用计算机来模拟人的视觉,因此模拟才是计算机视觉领域的最终目标。可以运行在Linux、Windows、Android和Mac OS操作系统上。
在计算机视觉项目的开发中,OpenCV作为较大众的开源库,拥有了丰富的常用图像处理函数库,采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上,能够快速的实现一些图像处理和识别的任务。
此外,OpenCV还提供了Java、python、cuda等的使用接口、机器学习的基础算法调用,从而使得图像处理和图像分析变得更加易于上手,让开发人员更多的精力花在算法的设计上。
————————————————
发展史
1 1.1 OpenCV发展历史 2 OpenCV于1999年由Intel建立,如今由Willow Garage公司提供支持。 3 4 OpenCV 0.X 5 1999年1月,CVL项目启动。主要目标是人机界面,能被UI调用的实时计算机视觉库,为Intel处理器做了特定优化。 6 2000年6月,第一个开源版本OpenCV alpha 3发布。 7 2000年12月,针对linux平台的OpenCV beta 1发布。 8 9 OpenCV 1.X 10 OpenCV 最初基于C语言开发,API也都是基于C的,面临内存管理、指针等C语言固有的麻烦。 11 2006年10月, 正式发布OpenCV 1.0版本,同时支持mac os系统和一些基础的机器学习方法,如神经网络、随机森林等,来完善对图像处理的支持。 12 2009年9月,OpenCV 1.2(beta2.0)发布。 13 14 OpenCV 2.X 15 当C++流行起来,OpenCV 2.x发布,其尽量使用C++而不是C,但是为了向前兼容,仍保留了对C API的支持。 16 2009年9月2.0 beta发布,主要使用CMake构建。 17 2010年3月:2.1发布 18 2010年12月6日,OpenCV 2.2发布 19 2011年8月,OpenCV 2.3发布。 20 2012年4月2日,发布OpenCV 2.4. 21 22 OpenCV 3.X 23 随着3.x的发布,1.x的C API将被淘汰不再被支持,以后C API可能通过C++源代码自动生成。3.x与2.x不完全兼容,与2.x相比,主要的不同之处在于OpenCV 3.x 的大部分方法都使用了OpenCL加速。 24 2014年8月, 3.0 alpha发布,除大部分方法都使用OpenCL加速外,3.x默认包含以及使用IPP(一套跨平台的软件函数库) 25 2017年8月,发布3.3版本,OpenCV开始支持C++ 11构建,同时加强对神经网络的支持。 26 OpenCV 4.X 27 2018年10月4.0.0发布,OpenCV开始需要支持C++11的编译器才能编译,同时对几百个基础函数使用"wide universal intrinsics"重写,极大改善了opencv处理图像的性能。
二、编译环境
直接pip安装
pip install opencv-python
注意:
1.安装的是opencv_python,但在导入的时候是import cv2。
2.OpenCV依赖一些库,比如Numpy和matplotlib,先安装上。
三、图像基本操作
3.1 图像读取(cv.imread())与显示(cv.imshow() )以及保存(cv.imwrite())
1 import cv2 2 import matplotlib.pyplot as plt 3 import numpy as np 4 5 # 读取图像,这个函数返回图像数据,它是一个NumPy数组。 6 image =cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\1.jpg') 7 8 # 显示图像 9 #cvtColor函数将图像从BGR颜色空间转换到RGB颜色空间。cv2.COLOR_BGR2RGB是转换的指定代码。 10 plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) 11 # 如果命名为为中文,需要转码 12 plt.title('boy') 13 plt.axis('off') 14 plt.show()
----------------------------------------
ps:即使图像路径错误,它也不会抛出任何错误,但是打印 img
会返回None
保存图片
1 import cv2 as cv 2 import os 3 4 print("当前工作目录:", os.getcwd()) 5 img = cv.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\9.png', 0) 6 cv.imshow('img', img) 7 k = cv.waitKey(0) 8 if k == 27: # ESC 退出 9 cv.destroyAllWindows() 10 elif k == ord('s'): # 's' 保存退出 11 cv.imwrite(r'C:\Users\19225\PycharmProjects\test\src\user\static\new.png', img) 12 cv.destroyAllWindows()
3.2学习OpenCV中常见的图像操作,如调整大小、裁剪、旋转等。
1 image =cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\1.jpg') 2 3 # 这里展示了如何调整图像大小和进行裁剪 4 resized_image = cv2.resize(image, (1000, 2000)) 5 cropped_image = image[50:150, 50:250] 6 7 # 显示调整前的图像 8 plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB)) 9 plt.title('Resized Image') 10 plt.axis('off') 11 plt.show() 12 13 # 显示裁剪后的图像 14 plt.imshow(cv2.cvtColor(cropped_image, cv2.COLOR_BGR2RGB)) 15 plt.title('Cropped Image') 16 plt.axis('off') 17 plt.show()
3.3学习使用OpenCV进行边缘检测,掌握Canny边缘检测算法。
1 image=cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\1.jpg') 2 # 这里展示了如何使用Canny算法进行边缘检测 3 edges = cv2.Canny(image, 100, 200) 4 ''' 5 这行代码使用OpenCV的Canny函数进行边缘检测。Canny算法是一种非常流行的边缘检测算法,因为它能够很好地在噪声抑制和边缘检测之间取得平衡。 6 该算法接受两个阈值参数(这里是100和200)来控制边缘检测的灵敏度。 7 较低的阈值用于捕获较弱的边缘,而较高的阈值则用于最终边缘检测中需要更强边缘响应的场合。 8 在Canny算法中,还会用到一种双阈值方法来检测强边缘和潜在的弱边缘,并通过强边缘来连接潜在的弱边缘,从而形成最终的边缘图像。 9 ''' 10 # 显示边缘检测结果 11 plt.imshow(edges, cmap='gray') 12 plt.title('Edge Detection') 13 plt.axis('off') 14 plt.show() 15 16 17 -------------------------- 18 什么边缘检测 19 边缘检测是计算机视觉和图像处理中的一个基本步骤,它旨在识别图像中亮度变化明显的点。这些点通常对应于物体的边界,在图像中形成了物体的轮廓。边缘检测对于后续的图像分析、图像分割、特征提取等任务非常重要。通过边缘检测,我们可以从图像中提取出重要的结构信息,这些信息对于理解图像内容、进行目标识别等任务非常有用。
3.4学习如何使用OpenCV拼接图像---Numpy (np.hstack,np.vstack)
只是简单地将几张图像直接堆叠而连成一张图像,并未对图像进行特征提取和边缘处理,因而并不能实现图像的全景拼接。
1 retval = np.hstack(tup) # 水平拼接 2 retval = np.vstack(tup) # 垂直拼接 3 4 5 ----------------------- 6 代码示例 7 # 读取要拼接的图片 8 img = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\4.jpg') 9 #调整图像大小 10 img = cv2.resize(img, None, fx=0.5, fy=0.5) # 为了完整显示,缩小一倍 11 blur2 = cv2.blur(img, (2, 2)) # 模糊处理 12 blur3 = cv2.blur(img, (5, 5)) 13 blur4 = cv2.blur(img, (10, 10)) 14 15 htich = np.hstack((img, blur2)) 16 htich2 = np.hstack((blur3, blur4)) 17 vtich = np.vstack((htich, htich2)) 18 19 # 显示图片 20 cv2.imshow("mergedDemo", vtich) 21 cv2.waitKey(0) 22 cv2.destroyAllWindows()
方式二:matplotlib
注意:opencv使用的是BGR
模式,而matplotlib使用的是RGB
模式,所以需要将opencv中的BGR、GRAY格式转换为RGB,使matplotlib中能正常显示opencv的图像。
1 img1 = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\4.jpg', cv2.IMREAD_COLOR) # 以彩色模式读取图片。这是默认模式 2 img2 = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\5.jpg', cv2.IMREAD_GRAYSCALE) # 以灰度模式读取图片 3 img3 = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\6.jpg', 4 cv2.IMREAD_UNCHANGED) # 包括alpha通道的完整图片将被读取 5 img4 = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\3.jpg', cv2.IMREAD_ANYDEPTH) # 读取图片,无论其深度如何 6 # 将opencv中的BGR、GRAY格式转换为RGB,使matplotlib中能正常显示opencv的图像 7 img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB) 8 img2 = cv2.cvtColor(img2, cv2.COLOR_GRAY2RGB) 9 img3 = cv2.cvtColor(img3, cv2.COLOR_BGR2RGB) 10 img4 = cv2.cvtColor(img4, cv2.COLOR_BGR2RGB) 11 plt.rcParams['font.sans-serif'] = ['FangSong'] # 支持中文标签 12 # 使用matplotlib的plt.subplot()和plt.imshow()函数将转换后的图片显示在一个2x2的子图网格中 13 plt.subplot(221), plt.title("img1"), plt.axis('off') 14 plt.imshow(img1) 15 plt.rcParams['font.sans-serif'] = ['FangSong'] # 支持中文标签 16 plt.subplot(222), plt.title("img2"), plt.axis('off') 17 plt.imshow(img2) 18 plt.rcParams['font.sans-serif'] = ['FangSong'] # 支持中文标签 19 plt.subplot(223), plt.title("img3"), plt.axis('off') 20 plt.imshow(img3) 21 plt.rcParams['font.sans-serif'] = ['FangSong'] # 支持中文标签 22 plt.subplot(224), plt.title("img4"), plt.axis('off') 23 plt.imshow(img4) 24 plt.show()
3.5图像打马赛克
1 import cv2 2 import numpy as np 3 4 # 图像打码示例 5 censored_image = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\2.jpg') 6 censored_image[100:200, 200:300] = np.random.randint(0, 256, (100, 100, 3)) 7 cv2.imshow('Censored Image', censored_image) 8 cv2.waitKey(0) 9 cv2.destroyAllWindows()
3.6 图像组合示例
1 import cv2 2 3 4 # 图像组合示例 5 image_a = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\2.jpg') 6 image_b = cv2.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\3.jpg') 7 image_a[200:300, 300:500] = image_b[300:400, 500:700] 8 cv2.imshow('Combined Image', image_a) 9 cv2.waitKey(0) 10 cv2.destroyAllWindows()
3.7 图像加法
我们可以通过 OpenCV 函数,cv.add()或简单地通过 numpy 操作将两个图像相加,res = img1 + img2。两个图像应该具有相同的深度和类型,或者第二个图像可以是像素值,比如(255,255,255),白色值。
注意 OpenCV 相加操作和 Numpy 相加操作之间存在差异。OpenCV 添加是饱和操作,而 Numpy 添加是模运算。要注意的是,两种加法对于结果溢出的数据,会通过某种方法使其在限定的数据范围内。
1 import numpy as np 2 import cv2 as cv 3 4 x = np.uint8([250]) 5 y = np.uint8([10]) 6 7 print(cv.add(x, y)) # 250 + 10 =260 => 255 8 9 print(x + y) # [4] 10 """ 11 对于结果怎么样得到的: 12 1.print(cv.add(x, y)): 13 cv.add()是 OpenCV 中的函数,用于对两个图像或数组进行加法操作。 14 这里 x = np.uint8([250]) 和 y = np.uint8([10]),都是无符号 8 位整数类型的数组。 15 当进行 250 + 10 的计算时,结果是 260。但是由于无符号 8 位整数的取值范围是 0 到 255,所以 260 超出了这个范围。在这种情况下,OpenCV 的 cv.add() 函数会将结果截断为 255。 16 17 2.print(x + y): 18 这里是使用 Python 的原生数组加法操作。 19 同样进行 250 + 10 的计算得到 260。但是对于无符号 8 位整数类型,当超出 255 的范围时,会发生溢出并从 0 重新开始计数。所以 260 - 256 = 4,最终结果为 [4]。 20 """
图像混合(cv.addWeighted())
这也是将图像相加,但是对图像赋予不同的权重,从而给出混合感或透明感
通过在(0,1)之间改变的值, 可以用来对两幅图像或两段视频产生时间上的 画面叠化 (cross-dissolve)效果,就像在幻灯片放映和电影制作中那样
1 import cv2 as cv 2 3 img1 = cv.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\6.jpg') 4 img2 = cv.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\5.jpg') 5 6 dst = cv.addWeighted(img1, 0.7, img2, 0.3, 0) 7 8 cv.imshow('dst', dst) 9 cv.waitKey(0) 10 cv.destroyAllWindows()
性能测量和改进技术
在图像处理中,由于我们每秒需要处理大量操作,因此我们的代码不仅要提供正确的解决方案,还要以最快的方式提供,函数:cv.getTickCount, cv.getTickFrequency
cv.getTickCount函数返回参考事件(如机器开启时刻)到调用此函数的时钟周期数。因此,如果在函数执行之前和之后调用它,则会获得用于执行函数的时钟周期数
cv.getTickFrequency函数返回时钟周期的频率,或每秒钟的时钟周期数。因此,要在几秒钟内找到执行时间
1 import cv2 as cv 2 from cffi.backend_ctypes import xrange 3 4 img1 = cv.imread(r'C:\Users\19225\PycharmProjects\test\src\user\static\6.jpg') 5 e1 = cv.getTickCount() 6 for i in xrange(5, 49, 2): 7 img1 = cv.medianBlur(img1, i) 8 e2 = cv.getTickCount() 9 t = (e2 - e1) / cv.getTickFrequency() 10 print(t) # 2.6559413 11