目录
[Windows 下使用 Anaconda 安装 OpenCV](#Windows 下使用 Anaconda 安装 OpenCV)
[二、创建 OpenCV 专用虚拟环境](#二、创建 OpenCV 专用虚拟环境)
[三、安装 OpenCV(推荐 opencv-contrib-python)](#三、安装 OpenCV(推荐 opencv-contrib-python))
[四、安装必要的依赖库(numpy + matplotlib)](#四、安装必要的依赖库(numpy + matplotlib))
[六、解决 Terminal 进入 base 环境的问题(可选)](#六、解决 Terminal 进入 base 环境的问题(可选))
[在 Terminal 手动激活:](#在 Terminal 手动激活:)
[1️⃣ 像素(Pixel)是什么?](#1️⃣ 像素(Pixel)是什么?)
[2️⃣ 灰度图 vs 彩色图(本质区别)](#2️⃣ 灰度图 vs 彩色图(本质区别))
[二、使用 OpenCV 读取图像](#二、使用 OpenCV 读取图像)
[1️⃣ 基本代码](#1️⃣ 基本代码)
[此时 img 到底是什么?](#此时 img 到底是什么?)
[2️⃣ 如何读取灰度图片?](#2️⃣ 如何读取灰度图片?)
[1️⃣ shape(结构 / 尺寸)](#1️⃣ shape(结构 / 尺寸))
[2️⃣ ndim(维度数)](#2️⃣ ndim(维度数))
[3️⃣ dtype(数据类型)](#3️⃣ dtype(数据类型))
[4️⃣ size(像素总数)](#4️⃣ size(像素总数))
[彩色 → 灰度](#彩色 → 灰度)
[什么是边界填充(Border Padding)](#什么是边界填充(Border Padding))
[OpenCV 中的边界填充函数](#OpenCV 中的边界填充函数)
[1️⃣ BORDER_REPLICATE(复制法)](#1️⃣ BORDER_REPLICATE(复制法))
[2️⃣ BORDER_REFLECT(反射法)](#2️⃣ BORDER_REFLECT(反射法))
[3️⃣ BORDER_REFLECT_101(反射 101)](#3️⃣ BORDER_REFLECT_101(反射 101))
[4️⃣ BORDER_WRAP(环绕法)](#4️⃣ BORDER_WRAP(环绕法))
[5️⃣ BORDER_CONSTANT(常量填充)](#5️⃣ BORDER_CONSTANT(常量填充))
[NumPy 数值运算(取模运算)](#NumPy 数值运算(取模运算))
[OpenCV 数值运算(饱和运算)](#OpenCV 数值运算(饱和运算))
[视频在 OpenCV 里是什么?](#视频在 OpenCV 里是什么?)
[读取视频文件并转灰度显示(ESC 退出)](#读取视频文件并转灰度显示(ESC 退出))
[1️⃣ 作用](#1️⃣ 作用)
[2️⃣ 判断视频是否成功打开](#2️⃣ 判断视频是否成功打开)
Windows 下使用 Anaconda 安装 OpenCV
OpenCV 是计算机视觉中最常用的图像处理库,而在 Windows 下正确安装 OpenCV 对初学者来说往往容易踩坑:版本不兼容、环境混乱、PyCharm 找不到库等。本教程将从零开始,带你用 Anaconda + 虚拟环境 安装 OpenCV,并最终在 PyCharm 中成功运行代码。
教程适用于:
-
Windows 系统
-
使用 Anaconda 管理 Python
-
PyCharm 或任意 IDE
-
初学者 & 想避免环境混乱的人
一、为什么一定要使用虚拟环境?
很多同学直接在 base 环境装包,导致:
-
Python 版本冲突
-
多个项目共享同一环境,容易"互相污染"
-
升级 / 回退库版本困难
-
OpenCV、matplotlib、numpy 冲突概率大
因此推荐使用:
一个项目一个环境
环境独立、干净、可随时删除重建
二、创建 OpenCV 专用虚拟环境
打开 Anaconda Prompt,创建一个名为 opencv4 的环境:
bash
conda create -n opencv4 python=3.10
激活环境:
bash
conda activate opencv4
看到前缀变成:(opencv4) 说明虚拟环境已激活成功。
三、安装 OpenCV(推荐 opencv-contrib-python)
OpenCV 有两种常见安装包:
| 包名 | 内容 |
|---|---|
| opencv-python | 基础功能(图像读写、滤波、边缘检测) |
| opencv-contrib-python(推荐) | 包含基础功能 + SIFT/SURF/ORB/Tracking 等扩展算法 |
推荐安装完整版本:
bash
pip install opencv-contrib-python
四、安装必要的依赖库(numpy + matplotlib)
OpenCV 常用 numpy 和 matplotlib:
bash
pip install numpy matplotlib
五、如何在pycharm使用这个虚拟环境?



六、解决 Terminal 进入 base 环境的问题(可选)
PyCharm 自带 Terminal 默认不会自动进入当前解释器对应的 conda 环境,导致 pip 装包装到 base。
解决方法:
在 Terminal 手动激活:
bash
conda activate opencv4
OpenCV入门------读取图像,显示图像
一、计算机眼中的"图像"是什么?
在我们人类眼中,图像是有颜色、有形状的画面;
但在计算机眼中,图像本质上只有一件事:
图像 = 数字组成的矩阵(数组)
计算机并不"看"图像,它只处理 数字。
1️⃣ 像素(Pixel)是什么?
图像是由很多个像素点组成的。
-
一个像素 = 图像中最小的点
-
每个像素用数字表示颜色或亮度
2️⃣ 灰度图 vs 彩色图(本质区别)
灰度图
-
每个像素只有 一个数字
-
范围:
0 ~ 255-
0:黑 -
255:白
-
bash
123 124 125
120 121 122
118 119 120
彩色图
-
每个像素由 三个数字组成
-
分别表示三种颜色强度
在 OpenCV 中顺序是:
bash
[B, G, R] → 蓝、绿、红
例如:
bash
[104, 78, 62]
二、使用 OpenCV 读取图像
1️⃣ 基本代码
python
# 读取图片
img = cv2.imread('head.jpg')
# 打印图片
print( img)
# 显示图片
cv2.imshow('image',img)
cv2.waitKey(0) # 0表示等待时间,0表示一直等待
cv2.destroyAllWindows()
此时 img 到底是什么?
img的结构是:
bash
[[[104 78 62]
[104 78 62]
[104 78 62]
...
]]
第一层:一个像素
bash
[104 78 62]
表示一个像素
含义:
-
104:蓝色强度 -
78:绿色强度 -
62:红色强度
如果是灰度图片,那么一个数字表示一个像素

第二层:一整行像素
bash
[[104 78 62]
[104 78 62]
[104 78 62]
...
[143 147 148]
[143 147 148]
[143 147 148]]
[[106 80 64]
[106 80 64]
[106 80 64]
...
[150 154 155]
[150 154 155]
[150 154 155]]
含义:
-
每一行是一个像素
-
这一整块表示:图片中的一行
第三层:所有行组成整张图
bash
[
第 0 行像素,
第 1 行像素,
第 2 行像素,
...
]
含义:
👉 多行像素堆叠在一起 = 一张完整的图片
2️⃣ 如何读取灰度图片?
python
img2 = cv2.imread('head.jpg',cv2.IMREAD_GRAYSCALE)
print( img2)
cv2.imshow('image',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

其中 76 表示一个像素
76 76 76 ... 147 147 147\] 表示一行 \[\[ 76 76 76 ... 147 147 147
...
217 217 217 ... 90 89 88\]\] 表示整张图片
图像的基本属性
1️⃣ shape(结构 / 尺寸)
python
img.shape
含义
-
灰度图:
(H, W) -
彩色图:
(H, W, 3) -
透明图:
(H, W, 4)
👉 描述:有多少行、多少列、多少通道
OpenCV 使用
img.shape来获取图像在数组中的结构信息。对于彩色图像,图像以三维数组形式存储,
img.shape返回(高度, 宽度, 通道数),其中通道数通常为 3(B、G、R)。对于灰度图像,图像以二维数组形式存储,
每个像素本身就是一个数值,因此不再单独保留通道这一维,
img.shape只返回(高度, 宽度)。
2️⃣ ndim(维度数)
python
img.ndim
-
灰度图 →
2 -
彩色图 →
3
👉 数组有几层中括号
3️⃣ dtype(数据类型)
python
img.dtype
常见结果: uint8
含义
-
每个像素是 8 位无符号整数
-
范围:
0 ~ 255
⚠️ 这是为什么像素不能随便加到 300 的原因
4️⃣ size(像素总数)
python
img.size
表示:H × W × 通道数
👉 数组中一共有多少个数字
图像的基本操作
读取图像
python
img = cv2.imread('head.jpg')
gray = cv2.imread('head.jpg', cv2.IMREAD_GRAYSCALE) #灰色图像
显示图像
python
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
访问像素
python
pixel = img[100, 200] # [B G R]
b = img[100, 200, 0]
g = img[100, 200, 1]
r = img[100, 200, 2]
灰度图:
python
value = gray[100, 200]
修改像素
python
img[100, 200] = [0, 0, 255] # 改成红色
图像裁剪(切片)
python
roi = img[100:300, 200:400]
含义:
-
行:100 ~ 299
-
列:200 ~ 399
👉 裁剪本质是 数组切片
复制图像(避免误操作)
python
img2 = img.copy()
⚠️ 直接 img2 = img 只是引用
彩色 → 灰度
python
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
颜色提取通道
python
# 颜色通道提取
b,g,r = cv2.split(img)
print( "b",b)


- 每个通道都是一张灰度图
合并
python
img = cv2.merge([b, g, r])
改变图像大小
指定目标尺寸
python
resized = cv2.resize(img, (300, 300))
用缩放因子(写 fx / fy)
python
res = cv2.resize(img, (0, 0), fx=3, fy=1)
fx控制"横向缩放倍数",fy控制"纵向缩放倍数"
-
fx = 3→ 宽度变为原来的 3 倍 -
fy = 1→ 高度保持不变
所以你看到的结果是:
图片被横向拉长了,但上下没有变
保存图像
python
cv2.imwrite('out.jpg', img)
边界填充
什么是边界填充(Border Padding)
一句话定义:
边界填充,就是在图像的四周"人为加一圈像素"。
从数组角度看:
-
原图:
(H, W)或(H, W, 3) -
填充后:
(H + 上 + 下, W + 左 + 右[, 3])
也就是说:
👉 shape 会变大
为什么要进行边界填充
在图像处理中,很多操作(如卷积、滤波、边缘检测)需要访问像素周围的邻域。
-
图像中间像素:邻域完整
-
图像边缘像素:邻域不完整
👉 边界填充用来解决"边缘像素邻域不足"的问题,避免信息丢失或计算异常。
OpenCV 中的边界填充函数
python
cv2.copyMakeBorder()
基本形式
python
dst = cv2.copyMakeBorder(
src,
top, bottom, left, right,
borderType,
value=...
)
常见边界填充方式(重点)
1️⃣ BORDER_REPLICATE(复制法)
原理:
复制最外层像素向外扩展。
特点:
-
实现简单
-
边缘连续
-
使用非常广泛
2️⃣ BORDER_REFLECT(反射法)
原理:
以边界为轴,对图像内容进行镜像反射(包含边界像素)。
特点:
-
边缘过渡自然
-
常用于图像滤波
3️⃣ BORDER_REFLECT_101(反射 101)
原理:
反射填充,但不重复边界像素本身。
特点:
-
比
REFLECT更自然 -
OpenCV 滤波的默认方式
4️⃣ BORDER_WRAP(环绕法)
原理:
从图像对侧"接过来"进行填充。
特点:
-
类似周期拼接
-
不适合自然图像
-
多用于纹理或周期信号
5️⃣ BORDER_CONSTANT(常量填充)
原理:
使用固定值填充边界。
特点:
-
边界明显
-
常用于调试或显示
-
可指定填充值(黑边、白边、彩边)

数值计算
两种加法机制
NumPy 数值运算(取模运算)
bash
img3 = img1 + img2
运算规则
结果对 256 取模
数学形式:
bash
result = (a + b) % 256
OpenCV 数值运算(饱和运算)
bash
img3 = cv2.add(img1, img2)
运算规则
超过 255 的值直接截断为 255
数学形式:
bash
result = min(a + b, 255)
常见数值运算类型
1️⃣ 加法(亮度增强 / 图像叠加)
cv2.add(img, value)
cv2.add(img1, img2)
cv2.add(img1, img2)要求两个输入图像:形状(shape)必须完全一致。
2️⃣ 减法(亮度降低 / 差分)
cv2.subtract(img1, img2)
- 小于 0 的值 → 0
3️⃣ 乘法(对比度调节)
cv2.multiply(img, factor)
- 超过 255 → 255
4️⃣ 除法(归一化 / 比例调整)
cv2.divide(img, divisor)
图像融合
python
cv2.addWeighted(img1, α, img2, β, γ)
数学形式:
bash
result = img1 * α + img2 * β + γ
例如:
python
cv2.addWeighted(img1, 0.7, img2, 0.3, 0)
三、使用OpenCV读取视频
视频在 OpenCV 里是什么?
在 OpenCV 中:
-
视频 = 一帧一帧的图片
-
视频处理的本质:
循环读取 → 处理当前帧 → 显示 → 读取下一帧
读取视频文件并转灰度显示(ESC 退出)
python
import cv2
# 1. 打开视频文件(也可以写 0 打开摄像头)
vc = cv2.VideoCapture('test.mp4')
# 2. 检查是否打开成功
if vc.isOpened():
open, frame = vc.read()
else:
open = False
# 3. 循环读取视频帧
while open:
ret, frame = vc.read()
# 视频读完 / 读取失败
if frame is None:
break
if ret is True:
# 4. 图像处理:BGR 转 灰度
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 5. 显示当前帧
cv2.imshow('result', gray)
# 6. 控制播放速度 & 按 ESC 退出
if cv2.waitKey(100) & 0xFF == 27:
break
# 7. 释放资源
vc.release()
cv2.destroyAllWindows()
核心对象:cv2.VideoCapture
python
vc = cv2.VideoCapture('test.mp4')
1️⃣ 作用
VideoCapture 用来打开视频源,可以是:
| 参数 | 含义 |
|---|---|
0 |
默认摄像头 |
1 |
第二个摄像头 |
'test.mp4' |
视频文件路径 |
2️⃣ 判断视频是否成功打开
python
if vc.isOpened():
open, frame = vc.read()
else:
open = False
关键点解释
-
isOpened()判断视频是否成功加载
-
vc.read()返回两个值:
python
ret → 是否成功读取(True / False)
frame → 当前帧图像(numpy 数组)
循环读取视频帧(最核心部分)
python
while open:
ret, frame = vc.read()
为什么要用 while?
-
视频是由很多帧组成的
-
一次
read()只能读一帧 -
所以必须 循环读取
判断是否读到视频末尾
python
if frame is None:
break
为什么要判断?
-
视频结束后:
-
ret = False -
frame = None
-
-
不判断会 死循环或报错
