目录
[1. 定义](#1. 定义)
[2. OpenCV 函数](#2. OpenCV 函数)
[3. 数学表达](#3. 数学表达)
[1. 定义](#1. 定义)
[2. 仿射变换的基本原理](#2. 仿射变换的基本原理)
[3. OpenCV 函数](#3. OpenCV 函数)
[4. 图像旋转](#4. 图像旋转)
[5. 图像平移](#5. 图像平移)
[6. 图像缩放](#6. 图像缩放)
[7. 图像剪切](#7. 图像剪切)
[8. 为什么会出现黑色背景?](#8. 为什么会出现黑色背景?)
[1. 定义](#1. 定义)
[2. RGB颜色空间](#2. RGB颜色空间)
[3. 颜色加法](#3. 颜色加法)
[4. 颜色加权加法](#4. 颜色加权加法)
[5. HSV颜色空间](#5. HSV颜色空间)
[6. RGB转Gray(灰度)](#6. RGB转Gray(灰度))
[7. RGB转HSV](#7. RGB转HSV)
[8. 综合案例](#8. 综合案例)
[8.2 颜色转换:](#8.2 颜色转换:)
[1. 灰度图](#1. 灰度图)
[2. 最大值法](#2. 最大值法)
[3. 平均值法](#3. 平均值法)
[4. 加权均值法](#4. 加权均值法)
[5. 两个极端的灰度值](#5. 两个极端的灰度值)
一、图像翻转(镜像翻转)
1. 定义
图像翻转是对图像在某一轴(水平、垂直或对角)上的镜像操作。
2. OpenCV 函数
python
cv2.flip(src, flipCode)
-
flipCode
:-
0
:上下翻转(垂直镜像),垂直翻转,图片像素点沿x轴翻转 -
1
:左右翻转(水平镜像),水平翻转,图片像素点沿y轴翻转 -
-1
:上下左右同时翻转,水平垂直翻转,水平翻转和垂直翻转的结合
-
案例演示:
python
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
pig = cv.resize(pig,(500,500))
#镜像翻转
#垂直翻转
flip = cv.flip(pig,0)
cv.imshow('flip', flip)
#水平翻转
flip1 = cv.flip(pig,1)
cv.imshow('flip1', flip1)
#水平垂直翻转
flip2 = cv.flip(pig,-1)
cv.imshow('flip2', flip2)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

水平翻转--filp:

垂直翻转--filp1:

水平垂直翻转--filp2:

3. 数学表达
图像为矩阵 I(x,y)I(x, y)I(x,y),假设宽度为 WWW,高度为 HHH,翻转后坐标变换为:
-
水平翻转:
-
垂直翻转:
二、图像仿射变换
1. 定义
仿射变换是保线性、保平行的二维变换,包括:平移、旋转、缩放、剪切、翻转等。
仿射变换的基本性质
保持直线
保持平行
比例不变性
不保持角度和长度
常见的仿射变换类型
旋转:绕着某个点或轴旋转一定角度。
平移:仅改变物体的位置,不改变其形状和大小。
缩放:改变物体的大小。
剪切:使物体发生倾斜变形。
2. 仿射变换的基本原理
线性变换
二维空间中,图像点坐标为$$(x,y)$$,仿射变换的目标是将这些点映射到新的位置 $$(x', y')$$。
为了实现这种映射,通常会使用一个矩阵乘法的形式:(类似于y=kx+b)
二维仿射变换的通用公式如下:

也可写成扩展的 2×3 矩阵形式:

(x,y):原始坐标
(x′,y′):变换后的新坐标
a,b,c,d:旋转、缩放、剪切控制项
e,f:平移量
变换 | 变换矩阵形式 |
---|---|
平移 | ![]() |
缩放 | ![]() |
旋转 | ![]() |
剪切 | ![]() |
3. OpenCV 函数
获得仿射矩阵
python
cv2.warpAffine(img,M,dsize)
-
img:输入图像。
-
M :2x3的变换矩阵,类型为
np.float32
。 -
dsize :输出图像的尺寸,形式为
(width,height)
。
4. 图像旋转
旋转图像可以将图像绕着某个点旋转一定的角度。
cv2.getRotationMatrix2D()函数
-
获取旋转矩阵
pythoncv2.getRotationMatrix2D(center,angle,scale)
-
center :旋转中心点的坐标,格式为
(x,y)
。 -
angle:旋转角度,单位为度,正值表示逆时针旋转负值表示顺时针旋转。
-
scale:缩放比例,若设为1,则不缩放。
-
返回值 :M,2x3的旋转矩阵。
-
案例:
python
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#获取旋转矩阵 cv2.getRotationMatrix2D(center,angle,scale) 2*3
M=cv.getRotationMatrix2D((180,180),-45,1)
#仿射变换函数 cv2.warpAffine(src,M,(cols,rows))
rotate = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow('rotate',rotate)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

图像旋转后--rotate:
5. 图像平移
平移操作可以将图像中的每个点沿着某个方向移动一定的距离。
-
假设我们有一个点 P(x,y),希望将其沿x轴方向平移t_x*个单位,沿y轴方向平移t_y个单位到新的位置P′(x′,y′),那么平移公式如下:
x′=x+tx
y′=y+ty
-
在矩阵形式下,该变换可以表示为

- 这里的t_x和t_y分别代表在x轴和y轴上的平移量。
案例:
python
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#定义平移量
tx,ty=100,100
#定义平移矩阵
M=np.float32([[1,0,tx],[0,1,ty]])
#仿射变换函数 cv2.warpAffine(src,M,(cols,rows))
translate = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow("translate",translate)
cv.imshow("flower",flower)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

图像平移后--translate:

6. 图像缩放
缩放操作可以改变图片的大小。
-
假设要把图像的宽高分别缩放为0.5和0.8,那么对应的缩放因子sx=0.5,sy=0.8。
-
点P(x,y)对应到新的位置P'(x',y'),缩放公式为:
x′=s_x\*x
y′=s_y\*y
-
在矩阵形式下,该变换可以表示为:

sx和sy分别表示在x轴和y轴方向上的缩放因子。
相较于图像旋转中只能等比例的缩放,图像缩放更加灵活,可以在指定方向上进行缩放。
案例:
python
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#定义缩放因子
sx,sy=0.5,0.5
#定义缩放矩阵
M = np.float32([[sx,0,0],[0,sy,0]])
#仿射变化
dst = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow("src",flower)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

图像缩放后--dst:

7. 图像剪切
剪切操作可以改变图形的形状,以便其在某个方向上倾斜,它将对象的形状改变为斜边平行四边形,而不改变其面积。
-
想象我们手上有一张矩形纸片,如果你固定纸片的一边,并沿着另一边施加一个平行于该边的力,这张纸片就会变形为一个平行四边形。这就是剪切变换的一个直观解释。
-
对于二维空间中的点P(x,y),对他进行剪切变换:
沿x轴剪切:x'=x+sh_y\*y y'=y
沿y轴剪切:x'=x y'=sh_x\*x+y
-
当需要同时沿两个方向进行剪切时,x'=x+sh_y*y , y'=sh_x*x+y
-
在矩阵形式下,该变换可以表示为:

图示理解:

shy和shx分别对应沿x轴和y轴方向上的剪切因子。
- 可以理解为,x不变,y偏移
案例:
python
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#设置剪切因子
shx = 0.3
shy = 0.3
#设置剪切矩阵
M = np.float32([[shx * flower.shape[1], 0, 1],
[0, shy * flower.shape[1], 1]])
#仿射变化
dst = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow("src",flower)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

图像剪切后:

8. 为什么会出现黑色背景?
原因:坐标映射存在空洞
仿射变换是将原图的每个像素位置映射到一个新的位置:

变换后的图像通常会:
-
改变方向(旋转)
-
改变大小(缩放)
-
改变位置(平移)
-
改变形状(剪切)
导致部分输出图像的像素位置 在原图中没有对应的像素值,这类区域系统会使用默认值填充。
OpenCV 默认的行为:
在 cv2.warpAffine()
中,如果变换后的图像某些区域无法从源图像映射到像素值,则默认用黑色填充:
python
dst = cv2.warpAffine(src, M, (width, height))
没有设置其他参数时,空洞区域填充为黑色,即
(0, 0, 0)
(彩色)或0
(灰度)。
三、图像色彩空间转换
1. 定义
OpenCV中,图像色彩空间转换是一个非常基础且重要的操作,就是将图像从一种颜色表示形式转换为另一种表示形式的过程。通过将图像从一个色彩空间转换到另一个色彩空间,可以更好地进行特定类型的图像处理和分析任务。常见的颜色空间包括RGB、HSV、YUV等。
-
色彩空间转换的作用
-
提高图像处理效果
-
节省计算资源
-
2. 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)的原因。
3. 颜色加法
你可以使用OpenCV的cv.add()函数把两幅图像相加,或者可以简单地通过numpy操作添加两个图像,如res = img1 + img2。两个图像应该具有相同的大小和类型。
OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算。
4. 颜色加权加法
python
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 + γ
这里γ取为零。
5. 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颜色空间,然后根据颜色区间来识别目标颜色。
6. RGB转Gray(灰度)
cv2.cvtColor
是OpenCV中的一个函数,用于图像颜色空间的转换。可以将一个图像从一个颜色空间转换为另一个颜色空间,比如从RGB到灰度图,或者从RGB到HSV的转换等。
python
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到灰度图像的转换。
- 例如
7. RGB转HSV
在图像处理中,HSV(Hue 色相、Saturation 饱和度、Value 亮度)是一种更接近人类感知的色彩表示方式。相较于 RGB,HSV 更适合用于颜色分割、目标检测等任务。
OpenCV 提供了函数 cv2.cvtColor()
进行颜色空间转换。
python
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
-
img:输入图像(RGB 格式),通常是 NumPy 数组
-
code :转换类型(此处为
cv2.COLOR_RGB2HSV
)
注意:如果你用的是 cv2.imread()
读取图像,那么默认图像是 BGR 格式,此时应使用:
python
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
8. 综合案例
8.1颜色加法:
python
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
cao = cv.imread("D:\OpenCV_notes\day02\images\cao.png")
#饱和操作 cvv.add(src1,src2) np.unit8 0~255 250+10
dst1 = cv.add(pig,cao)
cv.imshow("dst1",dst1)
#numpy直接相加 取模运算 对256取模 250+10=260 260%256=4
dst2 = pig + cao
cv.imshow("dst2",dst2)
#举个例子
x = np.uint8([[250]])
y = np.uint8([[10]])
xy1 = cv.add(x, y) # 饱和加法,结果为 255
xy2 = x + y
print(xy1)
print(xy2)
#颜色加权加法 cv.addWeighted(img1,alpha,img2,beta,gamma)
dst3 = cv.addWeighted(pig,0.7,cao,0.3,2)
cv.imshow("dst3",dst3)
cv.waitKey(0)
cv.destroyAllWindows()
原图:
pig:

cao:

饱和操作后--dst1:

直接相加,取模运算--dst2:

颜色加权加法后--dst3:

8.2 颜色转换:
python
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
#颜色转换 cvv.cvtColor(src,code[,dst[,alpha[,beta]]])
#转灰度图
gray = cv.cvtColor(pig, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)
#转HSV
hsv = cv.cvtColor(pig, cv.COLOR_BGR2HSV)
cv.imshow("hsv", hsv)
#转rgb
rgb = cv.cvtColor(pig, cv.COLOR_BGR2RGB)
cv.imshow("rgb", rgb)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

转灰度图后--gray:

转HSV后--HSV :

转rgb后--rgb:

四、灰度实验
1. 灰度图
每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;但是,灰度图像在黑色与白色之间还有许多级的颜色深度。灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,用于显示的灰度图像通常用每个采样像素8位的非线性尺度来保存,这样可以有256级灰度。
2. 最大值法
对于彩色图像的每个像素,它会从R、G、B三个通道的值中选出最大的一个,并将其作为灰度图像中对应位置的像素值。

例如某图像中某像素点的像素值如上图所示,那么在使用最大值法进行灰度化时,就会从该像素点对应的RGB通道中选取最大的像素值作为灰度值,所以在灰度图中的对应位置上,该像素点的像素值就是121。
案例:
python
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
shape = pig.shape
pig1 = np.zeros(shape, dtype=np.uint8)#创建一个全零的图片
#循环遍历 每一行
for i in range(shape[0]):
#循环遍历每一列
for j in range(shape[1]):
pig1[i,j] = max(pig[i,j,0],pig[i,j,1],pig[i,j,2])
cv.imshow('pig1', pig1)
cv.waitKey(0)
cv.destroyAllWindows()
原图:

最大值法后--pig1:

3. 平均值法
对于彩色图像的每个像素,它会将R、G、B三个通道的像素值全部加起来,然后再除以三,得到的平均值就是灰度图像中对应位置的像素值

例如某图像中某像素点的像素值如上图所示,那么在使用平均值进行灰度化时,其计算结果就是(91+121+46)/3=86(对结果进行取整),所以在灰度图中的对应位置上,该像素点的像素值就是86。
案例:
python
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
shape = pig.shape
pig1 = np.zeros(shape, dtype=np.uint8)#创建一个全零的图片
#循环遍历 每一行
for i in range(shape[0]):
#循环遍历每一列
for j in range(shape[1]):
pig1[i,j] = (int(pig[i,j,0])+int(pig[i,j,1])+int(pig[i,j,2]))//3
cv.imshow('pig1', pig1)
cv.waitKey(0)
cv.destroyAllWindows()
平均值法后--pig1:

4. 加权均值法
对于彩色图像的每个像素,它会按照一定的权重去乘以每个通道的像素值,并将其相加,得到最后的值就是灰度图像中对应位置的像素值。本实验中,权重的比例为: R乘以0.299,G乘以0.587,B乘以0.114,这是经过大量实验得到的一个权重比例,也是一个比较常用的权重比例。
所使用的权重之和应该等于1。这是为了确保生成的灰度图像素值保持在合理的亮度范围内,并且不会因为权重的比例不当导致整体过亮或过暗。

例如某图像中某像素点的像素值如上图所示,那么在使用加权平均值进行灰度化时,其计算结果就是10*0.299+121*0.587+46*0.114=79。所以在灰度图中的对应位置上,该像素点的像素值就是79。这种是最常用的加权均值方式(cv2内置了)
案例:
python
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
shape = pig.shape
pig1 = np.zeros(shape, dtype=np.uint8)#创建一个全零的图片
#定义权重
wb,wg,wr = 0.3,0.59,0.11
#循环遍历 每一行
for i in range(shape[0]):
#循环遍历每一列
for j in range(shape[1]):
pig1[i,j] = round(wb*pig[i,j,0]+wg*pig[i,j,1]+wr*pig[i,j,2])
cv.imshow('pig1', pig1)
cv.waitKey(0)
cv.destroyAllWindows()
加权平均值法后--pig1:

5. 两个极端的灰度值
在灰度图像中,"极端"的灰度值指的是亮度的两个极端:最暗和最亮的值。
-
**最暗的灰度值**:0。这代表完全黑色,在灰度图像中没有任何亮度。
-
**最亮的灰度值**:255。这代表完全白色,在灰度图像中具有最大亮度。