文章目录
- 先言
- 一、图像颜色空间转换
- 1.RGB颜色空间
- 2.颜色加法
- 3.颜色加权加法
- 4.HSV颜色空间
- 5.图像转换(cvtColor())
- 二、灰度实验
- 1.灰度图
- 2.图像灰度化(最大值法)
- 3.图像灰度化(平均值法)
- 4.图像灰度化(加权平均值法)
- 三、图像二值化
- 1.阈值法(THRESH_BINARY)和反阈值法(THRESH_BINARY_INV)
- 2.截断阈值法(THRESH_TRUNC)
- 3.低阈值零处理(THRESH_TOZERO)与超阈值零处理(THRESH_TOZERO_INV)
- 4.OTSU阈值法(threshold())
- 5.自适应二值化(adaptiveThreshold())
- 四、图像镜像翻转与仿射变换
- 1.图像翻转(图像镜像旋转)
- 2.图像旋转
- 3.图像平移
- 4.图像缩放
- 结语
先言
在计算机视觉任务中,图像预处理是至关重要的一环。无论是目标检测、人脸识别还是图像分类,原始图像数据往往需要经过一系列变换才能更好地被算法理解。OpenCV 提供了强大的图像处理工具,帮助我们高效完成这些预处理操作。
本文将重点介绍 图像颜色空间转换、灰度化实验、二值化处理、镜像翻转 和 仿射变换
等核心预处理技术,通过代码示例和效果对比,带你掌握如何用 OpenCV 优化图像数据
一、图像颜色空间转换
OpenCV中,图像色彩空间转换是一个非常基础且重要的操作,就是将图像从一种颜色表示形式转换为另一种表示形式的过程。通过将图像从一个色彩空间转换到另一个色彩空间,可以更好地进行特定类型的图像处理和分析任务。常见的颜色空间包括RGB、HSV、YUV等。
-
色彩空间转换的作用
-
提高图像处理效果
-
节省计算资源
-
1.RGB颜色空间
在图像处理中,最常见的就是RGB颜色空间。RGB颜色空间是我们接触最多的颜色空间,是一种用于表示和显示彩色图像的一种颜色模型。RGB代表红色(Red)、绿色(Green)和蓝色(Blue),这三种颜色通过不同强度的光的组合来创建其他颜色,广泛应用于我们的生活中,比如电视、电脑显示屏以及上面实验中所介绍的RGB彩色图。
RGB颜色模型基于笛卡尔坐标系,如下图所示,RGB原色值位于3个角上,二次色青色、红色和黄色位于另外三个角上,黑色位于原点处,白色位于离原点最远的角上。因为黑色在RGB三通道中表现为(0,0,0),所以映射到这里就是原点;而白色是(255,255,255),所以映射到这里就是三个坐标为最大值的点。
RGB颜色空间可以产生大约1600万种颜色,几乎包括了世界上的所有颜色,也就是说可以使用RGB颜色空间来生成任意一种颜色。
注意:在OpenCV中,颜色是以BGR的方式进行存储的,而不是RGB,这也是上面红色的像素值是(0,0,255)而不是(255,0,0)的原因。
2.颜色加法
你可以使用OpenCV的cv.add()函数把两幅图像相加,或者可以简单地通过numpy操作添加两个图像,如res = img1 + img2。两个图像应该具有相同的大小和类型。
cv.add()
饱和运算:
import cv2 as cv
#读取两个图像
cao = cv.imread("../images/cao.png")
pig = cv.imread("../images/pig.png")
#cv的饱和操作add(img1,img2)
dst1 = cv.add(cao,pig)
cv.imshow("add",dst1)
cv.waitKey(0)
cv.destroyAllWindows()
numpy 直接加法:
import cv2 as cv
import numpy as np#读取图像
cao = cv.imread("../images/cao.png")
pig = cv.imread("../images/pig.png")
#numpy直接相加,取模运算 对256取模 250+10=4
dst2 = cao+pig
cv.imshow("numpy",dst2)
cv.waitKey(0)
cv.destroyAllWindows()
OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算。
3.颜色加权加法
cv2.addWeighted(src1,alpha,src2,deta,gamma)
src1
、src2
:输入图像。alpha
、beta
:两张图象权重。gamma
:亮度调整值。gamma > 0
,图像会变亮。gamma < 0
,图像会变暗。gamma = 0
,则没有额外的亮度调整。
这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。图像混合的计算公式如下:
g(x) = (1−α)f0(x) + αf1(x)
通过修改 α 的值(0 → 1),可以实现非常炫酷的混合。
现在我们把两幅图混合在一起。第一幅图的权重是0.7,第二幅图的权重是0.3。函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。
dst = α⋅img1 + β⋅img2 + γ
示例:
import cv2 as cv
#读取图像
cao = cv.imread("../images/cao.png")
pig = cv.imread("../images/pig.png")
#加权颜色加法cv.addWeighted(img1,alpha,img2,beta,gamma)
dst3 = cv.addWeighted(cao,0.5,pig,0.6,15)
cv.imshow("addWeighted",dst3)
cv.waitKey(0)
cv.destroyAllWindows()
4.HSV颜色空间
HSV颜色空间指的是HSV颜色模型,这是一种与RGB颜色模型并列的颜色空间表示法。RGB颜色模型使用红、绿、蓝三原色的强度来表示颜色,是一种加色法模型,即颜色的混合是添加三原色的强度。而HSV颜色空间使用色调(Hue)、饱和度(Saturation)和亮度(Value)三个参数来表示颜色,色调H表示颜色的种类,如红色、绿色、蓝色等;饱和度表示颜色的纯度或强度,如红色越纯,饱和度就越高;亮度表示颜色的明暗程度,如黑色比白色亮度低。
HSV颜色模型是一种六角锥体模型,如下图所示:
色调H:
使用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°。通过改变H的值,可以选择不同的颜色
饱和度S:
饱和度S表示颜色接近光谱色的程度。一种颜色可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例越大,颜色接近光谱色的程度就越高,颜色的饱和度就越高。饱和度越高,颜色就越深而艳,光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,其中0%表示灰色或无色,100%表示纯色,通过调整饱和度的值,可以使颜色变得更加鲜艳或者更加灰暗。
明度V:
明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白),通过调整明度的值,可以使颜色变得更亮或者更暗。
一般对颜色空间的图像进行有效处理都是在HSV空间进行的,然后对于基本色中对应的HSV分量需要给定一个严格的范围,下面是通过实验计算的模糊范围(准确的范围在网上都没有给出)。
H: 0— 180
S: 0— 255
V: 0— 255
此处把部分红色归为紫色范围:
为什么有了RGB颜色空间我们还是需要转换成HSV颜色空间来进行图像处理呢?
- 符合人类对颜色的感知方式:人类对颜色的感知是基于色调、饱和度和亮度三个维度的,而HSV颜色空间恰好就是通过这三个维度来描述颜色的。因此,使用HSV空间处理图像可以更直观地调整颜色和进行色彩平衡等操作,更符合人类的感知习惯。
- 颜色调整更加直观:在HSV颜色空间中,色调、饱和度和亮度的调整都是直观的,而在RGB颜色空间中调整颜色不那么直观。例如,在RGB空间中要调整红色系的颜色,需要同时调整R、G、B三个通道的数值,而在HSV空间中只需要调整色调和饱和度即可。
- 降维处理有利于计算:在图像处理中,降维处理可以减少计算的复杂性和计算量。HSV颜色空间相对于RGB颜色空间,减少了两个维度(红、绿、蓝),这有利于进行一些计算和处理任务,比如色彩分割、匹配等。
因此,在进行图片颜色识别时,我们会将RGB图像转换到HSV颜色空间,然后根据颜色区间来识别目标颜色。
5.图像转换(cvtColor())
cv2.cvtColor
是OpenCV中的一个函数,用于图像颜色空间的转换。可以将一个图像从一个颜色空间转换为另一个颜色空间,比如从RGB到灰度图,或者从RGB到HSV的转换等。
cv2.cvtColor(img,code)
img
:输入图像,可以是一个Numpy数组绘着一个OpenCV的Mat对象Mat
是一个核心的数据结构,主要用于存储图像和矩阵数据。在 Python 中使用 OpenCV 时,通常直接处理的是 NumPy 数组,cv2
模块自动将Mat
对象转换为 NumPy 数组。二者之间的转换是透明且自动完成的。例如,当你使用cv2.imread()
函数读取图像时,返回的是一个 NumPy 数组,但在C++中则是Mat
对象。
code
:指定转换的类型,可以使用预定义的转换代码。- 例如
cv2.COLOR_RGB2GRAY
表示从rgb到灰度图像的转换。
- 例如
代码示例:
import cv2 as cv
#读取图像
img = cv.imread("../images/1.jpg")
#颜色转换 cv.cvtColor(img,code)code这里表示转化模式
#BGR to GRAY
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#BGR to HSV
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
#BGR to RGB
rgb = cv.cvtColor(img,cv.COLOR_BGR2RGB)
cv.imshow("gray",gray)
cv.imshow("hsv",hsv)
cv.imshow("rgb",rgb)
cv.waitKey(0)
cv.destroyAllWindows()
二、灰度实验
将彩色图像转换为灰度图像的过程称为灰度化,这种做法在图像处理和计算机视觉领域非常常见。
灰度图与彩色图最大的不同就是:彩色图是由R、G、B三个通道组成,而灰度图只有一个通道,也称为单通道图像,所以彩色图转成灰度图的过程本质上就是将R、G、B三通道合并成一个通道的过程。本实验中一共介绍了三种合并方法,分别是最大值法、平均值法以及加权均值法。
1.灰度图
每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;但是,灰度图像在黑色与白色之间还有许多级的颜色深度。灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,用于显示的灰度图像通常用每个采样像素8位的非线性尺度来保存,这样可以有256级灰度。
import cv2 as cv
#读取图像
img = cv.imread("../images/1.jpg")
#颜色转换 cv.cvtColor(img,code)
#BGR to GRAY
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
print(gray.shape) #shape:(h,w)
在上述代码中将一张BGR图像转为灰度图查看他的维度,发现这是一张二维图像,原本的三通道(一维数组)转换为一个零维常量(指8位非线性尺寸0~255)
储存在二维数组中
2.图像灰度化(最大值法)
实现对彩色图像的灰度化有三种方式,其中最大值法对于彩色图像的每个像素,它会从R、G、B三个通道的值中选出最大的一个,并将其作为灰度图像中对应位置的像素值。
代码如下(示例):
import cv2 as cv
import numpy as np
#读取图像
src = cv.imread("../images/lvbo3.png")
#创建一个新的图像,用于保存结果
img = np.zeros((src.shape[0],src.shape[1]),dtype=src.dtype)
#循环遍历图像的每一个像素
for i in range(src.shape[0]):for j in range(src.shape[1]):# #修改像素值img[i,j]=max(src[i,j,0],src[i,j,1],src[i,j,2])
cv.imshow("result",img)
cv.waitKey(0)
cv.destroyAllWindows()
3.图像灰度化(平均值法)
对于彩色图像的每个像素,它会将R、G、B三个通道的像素值全部加起来,然后再除以三,得到的平均值就是灰度图像中对应位置的像素值。
代码如下(示例):
import cv2 as cv
import numpy as np
#读取图像
src = cv.imread("../images/lvbo3.png")
#创建一个新的图像,用于保存结果
img = np.zeros((src.shape[0],src.shape[1]),dtype=src.dtype)
#循环遍历图像的每一个像素
for i in range(src.shape[0]):for j in range(src.shape[1]):#转为更大的数据类型,防止溢出img[i,j]=(int(src[i,j,0])+int(src[i,j,1])+int(src[i,j,2]))//3
cv.imshow("result",img)
cv.waitKey(0)
cv.destroyAllWindows()
4.图像灰度化(加权平均值法)
对于彩色图像的每个像素,它会按照一定的权重去乘以每个通道的像素值,并将其相加,得到最后的值就是灰度图像中对应位置的像素值。本实验中,权重的比例为: R乘以0.299,G乘以0.587,B乘以0.114
,这是经过大量实验得到的一个权重比例,也是一个比较常用的权重比例(在上面讲到对图像颜色空间转换的cvtColor函数cv.COLOR_BGR2GRAY实现的图像灰度化比例一致
)。
所使用的权重之和应该等于1。这是为了确保生成的灰度图像素值保持在合理的亮度范围内,并且不会因为权重的比例不当导致整体过亮或过暗。
代码如下(示例):
import cv2 as cv
import numpy as np
#读取图像
src = cv.imread("../images/lvbo3.png")
#创建一个新的图像,用于保存结果
img = np.zeros((src.shape[0],src.shape[1]),dtype=src.dtype)
#定义权重
wb,wg,wr = 0.114,0.587,0.299
#循环遍历图像的每一个像素
for i in range(src.shape[0]):for j in range(src.shape[1]):img[i,j] = round(wb*src[i,j,0]+wg*src[i,j,1]+wr*src[i,j,2])
cv.imshow("result",img)
cv.waitKey(0)
cv.destroyAllWindows()
三、图像二值化
图像二值化处理:将某张图像的所有像素改成只有两种值之一
。
一幅二值图像的二维矩阵仅由0、1两个值构成,“0”代表黑色,“1”代白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。
其操作的图像也必须是灰度图
。也就是说,二值化的过程,就是将一张灰度图上的像素根据某种规则修改为0和maxval(maxval表示最大值,一般为255,显示白色)两种像素值,使图像呈现黑白的效果,能够帮助我们更好地分析图像中的形状、边缘和轮廓等特征。
- 简便:降低计算量和计算需求,加快处理速度。
- 节约资源:二值图像占用空间远小于彩色图。
- 边缘检测:二值化常作为边缘检测的预处理步骤,因为简化后的图易于识别出轮廓和边界。
1.阈值法(THRESH_BINARY)和反阈值法(THRESH_BINARY_INV)
全局阈值法:
_,binary = cv2.threshold(img,thresh,maxval,type)
img
:输入图像,要进行二值化处理的灰度图。thresh
:设定的阈值。当像素值大于(或小于,取决于阈值类型)thresh
时,该像素被赋予的值。type
:阈值处理的类型。- 返回值:
- 第一个值(通常用下划线表示):计算出的阈值,若使用自适应阈值法,会根据算法自动计算出这个值。
- 第二个值(binary):二值化后的图像矩阵。与输入图像尺寸相同。
代码如下(示例):
import cv2 as cv
#读取图像
flower = cv.imread('../images/flower.png')
#灰度处理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))#二值化处理 阈值法(大于阈值为maxval,小于阈值为0)
_, binary = cv.threshold(gray,200,255,cv.THRESH_BINARY)
cv.imshow("binary",binary)#二值化处理 反阈值法(大于阈值的为0,小于阈值为maxval)
_, inv = cv.threshold(gray,200,255,cv.THRESH_BINARY_INV)
cv.imshow("inv",inv)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果:
2.截断阈值法(THRESH_TRUNC)
截断阈值法,指将灰度图中的所有像素与阈值进行比较,像素值大于阈值的部分将会被修改为阈值,小于等于阈值的部分不变(当阈值为255时二值化处理的灰度图与原灰度图没有区别
)。
换句话说,经过截断阈值法处理过的二值化图中的最大像素值就是阈值。
代码如下(示例):
import cv2 as cv
#读取图像
flower = cv.imread('../images/flower.png')
#灰度处理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#截断阈值法(大于阈值等于阈值,小于阈值不变)
_, trunc = cv.threshold(gray,200,0,cv.THRESH_TRUNC)
cv.imshow("trunc",trunc)
cv.waitKey(0)
cv.destroyAllWindows()
使用截断阈值法进行图像二值化处理时,设置的maxval
参数实际上是不起作用的(如图):
3.低阈值零处理(THRESH_TOZERO)与超阈值零处理(THRESH_TOZERO_INV)
- 低阈值零处理,像素值小于等于阈值的部分被置为0(黑色),像素值大于阈值部分不变。
- 超阈值零处理,像素值大于阈值的部分置为0(黑色),像素值小于等于阈值的部分不变。
代码如下(示例):
import cv2 as cv
#读取图像
flower = cv.imread('../images/flower.png')
#灰度处理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#低阈值零处理(低于阈值为0,高于阈值不变)
_, tozero = cv.threshold(gray,127,0,cv.THRESH_TOZERO)
cv.imshow("tozero",tozero)
#超阈值零处理(高于阈值为0,低于阈值不变)
_, tozero_inv = cv.threshold(gray,127,0,cv.THRESH_TOZERO_INV)
cv.imshow("tozero_inv",tozero_inv)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果如下:
4.OTSU阈值法(threshold())
cv2.THRESH_OTS 并不是一个有效的阈值类型或标。THRESH_OTSU
本身并不是一个独立的阈值化方法,而是与 OpenCV 中的二值化方法结合使用的一个标志。具体来说,THRESH_OTSU
通常与 THRESH_BINARY
或 THRESH_BINARY_INV
结合使用。在实际应用中,如果你使用 THRESH_OTSU
标志但没有指定其他二值化类型,默认情况下它会与 THRESH_BINARY
结合使用。也就是说,当你仅指定了 cv2.THRESH_OTSU
,实际上等同于同时指定了 cv2.THRESH_BINARY + cv2.THRESH_OTSU
。
代码如下(示例):
import cv2 as cv
#读取图像
flower = cv.imread('../images/flower.png')
#灰度处理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))#OTSU阈值法(thresh)由函数计算得到,默认结合阈值法
_,otsu = cv.threshold(gray,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
cv.imshow("otsu",otsu)
#OTSU结合反阈值法
_,otsu_inv = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
cv.imshow("otsu_inv",otsu_inv)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果:
5.自适应二值化(adaptiveThreshold())
与二值化算法相比,自适应二值化更加适合用在明暗分布不均的图片,因为图片的明暗不均,导致图片上的每一小部分都要使用不同的阈值进行二值化处理,这时候传统的二值化算法就无法满足我们的需求了,于是就出现了自适应二值化。
cv2.adaptiveThreshold(image_np_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 7, 10)
其中各个参数的含义如下:
maxval
:最大阈值,一般为255
adaptiveMethod
:小区域阈值的计算方式:
ADAPTIVE_THRESH_MEAN_C
:小区域内取均值
ADAPTIVE_THRESH_GAUSSIAN_C
:小区域内加权求和,权重是个高斯核
thresholdType
:二值化方法,只能使用THRESH_BINARY、THRESH_BINARY_INV,也就是阈值法和反阈值法
blockSize
:选取的小区域的面积,如7就是7*7的小块。
c
:最终阈值等于小区域计算出的阈值再减去此值
下面介绍一下这两种方法。
- 取均值法
假如我们使用的小区域是3*3的,那么就会从图片的左上角开始(也就是像素值为162的地方)计算其邻域内的平均值,如果处于边缘地区就会对边界进行填充,填充值就是边界的像素点,如下图所示:
代码如下(示例):
import cv2 as cv
#读取图像
flower = cv.imread('../images/flower.png')
#灰度处理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#均值法
mean = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,2)
cv.imshow("mean",mean)
cv.waitKey(0)
cv.destroyAllWindows()
- 高斯核加权均值法
对小区域内的像素进行加权求和得到新的阈值,其权重值来自于高斯分布。
高斯分布,通过概率密度函数来定义高斯分布,一维高斯概率分布函数为:
p(y)=1σ2πe−(y−μ)22σ2p(y)={\frac{1}{\sigma{\sqrt{2\pi}}}}e^{{\frac{-(y-\mu)^{2}}{2\sigma^{2}}}} p(y)=σ2π1e2σ2−(y−μ)2
我们拓展到二维图像,一般情况下我们使x轴和y轴的相等并且,此时我们可以得到二维高斯函数的表达式为:
g(x,y)=12πσ2e−(x2+y2)2σ2g(x,y)=\frac{1}{2\pi\sigma ^{2}}e^{-\frac{(x^{2}+y^{2})}{2\sigma^{2}}} g(x,y)=2πσ21e−2σ2(x2+y2)
高斯概率函数是相对于二维坐标产生的,其中(x,y)为点坐标,要得到一个高斯滤波器模板,应先对高斯函数进行离散化,将得到的值作为模板的系数。例如:要产生一个3*3的高斯权重核,以核的中心位置为坐标原点进行取样,其周围的坐标如下图所示(x轴水平向右,y轴竖直向上)
通过这个高斯核,即可对图片中的每个像素去计算其阈值,并将该阈值减去固定值得到最终阈值,然后根据二值化规则进行二值化。
代码如下(示例):
import cv2 as cv
#读取图像
flower = cv.imread('../images/flower.png')
#灰度处理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#自适应二值化(高斯核加权法)
gauss = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,2)
cv.imshow("gauss",gauss)
cv.waitKey(0)
cv.destroyAllWindows()
两种方法执行对比:
上述两种方法,仅仅只是卷积核的参数会发生变化,计算过程是一样的,很明显高斯加权均值法的二值化细致程度要高一些。
四、图像镜像翻转与仿射变换
-
仿射变换的基本原理
-
线性变换
-
二维空间中,图像点坐标为(x,y)(x,y)(x,y),仿射变换的目标是将这些点映射到新的位置 (x′,y′)(x', y')(x′,y′)。
-
为了实现这种映射,通常会使用一个矩阵乘法的形式:
(类似于y=kx+b)
a,b,c,d 是线性变换部分的系数,控制旋转、缩放和剪切。
-
t_x,t_y 是平移部分的系数,控制图像在平面上的移动。
-
输入点的坐标被扩展为齐次坐标形式[x,y,1][x,y,1][x,y,1],以便能够同时处理线性变换和平移
-
-
-
cv2.warpAffine()函数
仿射变换函数
cv2.warpAffine(img,M,dsize)
-
img:输入图像。
-
M:2x3的变换矩阵,类型为
np.float32
。 -
dsize:输出图像的尺寸,形式为
(width,height)
。
1.图像翻转(图像镜像旋转)
在OpenCV中,图片的镜像旋转是以图像的中心为原点进行镜像翻转的。
-
cv2.flip(img,flipcode)
-
参数
- img: 要翻转的图像
- flipcode: 指定翻转类型的标志
- flipcode=0: 垂直翻转,图片像素点沿x轴翻转
- flipcode>0: 水平翻转,图片像素点沿y轴翻转
- flipcode<0: 水平垂直翻转,水平翻转和垂直翻转的结合
代码如下(示例):
import cv2 as cv
import numpy as np
#读取图像
cao = cv.imread("../images/cao.png")
cao=cv.resize(cao,(300,300))
#翻转,镜像翻转,以图像原点为中心(cv.flip(img,flipcode))
#0(垂直翻转沿X轴)>0(水平翻转沿Y轴)<0(垂直水平翻转)
flip_0 = cv.flip(cao,0)
flip_1 = cv.flip(cao,1)
flip_2 = cv.flip(cao,-1)
cv.imshow("cao",cao)
cv.imshow("flip_0",flip_0)
cv.imshow("flip_1",flip_1)
cv.imshow("flip_2",flip_2)
cv.waitKey(0)
cv.destroyAllWindows()
执行效果:
2.图像旋转
cv2.getRotationMatrix2D()函数
获取旋转矩阵
cv2.getRotationMatrix2D(center,angle,scale)
- center:旋转中心点的坐标,格式为
(x,y)
。 - angle:旋转角度,单位为度,正值表示逆时针旋转负值表示顺时针旋转。
- scale:缩放比例,若设为1,则不缩放。
- 返回值:M,2x3的旋转矩阵。
代码示例:
import cv2 as cv
#读取图像
img = cv.imread("../images/1.jpg")
cv.imshow("img",img)
#获取旋转矩阵cv2.getRotationMatrix2D(旋转中心,旋转角度,缩放比例)
M = cv.getRotationMatrix2D((img.shape[1]/2,img.shape[0]/2),45,1)
#仿射变换cv2.warpAffine(src, M, (width, height))
dst = cv.warpAffine(img,M,(img.shape[1],img.shape[0]))
cv.imshow("src",dst)
cv.waitKey(0)
cv.destroyAllWindows()
执行效果:
3.图像平移
移操作可以将图像中的每个点沿着某个方向移动一定的距离。
假设我们有一个点 P(x,y)P(x,y)P(x,y),希望将其沿x轴方向平移txt_xtx*个单位,沿y轴方向平移tyt_yty个单位到新的位置P′(x′,y′)P′(x′,y′)P′(x′,y′),那么平移公式如下:
x′=x+txx′=x+txx′=x+tx
y′=y+tyy′=y+tyy′=y+ty
在矩阵形式下,该变换可以表示为:
代码示例:
import cv2 as cv
import numpy as np
#读取图像
img = cv.imread("../images/1.jpg")
img = cv.resize(img,(300,300))
#创建一个平移矩阵
M = np.float32([[1,0,100],[0,1,50]])
#仿射变换
dst = cv.warpAffine(img,M,(img.shape[1]*2,img.shape[0]*2))
cv.imshow("img",img)
cv.imshow("src",dst)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果:
4.图像缩放
缩放操作可以改变图片的大小。
-
假设要把图像的宽高分别缩放为0.5和0.8,那么对应的缩放因子sx=0.5,sy=0.8。
-
点P(x,y)P(x,y)P(x,y)对应到新的位置P′(x′,y′)P'(x',y')P′(x′,y′),缩放公式为:
x′=sx∗xx′=s_x*xx′=sx∗x
y′=sy∗yy′=s_y*yy′=sy∗y
在矩阵形式下,该变换可以表示为:
-
相较于图像旋转中只能等比例的缩放,图像缩放更加灵活,可以在指定方向上进行缩放。
sx和sy分别表示在x轴和y轴方向上的缩放因子
。
代码示例:
import cv2 as cv
import numpy as np
#读取图像
img = cv.imread("../images/1.jpg")
img = cv.resize(img,(400,400))
#创建一个缩放矩阵
M = np.float32([[0.5,0,100],[0,0.5,100]])
dst = cv.warpAffine(img,M,(img.shape[1],img.shape[0]))
cv.imshow("img",img)
cv.imshow("src",dst)
cv.waitKey(0)
cv.destroyAllWindows()
执行效果:
结语
图像预处理是计算机视觉任务的“隐形引擎”,合理运用这些技术可以显著提升模型的性能和鲁棒性。本文从 颜色空间转换 到 仿射变换,系统介绍了 OpenCV 的核心预处理方法,并提供了可复现的代码示例。
📌 动手挑战: 尝试对一张倾斜的名片图片进行仿射变换矫正,并利用二值化提取清晰的文字信息!
🔗 后续预告: 在下一篇文章中,我们将深入探讨 图像滤波与边缘检测,进一步解锁 OpenCV 的高级功能!