图像预处理
在计算机视觉和图像处理领域,图像预处理是一个重要的步骤,它能够提高后续处理(如特征提取、目标检测等)的准确性和效率。
OpenCV 提供了许多图像预处理的函数和方法,一些常见的图像预处理操作:
-
图像色彩空间转换
-
图像大小调整
-
图像仿射变换
-
图像翻转
-
图像裁剪
-
图像二值化处理
-
图像去噪
-
边缘检测
-
图像平滑处理
-
图像形态学
一、图像翻转
cv2.flip 是 OpenCV 库中的一个函数,用于翻转图像。翻转可以是水平翻转、垂直翻转或同时水平和垂直翻转。这个函数接受两个参数:要翻转的图像和一个指定翻转类型的标志。
import cv2
img = cv2.imread('../images/car.png')
"""
图像翻转
cv2.flip(src, flipCode[, dst])
- src:输入图像,可以是任意类型和深度的多通道图像。
- flipCode:指定翻转类型的整数标志:
- `0`:沿 X 轴翻转(垂直翻转)
- `1`:沿 Y 轴翻转(水平翻转)
- `-1`:沿 X 轴和 Y 轴翻转(同时水平和垂直翻转)
- dst:可选参数,输出图像。如果未提供,输出图像将与输入图像具有相同的尺寸和类型。
"""
# 垂直翻转 0
# f_img = cv2.flip(img, 0)
# 水平翻转 1
# f_img = cv2.flip(img, 1)
# 同时水平喝垂直翻转 -1
f_img = cv2.flip(img, -1)
cv2.imshow('old', img)
cv2.imshow('new', f_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、图像仿射变换
仿射变换(Affine Transformation)是一种线性变换,它保持了点之间的相对距离不变,即平行线在变换后仍然保持平行。在图像处理中,仿射变换常用于旋转、缩放、平移和剪切等操作。
1、图像旋转
旋转操作可以将图像绕着某个点旋转一定的角度。
import cv2
img = cv2.imread('../images/car.png')
"""
图像翻转
cv2.flip(src, flipCode[, dst])
- src:输入图像,可以是任意类型和深度的多通道图像。
- flipCode:指定翻转类型的整数标志:
- `0`:沿 X 轴翻转(垂直翻转)
- `1`:沿 Y 轴翻转(水平翻转)
- `-1`:沿 X 轴和 Y 轴翻转(同时水平和垂直翻转)
- dst:可选参数,输出图像。如果未提供,输出图像将与输入图像具有相同的尺寸和类型。
"""
# 垂直翻转 0
# f_img = cv2.flip(img, 0)
# 水平翻转 1
# f_img = cv2.flip(img, 1)
# 同时水平喝垂直翻转 -1
f_img = cv2.flip(img, -1)
cv2.imshow('old', img)
cv2.imshow('new', f_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
2、图像平移
平移操作可以将图像中的每个点沿着某个方向移动一定的距离。
import cv2
import numpy as np
img = cv2.imread('../images/car.png')
"""
图像平移
将图像中的每个点沿着某个方向移动一定的距离
"""
# 获取图像像素
(h, w) = img.shape[:2]
# 定义 平移水平和垂直移动的距离
# tx 和 ty 分别表示在x轴和y轴方向上的平移距离
ty = 50
tx = 100
# 创建平移矩阵
M = np.float32([[1, 0, tx], [0, 1, ty]])
# 应用平移变换
W_img = cv2.warpAffine(img, M, (w, h))
cv2.imshow('m', W_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
3、图像缩放
缩放操作可以改变图像的大小。
import cv2
import numpy as np
img = cv2.imread('../images/car.png')
(h, w) = img.shape[:2]
# 定义缩放参数
# 大于1 放大 小于1 缩小
# sx 和 sy 分别表示在x轴和y轴方向上的缩放因子
sx = 0.5
sy = 0.5
M = np.float32([[sx, 0, 0], [0, sy, 0]])
# 应用缩放变换
s_img = cv2.warpAffine(img, M, ((int(w*sx)), int(h*sy)))
# 显示结果
cv2.imshow('Scaled Image', s_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4、图像剪切
剪切操作可以改变图像的形状,使其在某个方向上倾斜。
import cv2
import numpy as np
img = cv2.imread('../images/car.png')
rows, cols = img.shape[:2]
"""
图像剪切
改变图像的形状,使其在某个方向上倾斜
"""
# 定义剪切因子
shx, shy = 0.1, 0.5
M = np.float32([[1, shx, 0], [shy, 1, 0]])
# 剪切图片
s_img = cv2.warpAffine(img, M, (cols, rows))
# 显示结果
cv2.imshow('Sheared Image', s_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
三、图像色彩空间转换
OpenCV中的色彩空间转换是将图像从一种颜色表示形式转换为另一种颜色表示形式的过程。常见的颜色空间包括RGB、HSV、YUV等。
作用
-
方便图像处理:在不同的颜色空间中,对应的通道代表了不同的属性,例如在RGB空间中,红、绿、蓝三个通道分别代表了颜色的强度,而在 HSV 空间中,H (色相)代表了颜色的种类,S (饱和度)代表了颜色的深浅,V (亮度)代表了颜色的明暗。因此,对于不同的处理需求,选择不同的颜色空间进行处理可以更加方便。
-
提高图像处理效果:在某些情况下,使用某些特定的颜色空间可以提高图像处理的效果。例如,在HSV空间中,可以通过调整 S (饱和度)和 V (亮度)来提高图像的对比度并去除噪点。
-
节省计算资源:在某些情况下,使用特定的颜色空间可以帮助我们节省计算资源。例如,在RGB空间中,每个像素需要3个通道来表示,而在灰度空间中,每个像素只需要一个通道就可以表示。因此,如果只需要处理亮度信息而不需要颜色信息时,将图像转换为灰度空间可以节省计算资源。
cv2.cvtColor()
是OpenCV中的一个函数,用于图像颜色空间的转换。它可以将一个图像从一个颜色空间转换为另一个颜色空间,比如从RGB到灰度图像的转换,或者从BGR到HSV的转换等。
cv2.cvtColor(src, code)
参数
-
src
:输入图像,可以是一个NumPy数组或者一个OpenCV的Mat对象。 -
code
:指定转换的类型,可以使用预定义的转换代码,例如cv2.COLOR_BGR2GRAY
表示从BGR到灰度图像的转换。
1、RGB转灰度图像
RGB 转 Gray(灰度),将彩色图像转换为灰度图像,可以减少数据量并简化算法。
import cv2
img = cv2.imread('../images/car.png')
"""
图像色彩空间转换
opencv 默认的图像格式为BGR
"""
# COLOR_BGR2GRAY BGR图像->灰度图像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
2、RGB转HSV
RGB 转 HSV,HSV(Hue, Saturation, Value)色彩空间在颜色分割和颜色识别中非常有用。
# cv2.COLOR_BGR2HSV BGR图像->HSV图像
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
四、图像二值化处理
cv2.threshold
是 OpenCV 中用于图像二值化的函数。它通过设置阈值将图像分为前景和背景,常用于图像处理和分析。
cv2.threshold
将灰度图像转换为二值图像,根据指定的阈值将像素值分为两类:高于阈值的像素设为一个值(通常是255),低于阈值的像素设为另一个值(通常是0)。
retval, dst = cv2.threshold(src, thresh, maxval, type)
参数
-
src: 输入的灰度图像。
-
thresh: 阈值,决定分割的界限。
-
maxval: 当像素值超过阈值时,赋予的最大值(通常为255)。
-
type
: 阈值类型,常用的有:
-
cv2.THRESH_BINARY
: 超过阈值的像素设为最大值,其余设为0。 -
cv2.THRESH_BINARY_INV
: 超过阈值的像素设为0,其余设为最大值。 -
cv2.THRESH_TRUNC
: 超过阈值的像素设为阈值,其余不变。 -
cv2.THRESH_TOZERO
: 超过阈值的像素不变,其余设为0。 -
cv2.THRESH_TOZERO_INV
: 超过阈值的像素设为0,其余不变。
-
返回值
-
retval: 实际使用的阈值(可能与输入值不同)。
-
dst: 输出的二值图像。
import cv2
"""
cv2.threshold
将灰度图像转换为二值图像
它通过设置阈值将图像分为前景和背景,常用于图像处理和分析。
根据指定的阈值将像素值分为两类:
高于阈值的像素设为一个值(通常是255)
低于阈值的像素设为另一个值(通常是0)
"""
# 读取图像并转换为灰度图
img = cv2.imread('../images/car.png')
g_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化处理
# rs 实际应用阈值 t_img 转换后的图像
rs, t_img = cv2.threshold(g_img, 100, 500, cv2.THRESH_BINARY)
# 显示结果
cv2.imshow('原图', img)
cv2.imshow('二值图像', t_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
五、图像掩模
通常用于创建掩模,以便从图像中提取特定颜色的区域。
cv2.inRange(src, lowerb, upperb)
import cv2
import numpy as np
"""
cv2.inRange(src, lowerb, upperb)
通常用于创建掩模,以便从图像中提取特定颜色的区域
参数
- src: 输入的图像,可以是彩色图像或灰度图像。
- lowerb: 颜色范围的下界(数组或元组),指定了要提取的颜色的最小值。
- upperb: 颜色范围的上界(数组或元组),指定了要提取的颜色的最大值。
返回值
返回一个二值图像:
白色部分表示在指定颜色范围内的区域;
黑色部分表示不在范围内的区域。
"""
img = cv2.imread('../images/car3.png')
# 把图像转换为HSV空间
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 获取蓝色所在的HSV范围
lowerb = np.array([100, 100, 50])
upperb = np.array([140, 255, 255])
# 创建掩模
mask = cv2.inRange(hsv_img, lowerb, upperb)
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
六、图像检测轮廓
cv2.findContours
函数可以在二值图像中找到轮廓,并返回轮廓的点集。轮廓可以用来表示物体的边界,常用于物体检测、分割和形状分析。
contours, hierarchy = cv2.findContours(image, mode, method)
参数
-
image: 输入的二值图像。通常在调用该函数之前需要将图像转换为灰度图像并进行二值化处理(如使用
cv2.threshold
或cv2.Canny
)。 -
mode
: 轮廓检索模式:
-
cv2.RETR_EXTERNAL
: 只检索外部轮廓。 -
cv2.RETR_LIST
: 检索所有轮廓,并将其放入列表中。 -
cv2.RETR_TREE
: 检索所有轮廓,并建立层级关系。
-
-
method
: 轮廓逼近方法:
-
cv2.CHAIN_APPROX_SIMPLE
: 压缩轮廓,仅保留端点。 -
cv2.CHAIN_APPROX_NONE
: 保留所有轮廓点。
-
返回值
-
contours: 一个 Python 列表,其中每个元素是一个轮廓(即一组点),轮廓的点以 NumPy 数组的形式存储。
-
hierarchy: 轮廓的层级信息,包含轮廓之间的关系。
import cv2
import numpy as np
"""
cv2.findContours
可以在二值图像中找到轮廓,并返回轮廓的点集。
轮廓可以用来表示物体的边界,常用于物体检测、分割和形状分析。
contours, hierarchy = cv2.findContours(image, mode, method)
参数
1. image: 输入的二值图像。
通常在调用该函数之前需要将图像转换为灰度图像并进行二值化处理
(如使用 `cv2.threshold` 或 `cv2.Canny`)。
2. mode: 轮廓检索模式:
- cv2.RETR_EXTERNAL: 只检索外部轮廓。
- cv2.RETR_LIST: 检索所有轮廓,并将其放入列表中。
- cv2.RETR_TREE: 检索所有轮廓,并建立层级关系。
3. method: 轮廓逼近方法:
- cv2.CHAIN_APPROX_SIMPLE: 压缩轮廓,仅保留端点。
- cv2.CHAIN_APPROX_NONE: 保留所有轮廓点。
返回值
- contours: 一个 Python 列表,其中每个元素是一个轮廓(即一组点),轮廓的点以 NumPy 数组的形式存储。
- hierarchy: 轮廓的层级信息,包含轮廓之间的关系。
"""
img = cv2.imread('../images/car3.png')
# 把图像转换为HSV空间
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 获取蓝色所在的HSV范围
lowerb = np.array([100, 100, 50])
upperb = np.array([140, 255, 255])
# 创建掩模
mask = cv2.inRange(hsv_img, lowerb, upperb)
# 二值化处理
ret, b_img = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
# 检测轮廓
# cv2.RETR_EXTERNAL: 只检索外部轮廓 CHAIN_APPROX_SIMPLE: 压缩轮廓,仅保留端点
contours, hierarchy = cv2.findContours(b_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# cv2.RETR_LIST: 检索所有轮廓,并将其放入列表中
# contours, hierarchy = cv2.findContours(b_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 灰度图像转换为彩色图像 COLOR_GRAY2BGR
bgr_img = cv2.cvtColor(b_img, cv2.COLOR_GRAY2BGR)
# 绘制轮廓
output_img = cv2.drawContours(bgr_img, contours, -1, (0, 255, 0), 1)
# # 获取绘制轮廓的边界框
# for c in contours:
# x, y, w, h = cv2.boundingRect(c)
# print(x, y, w, h)
# 边界框 405 299 225 73
cv2.rectangle(output_img, (405, 299), (405+225, 299+73), (0, 0, 255), 2)
# 显示结果
cv2.imshow('output', output_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
练习:对车牌的分隔提取
import cv2
import numpy as np
img = cv2.imread('../images/car3.png')
"""
创建掩模->方便缩小识别范围->限定在车牌
"""
# 把图像转换为HSV空间
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
"""
例图中的车牌背景色都为蓝色->获取蓝色所在的HSV范围
"""
lowerb = np.array([100, 100, 50])
upperb = np.array([140, 255, 255])
# 创建掩模
mask = cv2.inRange(hsv_img, lowerb, upperb)
# 二值化处理
ret, b_img = cv2.threshold(mask, 125, 255, cv2.THRESH_BINARY)
# 获取图片轮廓
contours, hierarchy = cv2.findContours(b_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
"""
根据找到的车牌大小估计识别范围
"""
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
# print(x, y, w, h)
# 绘制矩形 326 170 168 54
if w > 150 and h > 45:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 截取车牌号
end_img = img[y:y+h, x:x+w]
# 显示结果
cv2.imshow('old', img)
cv2.imshow('output', end_img)
cv2.waitKey(0)
cv2.destroyAllWindows()