Python OpenCV精讲系列 - 图像处理基础(二)
💖💖⚡️⚡️专栏:Python OpenCV精讲⚡️⚡️💖💖
本专栏聚焦于Python结合OpenCV库进行计算机视觉开发的专业教程。通过系统化的课程设计,从基础概念入手,逐步深入到图像处理、特征检测、物体识别等多个领域。适合希望在计算机视觉方向上建立坚实基础的技术人员及研究者。每一课不仅包含理论讲解,更有实战代码示例,助力读者快速将所学应用于实际项目中,提升解决复杂视觉问题的能力。无论是入门者还是寻求技能进阶的开发者,都将在此收获满满的知识与实践经验。
1. 图像缩放
图像缩放是一种常见的图像处理技术,用于改变图像的尺寸。OpenCV提供了cv2.resize()
函数来实现这一功能。
1.1 缩放函数详解
resized = cv2.resize(image, dsize, fx=None, fy=None, interpolation=None)
-
参数:
image
:输入图像。dsize
:输出图像的尺寸(宽度,高度),或者如果设置了fx
和fy
则可以省略。fx
:水平方向上的缩放系数。fy
:垂直方向上的缩放系数。interpolation
:插值方法,常用的有cv2.INTER_LINEAR
(线性插值)、cv2.INTER_CUBIC
(三次样条插值)和cv2.INTER_NEAREST
(最近邻插值)等。
-
返回值:
resized
:缩放后的图像。
-
注意事项:
- 当
dsize
未设置时,必须同时设置fx
和fy
。 - 插值方法的选择会影响缩放后的图像质量。例如,
cv2.INTER_LINEAR
适用于一般情况,而cv2.INTER_CUBIC
适用于高质量缩放。 - 缩放系数大于1表示放大图像,小于1表示缩小图像。
- 当
-
详细解释:
-
缩放系数
fx
和fy
:- 缩放系数用于控制图像在水平方向和垂直方向上的缩放比例。例如,
fx=0.5
和fy=0.5
表示将图像缩小一半;fx=2
和fy=2
表示将图像放大两倍。 - 如果仅设置
fx
或fy
,另一个方向上的缩放系数将默认与已设置的缩放系数相同。
- 缩放系数用于控制图像在水平方向和垂直方向上的缩放比例。例如,
-
插值方法:
- 最近邻插值 (
cv2.INTER_NEAREST
):这是一种最简单的插值方法,它根据最近的像素值来确定新像素的颜色。这种方法速度快,但在缩放时可能会产生明显的锯齿效应。 - 线性插值 (
cv2.INTER_LINEAR
):这是一种较为常用的插值方法,它根据周围四个像素的值来计算新像素的颜色。这种方法可以减少锯齿效应,适用于一般情况。 - 三次样条插值 (
cv2.INTER_CUBIC
):这是一种更复杂的插值方法,它根据周围多个像素的值来计算新像素的颜色。这种方法能够提供更好的图像质量,适用于需要高质量缩放的情况。
- 最近邻插值 (
-
缩放操作的注意事项:
- 缩放操作可能会导致图像失真,尤其是在大幅度放大或缩小的情况下。
- 使用适当的插值方法可以减少失真,提高图像质量。
- 缩放操作不会改变原始图像,而是生成一个新的缩放后的图像。
-
1.2 示例代码
import cv2def resize_image(image_path, scale_percent, interpolation_method):# 读取图像image = cv2.imread(image_path)if image is None:print("Error: File not found!")return# 缩放比例width = int(image.shape[1] * scale_percent / 100)height = int(image.shape[0] * scale_percent / 100)dsize = (width, height)# 缩放图像resized = cv2.resize(image, dsize=dsize, interpolation=interpolation_method)# 显示图像cv2.imshow('Resized Image', resized)cv2.waitKey(0)cv2.destroyAllWindows()if __name__ == "__main__":image_path = 'path/to/your/image.jpg'scale_percent = 50 # 缩放比例interpolation_method = cv2.INTER_LINEAR # 线性插值resize_image(image_path, scale_percent, interpolation_method)
2. 图像旋转
图像旋转可以用来改变图像的方向。OpenCV提供了cv2.getRotationMatrix2D()
和cv2.warpAffine()
函数来实现图像旋转。
2.1 旋转函数详解
rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(image, rotation_matrix, (width, height))
-
参数:
center
:旋转中心点。angle
:旋转角度(逆时针方向)。scale
:缩放系数。width
和height
:输出图像的尺寸。
-
返回值:
rotation_matrix
:旋转矩阵。rotated
:旋转后的图像。
-
注意事项:
- 旋转中心点通常是图像的几何中心,可以通过
(image.shape[1] // 2, image.shape[0] // 2)
计算得到。 - 旋转操作可能导致图像的一部分被裁剪掉。为了避免这种情况,可以在旋转前先调整输出图像的尺寸。
- 缩放系数为1表示不缩放,大于1表示放大,小于1表示缩小。
- 旋转中心点通常是图像的几何中心,可以通过
-
详细解释:
-
旋转矩阵
cv2.getRotationMatrix2D()
:- 这个函数用于计算图像旋转所需的仿射变换矩阵。矩阵的形式如下:
[
\begin{bmatrix}
\cos(\theta) & -\sin(\theta) \
\sin(\theta) & \cos(\theta) \
\end{bmatrix}
] - 其中
\(\theta\)
是旋转的角度,cos(\theta)
和sin(\theta)
分别对应旋转矩阵的第一行和第二行的第一个元素。 - 旋转矩阵还包括平移部分,用于移动图像以适应旋转后的尺寸变化。
- 这个函数用于计算图像旋转所需的仿射变换矩阵。矩阵的形式如下:
-
仿射变换
cv2.warpAffine()
:- 这个函数用于应用仿射变换矩阵到图像上,从而实现图像的旋转。
- 仿射变换不仅可以用于旋转,还可以用于缩放和平移等操作。
- 输出图像的尺寸
width
和height
需要根据旋转角度和缩放系数来计算,以确保旋转后的图像完整显示。
-
旋转操作的注意事项:
- 旋转操作可能会导致图像的一部分被裁剪掉,特别是在旋转角度较大时。
- 为了避免裁剪,可以在旋转前计算旋转后的图像尺寸,并使用这个尺寸作为
cv2.warpAffine()
的输出尺寸。 - 旋转操作不会改变原始图像,而是生成一个新的旋转后的图像。
-
2.2 示例代码
import cv2
import numpy as npdef rotate_image(image_path, angle, scale):# 读取图像image = cv2.imread(image_path)if image is None:print("Error: File not found!")return# 获取图像中心center = (image.shape[1] // 2, image.shape[0] // 2)# 计算旋转矩阵rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)# 调整输出图像的尺寸以避免裁剪cos = np.abs(rotation_matrix[0, 0])sin = np.abs(rotation_matrix[0, 1])nW = int((image.shape[0] * sin) + (image.shape[1] * cos))nH = int((image.shape[0] * cos) + (image.shape[1] * sin))# 调整旋转矩阵以适应新的尺寸rotation_matrix[0, 2] += (nW / 2) - center[0]rotation_matrix[1, 2] += (nH / 2) - center[1]# 应用仿射变换rotated = cv2.warpAffine(image, rotation_matrix, (nW, nH))# 显示图像cv2.imshow('Rotated Image', rotated)cv2.waitKey(0)cv2.destroyAllWindows()if __name__ == "__main__":image_path = 'path/to/your/image.jpg'angle = 45 # 旋转角度scale = 1.0 # 缩放系数rotate_image(image_path, angle, scale)
3. 图像裁剪
图像裁剪用于从原始图像中提取感兴趣的部分。OpenCV可以通过简单的NumPy数组索引来实现图像裁剪。
3.1 裁剪函数详解
cropped = image[y1:y2, x1:x2]
-
参数:
y1
,y2
:裁剪区域的起始和结束行坐标。x1
,x2
:裁剪区域的起始和结束列坐标。
-
返回值:
cropped
:裁剪后的图像。
-
注意事项:
- 索引是从0开始的,因此
y1
和x1
通常为0,除非你想要从图像的某个位置开始裁剪。 - 裁剪操作不会改变原始图像,而是返回一个新的裁剪后的图像。
- 索引是从0开始的,因此
-
详细解释:
-
裁剪操作:
- 裁剪操作是通过简单的NumPy数组索引来实现的。例如,
image[y1:y2, x1:x2]
表示从图像的y1
行到y2
行、x1
列到x2
列之间进行裁剪。 - NumPy数组索引遵循Python的标准切片规则,即
start:end
表示从start
(包含)到end
(不包含)之间的元素。
- 裁剪操作是通过简单的NumPy数组索引来实现的。例如,
-
裁剪操作的注意事项:
- 确保裁剪区域的坐标在图像的有效范围内,否则会导致错误。
- 裁剪操作不会改变原始图像,而是生成一个新的裁剪后的图像。
-
3.2 示例代码
import cv2def crop_image(image_path, y1, y2, x1, x2):# 读取图像image = cv2.imread(image_path)if image is None:print("Error: File not found!")return# 裁剪图像cropped = image[y1:y2, x1:x2]# 显示图像cv2.imshow('Cropped Image', cropped)cv2.waitKey(0)cv2.destroyAllWindows()if __name__ == "__main__":image_path = 'path/to/your/image.jpg'y1, y2, x1, x2 = 100, 400, 100, 400 # 裁剪区域crop_image(image_path, y1, y2, x1, x2)
4. 综合示例
接下来,我们将结合上述三种技术,创建一个综合示例。在这个示例中,我们将读取一张图像,对其进行缩放、旋转和裁剪,最后显示处理后的图像。
import cv2
import numpy as npdef process_image(image_path):# 读取图像image = cv2.imread(image_path)if image is None:print("Error: File not found!")return# 缩放图像scale_percent = 50width = int(image.shape[1] * scale_percent / 100)height = int(image.shape[0] * scale_percent / 100)dsize = (width, height)resized = cv2.resize(image, dsize=dsize, interpolation=cv2.INTER_LINEAR)# 旋转图像center = (resized.shape[1] // 2, resized.shape[0] // 2)angle = 45scale = 1.0rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)# 调整输出图像的尺寸以避免裁剪cos = np.abs(rotation_matrix[0, 0])sin = np.abs(rotation_matrix[0, 1])nW = int((resized.shape[0] * sin) + (resized.shape[1] * cos))nH = int((resized.shape[0] * cos) + (resized.shape[1] * sin))# 调整旋转矩阵以适应新的尺寸rotation_matrix[0, 2] += (nW / 2) - center[0]rotation_matrix[1, 2] += (nH / 2) - center[1]# 应用仿射变换rotated = cv2.warpAffine(resized, rotation_matrix, (nW, nH))# 裁剪图像y1, y2, x1, x2 = 100, 400, 100, 400cropped = rotated[y1:y2, x1:x2]# 显示图像cv2.imshow('Processed Image', cropped)cv2.waitKey(0)cv2.destroyAllWindows()if __name__ == "__main__":image_path = 'path/to/your/image.jpg'process_image(image_path)
5. 小结
在本篇文章中,我们详细介绍了如何使用OpenCV进行图像的缩放、旋转和裁剪。这些技术在图像处理中非常常见,并且是许多高级应用的基础。接下来的文章将涉及更复杂的图像处理技术,如图像滤波、边缘检测等。