OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它包含了数百种计算机视觉算法,广泛用于图像处理、视频分析、物体检测、人脸识别等任务。
简单来说:OpenCV就是让计算机"看懂"图像和视频的一把钥匙,就像给计算机安装了一双"眼睛"。
pip install opencv-python
如果是苹果M系列芯片 Mac:
pip install opencv-python
验证安装:
import cv2
print(cv2.__version__) # 输出 OpenCV 版本
在计算机中,图像本质上就是一个矩阵(Matrix)。
假设有一张宽度300像素、高度200像素的彩色图片:
每个像素点的值通常是 0-255 的整数:
灰度图像 vs 彩色图像:
OpenCV 使用的是 行-列 坐标系(注意:不是常见的x-y坐标系):
┌─────────────→ 列 (x)
│ (0,0) (1,0) (2,0)
│ (0,1) (1,1) (2,1)
│ (0,2) (1,2) (2,2)
↓
行 (y)
重要:img[y, x] 表示访问第y行第x列的像素
例如:img[100, 200] 表示访问图像中第100行、第200列的像素值
import cv2
# 读取图像(彩色模式)
img = cv2.imread('photo.jpg', cv2.IMREAD_COLOR)
# 读取图像(灰度模式)
img_gray = cv2.imread('photo.jpg', cv2.IMREAD_GRAYSCALE)
# 读取图像(不变模式)
img_unchanged = cv2.imread('photo.jpg', cv2.IMREAD_UNCHANGED)
参数说明:
cv2.IMREAD_COLOR(或写1):读取彩色图像,忽略透明度cv2.IMREAD_GRAYSCALE(或写0):读取灰度图像cv2.IMREAD_UNCHANGED(或写-1):读取原始图像(含透明度通道)注意:如果图像读取失败,imread 会返回 None,所以最好加个判断:
img = cv2.imread('photo.jpg')
if img is None:
print("图像读取失败!")
else:
print("图像读取成功,形状:", img.shape)
import cv2
img = cv2.imread('photo.jpg')
# 显示图像(窗口名称,图像变量)
cv2.imshow('My Image', img)
# 等待按键(参数表示等待时间,单位毫秒。0表示无限等待)
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
常用组合:
cv2.imshow('Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这段代码会显示图像,等待用户按键,然后关闭窗口。
# 保存图像
cv2.imwrite('output.png', img)
# 第一个参数是保存的文件名,第二个是图像变量
import cv2
img = cv2.imread('photo.jpg')
# 获取图像形状
print(img.shape)
# 输出例如:(480, 640, 3) 表示 高度480,宽度640,3通道
# 获取图像高度
print(img.shape[0])
# 获取图像宽度
print(img.shape[1]
# 获取通道数
print(img.shape[2])
# 获取图像数据类型
print(img.dtype)
# 输出通常是 uint8(无符号8位整数,范围0-255)
# 获取图像像素总数
print(img.size)
# 输出:480 × 640 × 3 = 921600
import cv2
img = cv2.imread('photo.jpg')
# 方法一:直接指定目标尺寸
# 参数:(图像, 宽度, 高度)
resized = cv2.resize(img, (300, 200)) # 注意:先宽后高
# 方法二:按比例缩放
# 参数:(图像, None, fx, fy)
# fx, fy 是缩放因子
resized2 = cv2.resize(img, None, fx=0.5, fy=0.5) # 缩小到一半
# 放大到2倍
resized3 = cv2.resize(img, None, fx=2, fy=2)
注意:OpenCV 中 resize 的参数顺序是 (宽度, 高度),而不是(高, 宽)
图像本质上是矩阵,裁剪就是从矩阵中提取一部分。
import cv2
img = cv2.imread('photo.jpg')
# 裁剪图像:img[行_start:行_end, 列_start:列_end]
# 注意:是左闭右开区间 [start, end)
cropped = img[100:300, 200:400] # 裁剪 y:100-300, x:200:400 的区域
cv2.imshow('Cropped', cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()
示例图解:
原图:
┌────────────────────────────┐
│ │
│ 裁剪区域 │
│ ┌──────────┐ │
│ │ 这是 │ │
│ │ 裁剪 │ │
│ │ 结果 │ │
│ └──────────┘ │
│ │
└────────────────────────────┘
import cv2
img = cv2.imread('photo.jpg')
# flipCode 参数:
# 1 → 水平翻转(左右颠倒)
# 0 → 垂直翻转(上下颠倒)
# -1 → 同时水平垂直翻转(旋转180度)
# 水平翻转
flipped_h = cv2.flip(img, 1)
# 垂直翻转
flipped_v = cv2.flip(img, 0)
# 水平+垂直翻转
flipped_hv = cv2.flip(img, -1)
import cv2
import numpy as np
img = cv2.imread('photo.jpg')
height, width = img.shape[:2]
# 方法一:使用 getRotationMatrix2D
# 参数:(旋转中心, 旋转角度, 缩放因子)
# 旋转中心可以是 (width/2, height/2) 即图像中心
# 角度:正数表示逆时针旋转
# 旋转90度
M = cv2.getRotationMatrix2D((width/2, height/2), 90, 1)
rotated = cv2.warpAffine(img, M, (width, height))
# 方法二:使用 transpose(只能旋转90度的倍数)
# 顺时针旋转90度
rotated90 = cv2.transpose(img)
# 逆时针旋转90度
rotated90_cw = cv2.transpose(cv2.flip(img, 1))
RGB:红-绿-蓝,加法混色模式,屏幕显示常用
BGR:OpenCV默认使用BGR模式(注意:不是RGB!)
灰度(Gray):只有亮度信息,黑白照片
HSV:
YUV:常用于视频处理
import cv2
img = cv2.imread('photo.jpg')
# BGR 转 灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# BGR 转 RGB(用于 matplotlib 显示)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# BGR 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 灰度 转 BGR
bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
重要:OpenCV 默认使用 BGR 格式,而 matplotlib 使用 RGB 格式。如果用 OpenCV 读取图像后用 matplotlib 显示,颜色会偏红/蓝。解决方法:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('photo.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换后再显示
plt.imshow(img_rgb)
plt.show()
import cv2
img = cv2.imread('photo.jpg')
# 分离通道
b, g, r = cv2.split(img)
# 合并通道
merged = cv2.merge([b, g, r])
# 也可以只保留某个通道
only_red = img[:, :, 2] # 保留红色通道
OpenCV 可以直接在图像上绘制各种形状。
import cv2
import numpy as np
# 创建一张空白图像(黑色背景)
img = np.zeros((512, 512, 3), np.uint8)
# 画线:cv2.line(图像, 起点, 终点, 颜色, 线宽)
# 颜色是 BGR 格式
cv2.line(img, (0, 0), (511, 511), (0, 255, 0), 5)
# (0, 0) 是左上角,(511, 511) 是右下角
# (0, 255, 0) 是绿色,线宽5像素
import cv2
import numpy as np
img = np.zeros((512, 512, 3), np.uint8)
# 画矩形:cv2.rectangle(图像, 左上角, 右下角, 颜色, 线宽)
# 线宽为 -1 表示填充整个矩形
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
# 填充矩形
cv2.rectangle(img, (100, 100), (200, 200), (255, 0, 0), -1)
import cv2
import numpy as np
img = np.zeros((512, 512, 3), np.uint8)
# 画圆:cv2.circle(图像, 圆心, 半径, 颜色, 线宽)
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
# 圆心(447, 63),半径63,红色,填充
import cv2
import numpy as np
img = np.zeros((512, 512, 3), np.uint8)
# 添加文字:cv2.putText(图像, 文字, 位置, 字体, 大小, 颜色, 粗细, 线条类型)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'OpenCV', (10, 250), font, 4, (255, 255, 255), 2, cv2.LINE_AA)
常用字体:
cv2.FONT_HERSHEY_SIMPLEX - 正常大小无衬线字体cv2.FONT_HERSHEY_DUPLEX - 正常大小无衬线字体(复杂)cv2.FONT_HERSHEY_COMPLEX - 正常大小衬线字体cv2.FONT_ITALIC - 斜体(需要与其他字体组合)import cv2
import numpy as np
# 创建空白图像
img = np.ones((500, 500, 3), np.uint8) * 255 # 白色背景
# 画脸部轮廓(椭圆)
cv2.ellipse(img, (250, 250), (100, 120), 0, 0, 360, (255, 0, 0), 2)
# 画左眼(圆)
cv2.circle(img, (210, 220), 20, (0, 255, 0), 2)
# 画右眼(圆)
cv2.circle(img, (290, 220), 20, (0, 255, 0), 2)
# 画鼻子(线)
cv2.line(img, (250, 250), (240, 300), (0, 0, 255), 2)
cv2.line(img, (250, 250), (260, 300), (0, 0, 255), 2)
# 画嘴巴(椭圆的一部分)
cv2.ellipse(img, (250, 320), (60, 20), 0, 0, 180, (0, 0, 255), 2)
cv2.imshow('Face', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像滤波就是对图像进行"美化"或"提取特征"的过程,可以理解为给图像"化妆"或"美颜"。
模糊可以去除图像噪声,让图像看起来更柔和。
import cv2
img = cv2.imread('photo.jpg')
# 均值模糊
# 参数:图像, 内核大小 (必须是奇数)
blur = cv2.blur(img, (5, 5))
# 高斯模糊(更自然的模糊)
# 参数:图像, 内核大小, 标准差
gaussian = cv2.GaussianBlur(img, (5, 5), 0)
# 中值模糊(对椒盐噪声效果好)
median = cv2.medianBlur(img, 5)
# 双边滤波(保留边缘的模糊)
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
锐化让图像看起来更清晰,边缘更明显。
import cv2
import numpy as np
img = cv2.imread('photo.jpg')
# 定义锐化核
kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
# 应用锐化
sharpened = cv2.filter2D(img, -1, kernel)
# 另一种锐化方法:锐化 + 模糊的混合
kernel2 = np.array([[1, 1, 1],
[1, -7, 1],
[1, 1, 1]])
sharpened2 = cv2.filter2D(img, -1, kernel2)
边缘检测用于找出图像中物体的轮廓。
import cv2
img = cv2.imread('photo.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Canny 边缘检测
# 参数:图像, 阈值1, 阈值2
edges = cv2.Canny(gray, 50, 150)
# 阈值1过低:检测到更多边缘(包含噪声)
# 阈值2过高:只检测到最明显的边缘
原理:Canny 边缘检测会检测梯度变化大的地方,这些地方通常就是物体的边缘。
形态学操作主要用于处理图像的形状和结构。
import cv2
import numpy as np
img = cv2.imread('shape.png', 0)
# 二值化处理
_, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 腐蚀(缩小白色区域)
# 参数:图像, 内核, 迭代次数
kernel = np.ones((5, 5), np.uint8)
eroded = cv2.erode(binary, kernel, iterations=1)
# 膨胀(扩大白色区域)
dilated = cv2.dilate(binary, kernel, iterations=1)
# 开运算(先腐蚀后膨胀,去除小物体)
opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
# 闭运算(先膨胀后腐蚀,填充小孔洞)
closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
应用场景:
import cv2
import numpy as np
img1 = cv2.imread('image1.jpg')
img2 = cv2.imread('image2.jpg')
# 方法一:直接相加(会截断到255)
added = cv2.add(img1, img2)
# 方法二:带权重的相加(混合两幅图)
# 参数:图像1, 权重1, 图像2, 权重2, 偏移量
blended = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)
使用掩码可以选择性地处理图像的特定区域。
import cv2
import numpy as np
img = cv2.imread('photo.jpg')
# 创建掩码(全黑)
mask = np.zeros(img.shape[:2], dtype=np.uint8)
# 在掩码上创建白色区域(ROI)
mask[100:300, 200:400] = 255
# 使用掩码提取感兴趣区域
roi = cv2.bitwise_and(img, img, mask=mask)
import cv2
# 读取视频文件
cap = cv2.VideoCapture('video.mp4')
# 或者读取摄像头(0 表示第一个摄像头)
cap = cv2.VideoCapture(0)
while cap.isOpened():
# 读取一帧
ret, frame = cap.read()
if not ret:
break # 视频结束
# 处理这一帧
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 显示
cv2.imshow('Video', gray)
# 按 q 键退出
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
import cv2
cap = cv2.VideoCapture(0)
# 获取视频属性
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
# 创建 VideoWriter 对象
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, fps, (width, height))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 写入帧
out.write(frame)
cv2.imshow('Recording', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
import cv2
# 加载预训练的人脸检测模型
# OpenCV 提供了 Haar Cascade 分类器
face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
# 读取图片
img = cv2.imread('photo.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测人脸
# 参数:灰度图像, 缩放因子, 最小邻居数
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
# 在每张人脸上画矩形
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Face Detection', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
# 读取车牌图像
img = cv2.imread('car_plate.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 形态学操作
kernel = np.ones((3, 3), np.uint8)
dilated = cv2.dilate(binary, kernel, iterations=2)
# 找轮廓
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 筛选可能是字符的轮廓
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
# 根据宽高比筛选
if.2 < w/h < 1.0 and w > 10 and h > 10:
# 切割字符
char_img = img[y:y+h, x:x+w]
cv2.imshow('Character', char_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 高斯模糊模拟美颜
# 参数:图像, 核大小, 标准差
blurred = cv2.GaussianBlur(frame, (15, 15), 0)
# 混合原图和模糊图(保留细节)
# 权重:原图0.6,模糊图0.4
beauty = cv2.addWeighted(frame, 0.6, blurred, 0.4, 0)
cv2.imshow('Beauty', beauty)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
| 功能 | 函数 |
|---|---|
| 读取图像 | cv2.imread() |
| 显示图像 | cv2.imshow() |
| 保存图像 | cv2.imwrite() |
| 等待按键 | cv2.waitKey() |
| 调整大小 | cv2.resize() |
| 裁剪 | img[y1:y2, x1:x2] |
| 翻转 | cv2.flip() |
| 旋转 | cv2.warpAffine() |
| 颜色转换 | cv2.cvtColor() |
| 灰度化 | cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| 画线 | cv2.line() |
| 画矩形 | cv2.rectangle() |
| 画圆 | cv2.circle() |
| 画椭圆 | cv2.ellipse() |
| 写文字 | cv2.putText() |
| 均值模糊 | cv2.blur() |
| 高斯模糊 | cv2.GaussianBlur() |
| 中值模糊 | cv2.medianBlur() |
| 边缘检测 | cv2.Canny() |
| 二值化 | cv2.threshold() |
| 腐蚀 | cv2.erode() |
| 膨胀 | cv2.dilate() |
| 开运算 | cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) |
| 闭运算 | cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) |
| 人脸检测 | face_cascade.detectMultiScale() |
| 读取视频 | cv2.VideoCapture() |
| 写入视频 | cv2.VideoWriter() |