#OpenCV快速入门:图像读取、绘制与几何变换完整指南
#引言
OpenCV(Open Source Computer Vision Library)是计算机视觉领域最重要和广泛使用的开源库之一。它提供了丰富的图像处理和计算机视觉算法,支持多种编程语言(C++、Python、Java等)。本文将详细介绍OpenCV的基本操作,包括图像读取、绘制基本图形、几何变换等核心功能,为后续深入学习计算机视觉打下坚实基础。
📂 所属阶段:第一阶段 — 图像处理基石(传统 CV 篇)
🔗 相关章节:CV 概览与数字图像基础 · 图像增强与滤波
#1. OpenCV安装与基础配置
#1.1 安装OpenCV
# 基础版OpenCV
pip install opencv-python
# 包含额外功能的贡献版(推荐)
pip install opencv-contrib-python
# 如果需要最小化安装
pip install opencv-python-headless # 适用于服务器环境#1.2 验证安装
import cv2
print(f"OpenCV版本: {cv2.__version__}")
# 检查是否支持CUDA(GPU加速)
print(f"CUDA支持: {cv2.cuda.getCudaEnabledDeviceCount() > 0}")#1.3 基础导入和配置
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 设置中文字体(可选)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号#2. 图像读取与显示
#2.1 图像读取
import cv2
import numpy as np
# 读取图像 - 彩色模式(默认)
img_color = cv2.imread("photo.jpg", cv2.IMREAD_COLOR)
# 读取图像 - 灰度模式
img_gray = cv2.imread("photo.jpg", cv2.IMREAD_GRAYSCALE)
# 读取图像 - 包含alpha通道
img_unchanged = cv2.imread("photo.png", cv2.IMREAD_UNCHANGED)
# 检查图像是否成功加载
if img_color is None:
print("错误:无法读取图像文件")
else:
print(f"图像形状: {img_color.shape}") # (高度, 宽度, 通道数)
print(f"数据类型: {img_color.dtype}") # uint8
print(f"图像尺寸: {img_color.shape[1]} x {img_color.shape[0]}") # 宽度 x 高度#2.2 图像显示
# 使用OpenCV显示图像
cv2.imshow("彩色图像", img_color)
cv2.imshow("灰度图像", img_gray)
# 等待按键(0表示无限等待,其他数字表示毫秒)
cv2.waitKey(0)
# 销毁所有窗口
cv2.destroyAllWindows()
# 或者只销毁特定窗口
# cv2.destroyWindow("彩色图像")#2.3 图像保存
# 保存图像
success = cv2.imwrite("output.jpg", img_color)
if success:
print("图像保存成功")
else:
print("图像保存失败")
# 保存时设置压缩质量(JPEG)
cv2.imwrite("output_high_quality.jpg", img_color, [cv2.IMWRITE_JPEG_QUALITY, 95])
# 保存PNG图像时设置压缩级别
cv2.imwrite("output.png", img_color, [cv2.IMWRITE_PNG_COMPRESSION, 9])#2.4 Matplotlib显示(推荐用于Jupyter环境)
import matplotlib.pyplot as plt
def show_image(img, title="Image"):
"""
使用matplotlib显示OpenCV图像(自动处理BGR到RGB转换)
"""
if len(img.shape) == 3: # 彩色图像
# OpenCV使用BGR,matplotlib使用RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10, 6))
plt.imshow(img_rgb)
else: # 灰度图像
plt.figure(figsize=(10, 6))
plt.imshow(img, cmap='gray')
plt.title(title)
plt.axis('off')
plt.show()
# 使用示例
show_image(img_color, "原始图像")#3. 绘制基本图形
#3.1 创建空白画布
import cv2
import numpy as np
# 创建空白图像(黑色背景)
height, width = 400, 600
blank_img = np.zeros((height, width, 3), dtype=np.uint8)
# 创建白色背景图像
white_img = 255 * np.ones((height, width, 3), dtype=np.uint8)
# 创建指定颜色背景
blue_bg = np.full((height, width, 3), (255, 0, 0), dtype=np.uint8) # 蓝色背景#3.2 绘制直线
# 创建画布
img = np.zeros((400, 600, 3), dtype=np.uint8)
# 绘制直线:cv2.line(图像, 起点, 终点, 颜色(BGR), 线宽)
cv2.line(img, (50, 50), (550, 50), (0, 255, 0), 2) # 绿色直线
cv2.line(img, (50, 100), (550, 300), (255, 0, 0), 3) # 蓝色粗线
# 绘制虚线(自定义函数)
def draw_dashed_line(img, pt1, pt2, color, thickness=1, gap=10):
"""绘制虚线"""
dist = ((pt1[0] - pt2[0])**2 + (pt1[1] - pt2[1])**2)**0.5
dash_count = int(dist / gap)
for i in range(dash_count):
if i % 2 == 0: # 只绘制偶数段
start = (int(pt1[0] + (pt2[0] - pt1[0]) * i / dash_count),
int(pt1[1] + (pt2[1] - pt1[1]) * i / dash_count))
end = (int(pt1[0] + (pt2[0] - pt1[0]) * (i + 1) / dash_count),
int(pt1[1] + (pt2[1] - pt1[1]) * (i + 1) / dash_count))
cv2.line(img, start, end, color, thickness)
# 使用虚线函数
draw_dashed_line(img, (50, 200), (550, 200), (0, 255, 255), 2)#3.3 绘制矩形
# 绘制矩形:cv2.rectangle(图像, 左上角, 右下角, 颜色, 线宽(-1表示填充))
cv2.rectangle(img, (100, 100), (300, 200), (255, 0, 0), 2) # 空心矩形
cv2.rectangle(img, (350, 100), (500, 180), (0, 255, 0), -1) # 填充矩形
# 绘制圆角矩形(自定义函数)
def draw_rounded_rectangle(img, pt1, pt2, color, radius, thickness=1):
"""绘制圆角矩形"""
x1, y1 = pt1
x2, y2 = pt2
# 绘制四个圆角
cv2.circle(img, (x1 + radius, y1 + radius), radius, color, thickness)
cv2.circle(img, (x2 - radius, y1 + radius), radius, color, thickness)
cv2.circle(img, (x1 + radius, y2 - radius), radius, color, thickness)
cv2.circle(img, (x2 - radius, y2 - radius), radius, color, thickness)
# 绘制直线部分
cv2.line(img, (x1 + radius, y1), (x2 - radius, y1), color, thickness)
cv2.line(img, (x1 + radius, y2), (x2 - radius, y2), color, thickness)
cv2.line(img, (x1, y1 + radius), (x1, y2 - radius), color, thickness)
cv2.line(img, (x2, y1 + radius), (x2, y2 - radius), color, thickness)
# 使用圆角矩形函数
draw_rounded_rectangle(img, (100, 250), (250, 350), (255, 255, 0), 10, 2)#3.4 绘制圆形和椭圆
# 绘制圆形:cv2.circle(图像, 圆心, 半径, 颜色, 线宽)
cv2.circle(img, (450, 150), 50, (0, 0, 255), -1) # 填充红色圆形
# 绘制椭圆:cv2.ellipse(图像, 中心, 轴长, 旋转角度, 起始角, 结束角, 颜色, 线宽)
cv2.ellipse(img, (300, 300), (80, 40), 0, 0, 360, (255, 0, 255), 2) # 椭圆
# 绘制部分椭圆弧
cv2.ellipse(img, (400, 300), (60, 30), 45, 0, 180, (0, 255, 255), 3) # 椭圆弧#3.5 绘制多边形
# 绘制多边形
points = np.array([[100, 350], [150, 300], [200, 320], [180, 370], [120, 380]], np.int32)
points = points.reshape((-1, 1, 2))
# 绘制多边形:cv2.polylines(图像, 点集, 是否闭合, 颜色, 线宽)
cv2.polylines(img, [points], True, (255, 255, 255), 2) # 闭合多边形
# 填充多边形
cv2.fillPoly(img, [points], (128, 128, 128)) # 填充灰色#3.6 添加文字
# 添加文字:cv2.putText(图像, 文本, 位置, 字体, 大小, 颜色, 粗细)
cv2.putText(img, "Hello OpenCV!", (50, 350),
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
# 不同的字体样式
cv2.putText(img, "Normal Text", (50, 50),
cv2.FONT_HERSHEY_PLAIN, 1, (255, 255, 255), 1)
cv2.putText(img, "Complex Text", (50, 75),
cv2.FONT_HERSHEY_COMPLEX, 0.8, (255, 255, 255), 1)
# 带背景的文字(自定义函数)
def put_text_with_background(img, text, position, font, font_scale, color, thickness, bg_color=(0,0,0)):
"""添加带背景的文字"""
# 获取文本边界框
text_size = cv2.getTextSize(text, font, font_scale, thickness)[0]
# 计算背景矩形坐标
text_x, text_y = position
bg_top_left = (text_x, text_y - text_size[1] - 10)
bg_bottom_right = (text_x + text_size[0], text_y + 5)
# 绘制背景矩形
cv2.rectangle(img, bg_top_left, bg_bottom_right, bg_color, -1)
# 添加文字
cv2.putText(img, text, position, font, font_scale, color, thickness)
# 使用带背景文字函数
put_text_with_background(img, "带背景文字", (200, 50),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)#4. 几何变换详解
#4.1 图像缩放
import cv2
import numpy as np
img = cv2.imread("photo.jpg")
# 方法一:指定输出大小
resized_fixed = cv2.resize(img, (300, 200)) # (宽度, 高度)
# 方法二:指定缩放比例
resized_scaled = cv2.resize(img, None, fx=0.5, fy=0.5) # 宽高各缩小一半
# 方法三:保持宽高比的缩放
def resize_keep_aspect_ratio(image, target_width=None, target_height=None):
"""保持宽高比的缩放"""
h, w = image.shape[:2]
if target_width and target_height:
# 计算缩放比例,保持宽高比
scale = min(target_width/w, target_height/h)
new_w, new_h = int(w * scale), int(h * scale)
elif target_width:
scale = target_width / w
new_w, new_h = target_width, int(h * scale)
elif target_height:
scale = target_height / h
new_w, new_h = int(w * scale), target_height
else:
return image
return cv2.resize(image, (new_w, new_h))
# 使用示例
resized_aspect = resize_keep_aspect_ratio(img, target_width=400)
# 不同的插值方法
resized_cubic = cv2.resize(img, (800, 600), interpolation=cv2.INTER_CUBIC) # 放大用
resized_area = cv2.resize(img, (200, 150), interpolation=cv2.INTER_AREA) # 缩小用#4.2 图像旋转
def rotate_image(image, angle, center=None, scale=1.0):
"""
旋转图像
"""
h, w = image.shape[:2]
# 如果未指定中心点,则使用图像中心
if center is None:
center = (w // 2, h // 2)
# 获取旋转矩阵
rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
# 应用旋转
rotated = cv2.warpAffine(image, rotation_matrix, (w, h))
return rotated
# 基本旋转
img_rotated = rotate_image(img, 45) # 旋转45度
# 旋转并缩放
img_rotated_scaled = rotate_image(img, 30, scale=0.8)
# 完整旋转(保持完整图像)
def rotate_image_complete(image, angle):
"""完整旋转(防止裁剪)"""
h, w = image.shape[:2]
center = (w // 2, h // 2)
# 获取旋转矩阵
rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
# 计算旋转后的新边界
cos = abs(rotation_matrix[0, 0])
sin = abs(rotation_matrix[0, 1])
new_w = int((h * sin) + (w * cos))
new_h = int((h * cos) + (w * sin))
# 调整旋转矩阵的平移部分
rotation_matrix[0, 2] += (new_w / 2) - center[0]
rotation_matrix[1, 2] += (new_h / 2) - center[1]
# 应用旋转
rotated = cv2.warpAffine(image, rotation_matrix, (new_w, new_h))
return rotated
# 完整旋转示例
img_rotated_full = rotate_image_complete(img, 45)#4.3 仿射变换
def apply_affine_transform(image, src_points, dst_points):
"""
应用仿射变换
"""
# 获取仿射变换矩阵
matrix = cv2.getAffineTransform(src_points.astype(np.float32),
dst_points.astype(np.float32))
# 应用变换
h, w = image.shape[:2]
transformed = cv2.warpAffine(image, matrix, (w, h))
return transformed, matrix
# 仿射变换示例
h, w = img.shape[:2]
# 定义原图的三个点和目标位置
src_triangle = np.float32([[50, 50], [200, 50], [50, 200]])
dst_triangle = np.float32([[10, 100], [200, 50], [100, 250]])
img_affine, transform_matrix = apply_affine_transform(img, src_triangle, dst_triangle)
# 平行四边形变换
def parallelogram_transform(image):
"""平行四边形变换示例"""
h, w = image.shape[:2]
# 原图的四个角点
src_points = np.float32([
[0, 0], # 左上
[w-1, 0], # 右上
[0, h-1] # 左下
])
# 目标位置(创建倾斜效果)
dst_points = np.float32([
[50, 0], # 左上向右偏移
[w-1, 0], # 右上不变
[0, h-1] # 左下不变
])
matrix = cv2.getAffineTransform(src_points, dst_points)
transformed = cv2.warpAffine(image, matrix, (w, h))
return transformed
img_parallelogram = parallelogram_transform(img)#4.4 透视变换
def perspective_transform(image, src_points, dst_points):
"""
透视变换
"""
# 获取透视变换矩阵
matrix = cv2.getPerspectiveTransform(src_points.astype(np.float32),
dst_points.astype(np.float32))
# 应用变换
h, w = image.shape[:2]
transformed = cv2.warpPerspective(image, matrix, (w, h))
return transformed, matrix
# 透视变换示例:矫正倾斜的文档
def document_correction(image):
"""文档矫正示例"""
h, w = image.shape[:2]
# 假设原图是倾斜的矩形,四个角点
src_points = np.float32([
[100, 100], # 左上
[400, 50], # 右上
[80, 300], # 左下
[380, 280] # 右下
])
# 目标位置:标准矩形
dst_points = np.float32([
[0, 0], # 左上
[300, 0], # 右上
[0, 300], # 左下
[300, 300] # 右下
])
corrected, matrix = perspective_transform(image, src_points, dst_points)
return corrected
# 如果图像存在,应用文档矫正
# img_corrected = document_correction(img)#4.5 平移变换
def translate_image(image, dx, dy):
"""
图像平移
dx: 水平平移距离(正右负左)
dy: 垂直平移距离(正下负上)
"""
# 创建平移矩阵
translation_matrix = np.float32([
[1, 0, dx],
[0, 1, dy]
])
# 应用平移
h, w = image.shape[:2]
translated = cv2.warpAffine(image, translation_matrix, (w, h))
return translated
# 平移示例
img_translated = translate_image(img, 100, 50) # 向右平移100像素,向下平移50像素#5. 实战项目:图像几何变换工具
class ImageTransformationTool:
"""
图像几何变换工具类
"""
def __init__(self, image_path):
self.original_image = cv2.imread(image_path)
if self.original_image is None:
raise ValueError(f"无法读取图像: {image_path}")
self.current_image = self.original_image.copy()
def resize(self, width=None, height=None, fx=None, fy=None):
"""缩放图像"""
if width and height:
self.current_image = cv2.resize(self.current_image, (width, height))
elif fx and fy:
self.current_image = cv2.resize(self.current_image, None, fx=fx, fy=fy)
return self
def rotate(self, angle, scale=1.0):
"""旋转图像"""
h, w = self.current_image.shape[:2]
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, angle, scale)
self.current_image = cv2.warpAffine(self.current_image, matrix, (w, h))
return self
def translate(self, dx, dy):
"""平移图像"""
translation_matrix = np.float32([[1, 0, dx], [0, 1, dy]])
h, w = self.current_image.shape[:2]
self.current_image = cv2.warpAffine(self.current_image, translation_matrix, (w, h))
return self
def flip(self, flip_code):
"""翻转图像: 0垂直, 1水平, -1水平+垂直"""
self.current_image = cv2.flip(self.current_image, flip_code)
return self
def reset(self):
"""重置为原始图像"""
self.current_image = self.original_image.copy()
return self
def show(self, window_name="Transformed Image"):
"""显示当前图像"""
cv2.imshow(window_name, self.current_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
return self
def save(self, output_path):
"""保存图像"""
success = cv2.imwrite(output_path, self.current_image)
return success
# 使用示例
# tool = ImageTransformationTool("input.jpg")
# tool.rotate(45).resize(fx=0.8, fy=0.8).translate(50, 30).show()#相关教程
#6. 小结
OpenCV是计算机视觉领域不可或缺的工具,掌握其基本操作是学习计算机视觉的重要基础:
核心知识点总结:
- 图像读取/显示/保存:imread、imshow、imwrite
- 基本图形绘制:line、rectangle、circle、polylines、putText
- 几何变换:resize(缩放)、rotate(旋转)、warpAffine(仿射变换)、warpPerspective(透视变换)
- 色彩空间:注意OpenCV使用BGR而非RGB顺序
最佳实践:
- 在Jupyter环境中使用matplotlib显示图像,自动处理BGR到RGB转换
- 根据需求选择合适的插值方法(放大用INTER_CUBIC,缩小用INTER_AREA)
- 保持宽高比的缩放以避免图像变形
- 使用完整的旋转函数防止图像裁剪
💡 重要提醒:OpenCV使用BGR颜色顺序,不是标准的RGB!如果颜色显示异常,请检查通道顺序。
🔗 扩展阅读

