一、OpenCV简介
OpenCV是应用广泛的开源图像处理库,我们以其为基础,介绍相关的图像处理方法:
-
包括基本的图像处理方法:几何变换,形态学变换,图像平滑,直方图操作,模板匹配,霍夫变换等;
-
特征提取和描述方法:理解角点特征,Harris 和Shi-Tomas 算法,SIFT/SURF 算法,Fast 算法,ORB算法等;
-
还有OpenCV 在视频操作中的应用,最后的案例是使用OpenCV进行人脸检测。
OpenCV 的应用领域
OpenCV 的应用领域非常广泛,涵盖了计算机视觉的各个方面,例如:
- 图像处理: 图像滤波、图像增强、图像分割、图像特征提取等。
- 视频分析: 目标跟踪、运动检测、行为识别等。
- 物体识别: 人脸识别、车牌识别、物体识别等。
- 机器学习: 支持向量机、K 均值聚类、神经网络等。
- 深度学习: 图像分类、目标检测、图像分割等。
- 增强现实: 虚拟物体叠加、手势识别等。
- 机器人: 视觉导航、目标抓取等。
应用场景
- 人脸识别与检测: 利用图像中人脸的特征进行身份验证,应用于安全系统、社交媒体和照片管理等领域。
- 物体检测与跟踪: 在监控、无人驾驶、工业检测等场景中,通过检测和跟踪目标物体来进行分析。
- 增强现实(AR): 将虚拟信息叠加到现实世界的图像中,广泛应用于游戏、医疗、工业等领域。
- 医疗图像分析: 使用 OpenCV 分析医学图像(如 CT 扫描、MRI 图像)来帮助诊断疾病。
- 机器人视觉: 机器人通过视觉识别环境,进行物体操作、导航等任务。
- 无人驾驶: 在自动驾驶中,OpenCV 被用于车道检测、交通标志识别、障碍物检测等任务。
OpenCV 的未来发展
随着人工智能和计算机视觉技术的快速发展,OpenCV 也在不断更新和完善。未来,OpenCV 将会在以下几个方面继续发展:
- 深度学习: 进一步加强对深度学习的支持,提供更多的预训练模型和算法。
- 移动端: 优化 OpenCV 在移动端的性能,使其更适合移动应用开发。
- 云计算: 提供基于云计算的计算机视觉服务,方便用户进行大规模图像和视频处理。
1.1 图像处理简介
1.1.1 图像是什么
图像是人类视觉的基础,是自然景物的客观反映,人类认识世界和人类本身的重要源泉。"图"是物体反射或透射光的分布,"像"是人的视觉系统所接受的图在人脑中所形版的印象或认识,照片、绘画、剪贴画、地图、书法作品、手写汉学、传真、卫星云图、影视画面、X光片、脑电图、心电图等都是图像。一姚敏.数字图像处理:机械工业出版社,2014年。
1.1.2 模拟图像和数字图像
图像起源于1826年前后法国科学家JosephNicephoreNiepce发明的第一张可永久保存的照片,属于模拟图像。模拟图像又称连续图像,它通过某种物理量(如光、电等)的强弱变来记录图像亮度信息,所以是连续变换的。模拟信号的特点是容易受干扰,如今已经基本全面被数字图像替代。
在第一次世界大战后,1921年美国科学家发明了BartlaneSystem,并从伦敦传到纽约传输了第一幅数字图像,其亮度用离散数值表示,将图片编码成5个灰度级,如下图所示,通过海底电缆进行传输。在发送端图片被编码并使用打孔带记录,通过系统传输后在接收方使用特殊的打印机恢复成图像。

1950年左右,计算机被发明,数字图像处理学科正式诞生。模拟图像和数字图像的对比,我们可以看一下:
1.1.3 数字图像的表示
(1) 位数
计算机采用0/1编码的系统,数字图像也是利用0/1来记录信息,我们平常接触的图像都是8位数图像,包含0~255灰度,其中0,代表最黑,1,表示最白。
人眼对灰度更敏感一些,在16位到32位之间。
(2) 图像的分类
二值图像:
一幅二值图像的二维矩阵仅由0、1两个值构成,"0"代表黑色,"1"代白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。
灰度图:
每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;但是,灰度图像在黑色与白色之间还有许多级的颜色深度。灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,用于显示的灰度图像通常用每个采样像素8位的非线性尺度来保存,这样可以有256级灰度(如果用16位,则有65536级)。
彩色图:
每个像素通常是由红(R)、绿(G)、蓝(B)三个分量来表示的,分量介于(0,255)。RGB图像与索引I图像一样都可以用来表示彩色图像。与索引I图像一样,它分别用红(R)、绿(G)、蓝(B)三原色的组合来表示每个像素的颜色。但与索引I图像不同的是,RGB图像每一个像素的颜色值(由RGB三原色表示)直接存放在图像矩阵中,由于每一像素的颜色需由R、G、B三个分量来表示,M、N分别表示图像的行列数,三个M×N的二维矩阵分别表示各个像素的R、G、B三个颜色分量。RGB图像的数据类型一般为8位无符号整形,通常用于表示和存放真彩色图像。
总结
- 图像是什么?
图:物体反射或投射光的分布
像:人的视觉系统所接受的图在人脑中所形成的印象或认识
- 模拟图像和数字图像
模拟图像:连续存储的图像
数字图像:分级存储的图像
- 数字图像
位数:图像的表示,常见的就是8位
分类:二值图像,灰度图像和彩色图像
1.2 OpenCV简介及安装方法
OpenCV是一款由Intel公司俄罗斯团队发起并参与和维护的一个计算机视觉处理开源软件库,支持与计算机视觉和机器学习相关的众多算法,并且正在日益扩展。
OpenCV的优势:
1. 编程语言
OpenCV基于C++实现,同时提供python, Ruby, Matlab等语言的接口。OpenCV-Python是OpenCV的Python API,结合了OpenCV C++APi和Python语言的最佳特性。
2. 跨平台
可以在不同的系统平台上使用,包括Windows,Linux,OS×,Android和iOS。基于CUDA和OpenCL的高速GPU操作接口也在积极开发中
3. 活跃的开发团队
4. 丰富的API
完善的传统计算机视觉算法,涵盖主流的机器学习算法,同时添加了对深度学习的支持。
1.2.1 OpenCV-Python
OpenCV-Python是一个Python绑定库,旨在解决计算机视觉问题。
Python是一种由GuidovanRossum开发的通用编程语言,它很快就变得非常流行,主要是因为它的简单性和代码可误性。它使程序员能够用更少的代码行表达思想,而不会降低可读性。
与C/C++等语言相比,Python速度较慢。也就是说,Python可以使用C/ C++轻松扩展,这使我们可以在C/ C++中编写计算密集型代码,并创建可用作Python模块的Python包装器。这给我们带来了两个好处:首先,代码与原始C/C++代码一样快(因为它是在后台工作的实际C++代码),其次,在Python中编写代码比使用C/ C++更容易。OpenCV-Python是原始OpenCV C++实现的Python包装器。
OpenCV-Python使用Numpy,这是一个高度优化的数据库操作库,具有MATLAB风格的语法。所有OpenCV数组结构都转换为Numpy数组。这也使得与使用Numpy的其他库(如SciPy和Matplotlib)集成更容易。
1.2.2 OpenCv部署方法
- 创建并激活虚拟环境
cv,虚拟环境可以隔离不同项目的依赖,避免版本冲突,操作如下:
python
# 1. 安装 virtualenv(如果未安装)
pip install virtualenv
# 2. 创建名为 cv 的虚拟环境
virtualenv cv
# 3. 激活虚拟环境(进入 cv 环境)
cv\Scripts\activate
激活后命令行开头会出现 (cv),表示已进入虚拟环境。

- 创建Python虚拟环境cv, 在cv中安装即可。
先安装OpenCV-Python,由于一些经典的算法被申请了版权,新版本有很大的限制,所以选用3.4.3以下的版本
python
pip install opencv-python
现在可以测试一下是否安装成功,运行以下代码无措则说明安装成功。
python
import cv2
- 安装依赖包
python
# 安装 numpy(OpenCV 核心依赖)
pip install numpy
# 安装 matplotlib(用于图像可视化)
pip install matplotlib
- 验证安装是否成功
在激活的 cv 虚拟环境中,运行以下 Python 代码测试:
python
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 打印 OpenCV 版本(验证安装)
print("OpenCV 版本:", cv2.__version__)
# 简单测试:创建一个黑色图像并显示
# 创建 500x500 的黑色画布(3 通道 RGB)
img = np.zeros((500, 500, 3), dtype=np.uint8)
# 在画布上画红色文字(OpenCV 默认 BGR,红色为 (0,0,255))
cv2.putText(img, "OpenCV Installed!", (50, 250),
cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 3)
# 转换颜色空间(OpenCV BGR → matplotlib RGB)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 显示图像
plt.imshow(img_rgb)
plt.axis("off") # 隐藏坐标轴
plt.show()
如果能正常打印 OpenCV 版本,且弹出显示红色文字的黑色窗口,说明安装成功。
- 退出虚拟环境(可选)
使用完后,执行以下命令退出 cy 虚拟环境:
python
deactivate
1.3 OpenCV的模块

其中core、highgui、imgproc是最基础的模块,该课程主要是围绕这几个模块展开的,分别介绍如下:
- core模块实现了最核心的数据结构及其基本运算,如绘图函数、数组操作相关函数等。
- highgui模块实现了视频与图像的读取、显示、存储等接口。
- imgproc模块实现了图像处理的基础方法,包括图像滤波、图像的几何变换、平滑、阈值分割、形态学处理、边缘检测、目标检测、运动分析和对象跟踪等。
对于图像处理其他更高层次的方向及应用,OpenCV也有相关的模块实现
- features2d模块用于提取图像特征以及特征匹配,nonfree模块实现了一些专利算法,如sift特征。·objdetect模块实现了一些目标检测的功能,经典的基于Haar、LBP特征的人脸检测,基于HOG的行人、汽车等目标检测,分类器使用Cascade Classification(级联分类)和Latent SVM等。
- stitching模块实现了图像拼接功能。
- FLANN模块 (Fast Library for Approximate Nearest Neighbors), 包含快速近似最近邻搜索FLANN和聚类Clustering算法。
- ml模块机器学习模块(SVM,决策树,Boosting等等)。·photo模块包含图像修复和图像去噪两部分。
- video模块针对视频处理,如背景分离,前景检测、对象跟踪等。
OpenCV 的模块 core:最核心的数据结构 highgui:视频与图像的读取、显示、存储
imgproc:图像处理的基础方法
features2d:图像特征以及特征匹配
二、OpenCV基本操作
2.1 图像的基础操作
1、 图像的IO操作
1、API
- 读取图像
python
cv.imread()
参数:
- 要读取的图像
- 读取方式的标志
- CVIMREAD*COLOR:以彩色模式加载图像,任何图像的透明度都将被忽略。这是默认参数。
- CV.IMREADGRAYSCALE: 以灰度模式加载图像
- cv.IMREAD_UNCHANGED:包括alpha通道的加载图像模式。
可以使用1、0或者-1来替代上面三个标志
参考代码:
python
import numpy as np
import cv2 as cv
# 以灰度图的形式读取图像
img=cv.imread("messi5",0)
注意:如果使用绝对路径来读取图像的话,要确保没有中文目录,图像也不要以中文命名
注意:如果加载的路径有错误,不会报错,会返回一个None值
2、 显示图像
1、API
python
cv.imshow()
参数:
- 显示图像的窗口名称,以字符串类型标识
- 要加载的图像
注意:在调用显示图像的API后,要调用*cv.waitKey()*给图像绘制留下时间,否则窗口会出现无响应情况,并且图像无法显示出来。
另外也可以使用matplotlib对图像进行展示
python
# opencv中显示
cv.imshow('image',img)
cv.waitkey(0)
# matplotlib中展示
plt.imshow(img[:,:,::-1])
OpenCV默认以 BGR 格式读取彩色图像,而 Matplotlib的 imshow() 函数期望图像是 RGB 格式。img[:,:,::-1] 的作用是将 BGR 格式的图像转换为 RGB 格式
3、 保存图像
1、API
cv.imwrite()
参数:
- 文件名,要保存在哪里
- 要保存的图像
参考代码:
cv.imwrite('messigrat.png',img)
4、总结
我们通过加载灰度图像,显示图像,如果按's'并退出则保存图像,或者按ESC键直接退出而不保存。
python
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1读取图像
img = cv.imread("../images/mess.png")
# 2显示图像
# 2.1 opencv
cv.imshow("mess",img)
cv.waitKey(0) # 永远等待输入
cv.destroyAllWindows() # 关闭 窗口

python
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1读取图像
img = cv.imread("../images/mess.png")
# 2显示图像
#2.2 matplotlib
plt.imshow(img[:,:,::-1])
plt.show()
python
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1读取图像
img = cv.imread("../images/mess.png",0) # 灰度图 0
# 2显示图像
# 2.1 opencv
# cv.imshow("mess",img)
# cv.waitKey(0) # 永远等待输入
# cv.destroyAllWindows() # 关闭 窗口
#2.2 matplotlib
# plt.imshow(img[:,:,::-1])
plt.imshow(img,cmap=plt.cm.gray)
plt.show()

python
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1读取图像
img = cv.imread("../images/mess.png",0) # 灰度图 0
# 2显示图像
# 2.1 opencv
# cv.imshow("mess",img)
# cv.waitKey(0) # 永远等待输入
# cv.destroyAllWindows() # 关闭 窗口
#2.2 matplotlib
# plt.imshow(img[:,:,::-1])
plt.imshow(img,cmap=plt.cm.gray)
plt.show()
# 3.图像的保存
cv.imwrite("../images/mess_gray.png",img)

5、绘制几何图形
5.1 绘制直线
cv.line(img,start,end,color,thickness)
参数:
- img:要绘制直线的图像
- start,end:直线的起点和终点
- color:线条的颜色
- thinckness:线条宽度
5.2 绘制圆形
cv.circle(img,centerpoint,r,color,thickness)
参数:
-
img:要绘制的图像
-
centerpoint,r:圆心和半径
-
color:线条的颜色
-
thickness:线条宽度,为-1时生成闭合图案并填充颜色
5.3 绘制矩形
python
cv.rectangle(img,leftupper,rightdown,color,thinckness)
参数:
- img:要绘制矩形的图像
- leftupper,rightdown:矩形左上角和右下角坐标
- color:线条颜色
- thickness:线条宽度
5.4 向图像中添加文字
cv.putText(img,text,station,font,fontsize,color,thin=ckness,cv.LINE_AA)
参数:
- img:图像
- text:要写入的文本数据
- station:文本的放置位置
- font:字体
- fontsize:字体大小
5.5 效果展示
生成一个全黑的图像,然后在里面绘制图像并添加文字
6、获取并修改图像中的像素点
我们可以通过行和列的坐标值获取该像素点的像素值。对于BGR图像,它返回一个蓝,绿,红值的数组。对于灰度图像,仅返回相应的强度值。使用相同的方法对像素值进行修改。
import numpy as np
import matplotlib.pyplot as plt
img=np.zeros((256,256,3),np.uint8) # 其中(256,256,3),是什么意思 创建一个全零的数组,大小为256*256*3
# plt.imshow(img[:,:,::-1])
plt.imshow(img[:,:,::-1])
plt.show()
px=img[100,100]
print("第一个像素为",px)
img[100,100]=(0,0,255)
img[100,100+1]=(0,255,0)
img[100+1,100]=(255,0,0)
img[100+1,100+1]=(255,255,255)
px=img[100,100]
print("第一个像素为",px)
plt.imshow(img[:,:,::-1])
输出
python
D:\devCode\OpenCV\devCode\.venv\Scripts\python.exe D:\devCode\OpenCV\devCode\cv\Test1\code\03.获取并修改图像中的像素点.py
第一个像素为 [0 0 0]
第一个像素为 [ 0 0 255]
进程已结束,退出代码为 0

7、获取图像的属性
图像属性包括行数、列数和通道数,图像数据类型,像素等
| 属性 | API |
|---|---|
| 形状 | img.shape |
| 图像大小 | img.size |
| 数据类型 | img.dtype |
python
import numpy as np
import matplotlib.pyplot as plt
from numpy.ma.core import shape
img=np.zeros((256,256,3),np.uint8) # 其中(256,256,3),是什么意思 创建一个全零的数组,大小为256*256*3
# plt.imshow(img[:,:,::-1])
# plt.imshow(img[:,:,::-1])
# plt.show()
px=img[100,100]
print("第一个像素为",px)
img[100,100]=(0,0,255)
img[100,100+1]=(0,255,0)
img[100+1,100]=(255,0,0)
img[100+1,100+1]=(255,255,255)
px=img[100,100]
print("第一个像素为",px)
# plt.imshow(img[:,:,::-1])
shape=img.shape
print("图像的尺寸为",shape)
size=img.size
print("图像的大小为",size)
dtype=img.dtype
print("图像的数据类型为",dtype)
输出:
python
D:\devCode\OpenCV\devCode\.venv\Scripts\python.exe D:\devCode\OpenCV\devCode\cv\Test1\code\03.获取并修改图像中的像素点.py
第一个像素为 [0 0 0]
第一个像素为 [ 0 0 255]
图像的尺寸为 (256, 256, 3)
图像的大小为 196608
图像的数据类型为 uint8
进程已结束,退出代码为 0
8、图像通道的拆分与合并
有时需要再B,G,R 通道图像上单独工作,在这种情况下,需要将BGR图像分割为单个通道。或者在其他情况下,可能需要将这些单独的通道合并到BGR图像。
python
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from numpy.ma.core import shape
img=np.zeros((256,256,3),np.uint8) # 其中(256,256,3),是什么意思 创建一个全零的数组,大小为256*256*3
# plt.imshow(img[:,:,::-1])
# plt.imshow(img[:,:,::-1])
# plt.show()
px=img[100,100]
print("第一个像素为",px)
img[100,100]=(0,0,255)
img[100,100+1]=(0,255,0)
img[100+1,100]=(255,0,0)
img[100+1,100+1]=(255,255,255)
px=img[100,100]
print("第一个像素为",px)
# plt.imshow(img[:,:,::-1])
shape=img.shape
print("图像的尺寸为",shape)
size=img.size
print("图像的大小为",size)
dtype=img.dtype
print("图像的数据类型为",dtype)
# 通道拆分
b,g,r=cv.split(img)
print("\nb=",b,"\ng=",g,"\nr=",r)
# 通道合并
img=cv.merge((b,g,r))
plt.imshow(img[:,:,::-1])
输出
python
D:\devCode\OpenCV\devCode\.venv\Scripts\python.exe D:\devCode\OpenCV\devCode\cv\Test1\code\03.获取并修改图像中的像素点.py
第一个像素为 [0 0 0]
第一个像素为 [ 0 0 255]
图像的尺寸为 (256, 256, 3)
图像的大小为 196608
图像的数据类型为 uint8
b= [[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
g= [[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
r= [[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
进程已结束,退出代码为 0
9、色彩空间的改变
OpenCV中有150多种颜色空间转换方法。最广泛使用的转换方法有两种,BGR→Gray和BGR→HSV。
API:
python
cv.cvtColor(input_image,flag)
参数:
- input_image:进行颜色空间转换的图像
- flag:转换类型
- cv.COLOR_BGR2GRAY:BGR<->Gray
- cv.COLOR_BGR2J+HSV:BGR->HSV
python
dili=cv.imread("../images/mess.png")
b,g,r=cv.split(dili)
plt.imshow(b,cmap=plt.cm.gray)
img2=cv.merge((b,g,r))
grayImg=cv.cvtColor(dili,cv.COLOR_BGR2GRAY)
plt.imshow(grayImg,cmap=plt.cm.gray)
plt.show()
hsv=cv.cvtColor(dili,cv.COLOR_BGR2HSV)
plt.imshow(hsv)
plt.show()

总结:
1.图像IO操作的API:
- cv.imread():读取图像
- cv.imshow():显示图像
- cv.imwrite():保存图像
2.在图像上绘制几何图像
- cv.line():绘制直线
- cv.circle():绘制圆形
- cv.rectangle():绘制矩形
- cv.putText():在图像上添加文字
3.直接使用行列索引获取图像中的像素并进行修改
4.图像的属性
| 属性 | API |
|---|---|
| 形状 | img.shape |
| 图像大小 | img.size |
| 数据类型 | img.dtype |
5.拆分通道:cv.split()
通道合并:cv.merge()
6.色彩空间的改变
cv.cvtColor(iput_image,flag)
2.2 算数操作
1、图像的加法
使用openCV的cv.add()函数把两幅图相加,或者可以简单地通过numpy操作添加两个图像,eg:img1+img2.两个图像应该具有相同大小和类型,或者第二个图像可以是标量值。
注意:OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算
python
x=np.uint8([250])
y=np.uint8([10])
print(cv.add(x,y))
输出:[[255]]
print(x+y)
输出:[4]
eg:
python
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
rain = cv.imread("../images/rain.jpg")
plt.imshow(rain[:,:,::-1])
# plt.show()
view=cv.imread("../images/view.jpg")
plt.imshow(view[:,:,::-1])
# plt.show()
# 图像相加
img1 =cv.add(rain,view)
plt.imshow(img1[:,:,::-1])
# plt.show()
img2 = rain + view
plt.imshow(img2[:,:,::-1])
plt.show()


2、图像的混合
混合与加法不同的是两幅图像的权重不同,找会给人一种混合或者透明的感觉,图像混合的计算公式如下:
g(x)=(1−α)f0(x)+αf1(x) g(x)=(1-α)f_0(x)+αf_1(x) g(x)=(1−α)f0(x)+αf1(x)
通过修改α的值(0->1)可以实现非常炫酷的混合。
现在我们把两幅图混合在一起。第一幅权重是0.7,第二幅是0.3,函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。
dst=α.img1+β.img2+γ(γ取0) dst=α.img1+β.img2+γ(γ取0) dst=α.img1+β.img2+γ(γ取0)
python
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
rain = cv.imread("../images/rain.jpg")
plt.imshow(rain[:,:,::-1])
# plt.show()
view=cv.imread("../images/view.jpg")
plt.imshow(view[:,:,::-1])
# plt.show()
# 图像相加
img1 =cv.add(rain,view)
plt.imshow(img1[:,:,::-1])
# plt.show()
img2 = rain + view
plt.imshow(img2[:,:,::-1])
# plt.show()
# 混合
img3 = cv.addWeighted(rain,0.7,view,0.3,0)
plt.figure(figsize=(8,8))
plt.imshow(img3[:,:,::-1])
plt.show()
