第1篇:图像处理的基本运算------从像素操作到几何变换
系列导语:本文是"有趣的图像处理"系列的开篇之作。我们将从最基础的像素操作开始,深入理解亮度、对比度、饱和度调整的原理,掌握自动颜色校正与二值化技术,并学习图像的基本几何变换(缩放、平移、旋转)
导语
当你用手机修图软件调整照片亮度、旋转图片、或者将彩色照片变成黑白时,你正在使用图像处理的基本运算 。
这些看似简单的操作背后,其实是一套精确的数学公式和算法逻辑。理解这些基础运算,是掌握所有高级滤镜和特效的必要前提 。
本文将从像素的本质出发,带你理解:
- 图像是如何用矩阵表示的
- 亮度、对比度、饱和度的数学模型
- 自动颜色校正的算法原理
- 二值化与阈值处理
- 几何变换的矩阵表示(缩放、平移、旋转)
一、图像的本质------矩阵与像素
1.1 数字图像的数学表示
一幅数字图像,本质上就是一个二维矩阵:
I = [ p 11 p 12 p 13 ⋯ p 1 w p 21 p 22 p 23 ⋯ p 2 w p 31 p 32 p 33 ⋯ p 3 w ⋮ ⋮ ⋮ ⋱ ⋮ p h 1 p h 2 p h 3 ⋯ p h w ] I = \begin{bmatrix} p_{11} & p_{12} & p_{13} & \cdots & p_{1w} \\ p_{21} & p_{22} & p_{23} & \cdots & p_{2w} \\ p_{31} & p_{32} & p_{33} & \cdots & p_{3w} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ p_{h1} & p_{h2} & p_{h3} & \cdots & p_{hw} \end{bmatrix} I= p11p21p31⋮ph1p12p22p32⋮ph2p13p23p33⋮ph3⋯⋯⋯⋱⋯p1wp2wp3w⋮phw
其中:
- h h h 是图像高度(行数)
- w w w 是图像宽度(列数)
- p i j p_{ij} pij 是位置 ( i , j ) (i, j) (i,j) 处的像素值
1.2 像素值的含义
灰度图像:
- 每个像素用一个值表示: p i j ∈ [ 0 , 255 ] p_{ij} \in [0, 255] pij∈[0,255]
- 0 0 0 表示纯黑, 255 255 255 表示纯白
- 中间值表示不同程度的灰
彩色图像(RGB):
- 每个像素用三个值表示: ( R , G , B ) (R, G, B) (R,G,B)
- R R R:红色通道,取值范围 [ 0 , 255 ] [0, 255] [0,255]
- G G G:绿色通道,取值范围 [ 0 , 255 ] [0, 255] [0,255]
- B B B:蓝色通道,取值范围 [ 0 , 255 ] [0, 255] [0,255]
因此,一幅 h × w h \times w h×w 的彩色图像,实际上是一个 三维数组 : I ∈ R h × w × 3 I \in \mathbb{R}^{h \times w \times 3} I∈Rh×w×3
1.3 图像的坐标系
图像处理中常用两种坐标系:
笛卡尔坐标系:
- 原点 ( 0 , 0 ) (0, 0) (0,0) 在图像左上角
- x x x 轴向右, y y y 轴向下
- 像素 ( i , j ) (i, j) (i,j) 表示第 i i i 行、第 j j j 列
归一化坐标系:
- 将像素值映射到 [ 0 , 1 ] [0, 1] [0,1] 区间
- 公式: x norm = x / 255 x_{\text{norm}} = x / 255 xnorm=x/255
二、像素级操作------点亮与调暗
2.1 亮度调整(Brightness Adjustment)
数学公式 :
I ′ [ i , j ] = I [ i , j ] + Δ I'[i,j] = I[i,j] + \Delta I′[i,j]=I[i,j]+Δ
其中:
- I I I 是输入图像
- I ′ I' I′ 是输出图像
- Δ \Delta Δ 是亮度偏移量
- Δ > 0 \Delta > 0 Δ>0:图像变亮
- Δ < 0 \Delta < 0 Δ<0:图像变暗
BrightnessAdjust 算法流程:
输入 : 图像 I I I, 亮度偏移值 Δ \Delta Δ (默认50)
输出 : 调整后的图像 I ′ I' I′
-
将图像转为浮点型(防止溢出): I float = I . astype ( float32 ) I_{\text{float}} = I.\text{astype}(\text{float32}) Ifloat=I.astype(float32)
-
对每个像素 ( i , j ) (i, j) (i,j): I ′ [ i , j ] = I [ i , j ] + Δ I'[i,j] = I[i,j] + \Delta I′[i,j]=I[i,j]+Δ
-
裁剪到有效范围: I ′ = Clip ( I ′ , 0 , 255 ) I' = \text{Clip}(I', 0, 255) I′=Clip(I′,0,255)
-
转回无符号整数: I ′ = I ′ . astype ( uint8 ) I' = I'.\text{astype}(\text{uint8}) I′=I′.astype(uint8)
-
返回 I ′ I' I′
关键问题:为什么要裁剪(Clip)?
当 I [ i , j ] + Δ > 255 I[i,j] + \Delta > 255 I[i,j]+Δ>255 时,像素值会溢出。例如:
- 原始值: 240 240 240
- 增加亮度: 240 + 50 = 290 240 + 50 = 290 240+50=290
- 溢出后(uint8): 290 m o d 256 = 34 290 \bmod 256 = 34 290mod256=34(意外变暗!)
因此,必须用 Clip \text{Clip} Clip 函数将值限制在 [ 0 , 255 ] [0, 255] [0,255]:
Clip ( x , 0 , 255 ) = min ( max ( x , 0 ) , 255 ) \text{Clip}(x, 0, 255) = \min(\max(x, 0), 255) Clip(x,0,255)=min(max(x,0),255)
2.2 对比度调整(Contrast Adjustment)
数学公式 :
I ′ [ i , j ] = I [ i , j ] × factor I'[i,j] = I[i,j] \times \text{factor} I′[i,j]=I[i,j]×factor
其中:
- factor > 1 \text{factor} > 1 factor>1:增强对比度(亮的更亮,暗的更暗)
- factor < 1 \text{factor} < 1 factor<1:降低对比度
- factor = 1 \text{factor} = 1 factor=1:不变
算法流程:
算法: ContrastAdjust
输入 : 图像 I I I, 对比度因子 factor \text{factor} factor (默认1.5)
输出 : 调整后的图像 I ′ I' I′
①. 将图像转为浮点型: I float = I . astype ( float32 ) I_{\text{float}} = I.\text{astype}(\text{float32}) Ifloat=I.astype(float32)
②. 对每个像素 ( i , j ) (i, j) (i,j): I ′ [ i , j ] = I [ i , j ] × factor I'[i,j] = I[i,j] \times \text{factor} I′[i,j]=I[i,j]×factor
③. 裁剪到有效范围: I ′ = Clip ( I ′ , 0 , 255 ) I' = \text{Clip}(I', 0, 255) I′=Clip(I′,0,255)
④. 转回无符号整数: I ′ = I ′ . astype ( uint8 ) I' = I'.\text{astype}(\text{uint8}) I′=I′.astype(uint8)
- 返回 I ′ I' I′
对比度增强的本质:
对比度调整实际上是拉伸或压缩像素值的分布:
- factor = 1.5 \text{factor} = 1.5 factor=1.5 时,原值 100 → 150 100 \to 150 100→150, 200 → 300 200 \to 300 200→300(clip到255)
- 亮区间的差异被放大 ,暗区间的差异也被放大
2.3 亮度与对比度的组合
在实际应用中,亮度与对比度通常同时调整 :
I ′ [ i , j ] = Clip ( I [ i , j ] × factor + Δ , 0 , 255 ) I'[i,j] = \text{Clip}(I[i,j] \times \text{factor} + \Delta, 0, 255) I′[i,j]=Clip(I[i,j]×factor+Δ,0,255)
三、饱和度调整------颜色的鲜艳程度
3.1 为什么要在HSV空间调整饱和度?
RGB空间不适合直接调整颜色鲜艳程度,因为:
- R、G、B三个通道相互耦合
- 改变一个通道会影响颜色的色相(Hue)
HSV颜色空间将颜色分解为:
H(Hue,色相):颜色的种类(红、绿、蓝等)S(Saturation,饱和度):颜色的纯度V(Value,明度):颜色的亮度
在HSV空间中,只需调整S通道即可改变颜色鲜艳程度,不会影响色相。
3.2 饱和度调整算法
SaturationAdjust 算法流程:
输入 : 图像 I I I (RGB), 饱和度因子 factor \text{factor} factor (默认1.5)
输出 : 调整后的图像 I ′ I' I′
①. 将RGB转换为HSV: I hsv = RGB2HSV ( I ) I_{\text{hsv}} = \text{RGB2HSV}(I) Ihsv=RGB2HSV(I)
②. 提取S通道: S = I hsv [ : , : , 1 ] S = I_{\text{hsv}}[:,:,1] S=Ihsv[:,:,1]
③. 调整饱和度:
S ′ = Clip ( S × factor , 0 , 255 ) S' = \text{Clip}(S \times \text{factor}, 0, 255) S′=Clip(S×factor,0,255)
I hsv [ : , : , 1 ] = S ′ I_{\text{hsv}}[:,:,1] = S' Ihsv[:,:,1]=S′
④. 将HSV转换回RGB: I ′ = HSV2RGB ( I hsv ) I' = \text{HSV2RGB}(I_{\text{hsv}}) I′=HSV2RGB(Ihsv)
- 返回 I ′ I' I′
参数说明:
- factor > 1 \text{factor} > 1 factor>1:颜色更鲜艳
- factor < 1 \text{factor} < 1 factor<1:颜色更淡雅
- factor = 0 \text{factor} = 0 factor=0:完全去色(变成灰度图)
四、自动颜色校正------让图像"自动变好看"
4.1 自动颜色校正(Auto Color)
核心思想:让每个通道的平均值趋向中值(128),从而平衡颜色。
数学公式:
对每个通道 c ∈ { B , G , R } : avg c = mean ( I [ : , : , c ] ) # 计算通道平均值 factor c = 128 / avg c # 计算校正因子 I ′ [ : , : , c ] = Clip ( I [ : , : , c ] × factor c , 0 , 255 ) \begin{aligned} &\text{对每个通道 } c \in \{B, G, R\}: \\ &\quad \text{avg}_c = \text{mean}(I[:,:,c]) \qquad \text{\# 计算通道平均值} \\ &\quad \text{factor}_c = 128 / \text{avg}_c \qquad \text{\# 计算校正因子} \\ &\quad I'[:,:,c] = \text{Clip}(I[:,:,c] \times \text{factor}_c, 0, 255) \end{aligned} 对每个通道 c∈{B,G,R}:avgc=mean(I[:,:,c])# 计算通道平均值factorc=128/avgc# 计算校正因子I′[:,:,c]=Clip(I[:,:,c]×factorc,0,255)
AutoColorCorrection 算法流程:
输入 : 彩色图像 I I I ( H × W × 3 H \times W \times 3 H×W×3)
输出 : 颜色校正后的图像 I ′ I' I′
①. 复制图像: I ′ = I . copy ( ) I' = I.\text{copy}() I′=I.copy()
②. 对每个通道 c ∈ { 0 , 1 , 2 } c \in \{0, 1, 2\} c∈{0,1,2}: # B, G, R
计算通道平均值: avg c = mean ( I ′ [ : , : , c ] ) \text{avg}_c = \text{mean}(I'[:,:,c]) avgc=mean(I′[:,:,c])
计算校正因子
if avg c > 0 \text{avg}_c > 0 avgc>0: factor c = 128 / avg c \text{factor}_c = 128 / \text{avg}_c factorc=128/avgc
else: factor c = 1 \text{factor}_c = 1 factorc=1 # 防止除以零
应用校正: I ′ [ : , : , c ] = Clip ( I ′ [ : , : , c ] × factor c , 0 , 255 ) I'[:,:,c] = \text{Clip}(I'[:,:,c] \times \text{factor}_c, 0, 255) I′[:,:,c]=Clip(I′[:,:,c]×factorc,0,255)
③. 返回 I ′ I' I′
效果示例:
- 原始图像偏蓝(B通道平均值200)
- 校正因子: 128 / 200 = 0.64 128 / 200 = 0.64 128/200=0.64
- B通道所有像素值缩小64%,颜色更平衡
4.2 自动对比度(Auto Contrast)
核心思想 :将像素值线性映射到完整范围 [0, 255]。
数学公式 :
I ′ [ i , j ] = ( I [ i , j ] − min_val ) × 255 max_val − min_val I'[i,j] = (I[i,j] - \text{min\_val}) \times \frac{255}{\text{max\_val} - \text{min\_val}} I′[i,j]=(I[i,j]−min_val)×max_val−min_val255
其中:
- min_val = min ( I ) \text{min\_val} = \min(I) min_val=min(I):图像最小像素值
- max_val = max ( I ) \text{max\_val} = \max(I) max_val=max(I):图像最大像素值
AutoContrast 算法流程:
输入 : 图像 I I I
输出 : 对比度增强后的图像 I ′ I' I′
①. 计算全局最小和最大值:
min_val = min ( I ) \text{min\_val} = \min(I) min_val=min(I) max_val = max ( I ) \text{max\_val} = \max(I) max_val=max(I)
②. 如果 max_val > min_val : \text{max\_val} > \text{min\_val}: max_val>min_val: # 线性映射到 [ 0 , 255 ] [0, 255] [0,255]
I ′ = ( I − min_val ) × 255 / ( max_val − min_val ) I' = (I - \text{min\_val}) \times 255 / (\text{max\_val} - \text{min\_val}) I′=(I−min_val)×255/(max_val−min_val)
③. 否则: # 图像已经是均匀的,无需调整
I ′ = I I' = I I′=I
④. 返回 I ′ I' I′
实际实现 :使用OpenCV的 cv2.normalize() 函数:
I' = cv2.normalize(I, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
4.3 自动色阶(Auto Level)
核心思想 :与自动对比度类似,但对每个通道分别进行线性拉伸。
数学公式:
对每个通道 c : min c = min ( I [ : , : , c ] ) max c = max ( I [ : , : , c ] ) if max c > min c : I ′ [ : , : , c ] = ( I [ : , : , c ] − min c ) × 255 max c − min c \begin{aligned} &\text{对每个通道 } c: \\ &\quad \text{min}_c = \min(I[:,:,c]) \\ &\quad \text{max}_c = \max(I[:,:,c]) \\ &\quad \text{if } \text{max}_c > \text{min}_c: \\ &\qquad I'[:,:,c] = (I[:,:,c] - \text{min}_c) \times \frac{255}{\text{max}_c - \text{min}_c} \end{aligned} 对每个通道 c:minc=min(I[:,:,c])maxc=max(I[:,:,c])if maxc>minc:I′[:,:,c]=(I[:,:,c]−minc)×maxc−minc255
AutoLevel 算法流程:
输入: 彩色图像 I (H×W×3)
输出: 色阶调整后的图像 I'
①. 复制图像: I ′ = I . c o p y ( ) I' = I.copy() I′=I.copy()
②. 对每个通道 c ∈ {0, 1, 2}:
min c = min ( I ′ [ : , : , c ] ) \min_c = \min(I'[:,:,c]) minc=min(I′[:,:,c])
max c = max ( I ′ [ : , : , c ] ) \max_c = \max(I'[:,:,c]) maxc=max(I′[:,:,c])
if max_c > min_c:
I ′ [ : , : , c ] = ( I ′ [ : , : , c ] − m i n c ) × 255 / ( m a x c − m i n c ) I'[:,:,c] = (I'[:,:,c] - min_c) × 255 / (max_c - min_c) I′[:,:,c]=(I′[:,:,c]−minc)×255/(maxc−minc)
I ′ [ : , : , c ] = C l i p ( I ′ [ : , : , c ] , 0 , 255 ) I'[:,:,c] = Clip(I'[:,:,c], 0, 255) I′[:,:,c]=Clip(I′[:,:,c],0,255)
③. 返回 I ′ I' I′
自动颜色 vs 自动对比度 vs 自动色阶:
| 方法 | 原理 | 效果 |
|---|---|---|
| 自动颜色 | 通道均值归一化 | 平衡颜色 |
| 自动对比度 | 全局Min-Max映射 | 增强整体对比度 |
| 自动色阶 | 逐通道Min-Max映射 | 增强每通道对比度 |
五、灰度化与二值化
5.1 灰度化(Black & White)
方法一:平均值法
Gray [ i , j ] = R [ i , j ] + G [ i , j ] + B [ i , j ] 3 \text{Gray}[i,j] = \frac{R[i,j] + G[i,j] + B[i,j]}{3} Gray[i,j]=3R[i,j]+G[i,j]+B[i,j]
方法二:加权平均法(推荐)
人眼对不同颜色的敏感度不同:对绿色最敏感,对蓝色最不敏感。因此采用加权平均:
Gray [ i , j ] = 0.299 × R [ i , j ] + 0.587 × G [ i , j ] + 0.114 × B [ i , j ] \text{Gray}[i,j] = 0.299 \times R[i,j] + 0.587 \times G[i,j] + 0.114 \times B[i,j] Gray[i,j]=0.299×R[i,j]+0.587×G[i,j]+0.114×B[i,j]
RGB2Gray 算法流程:
输入 : 彩色图像 I I I ( H × W × 3 H \times W \times 3 H×W×3)
输出 : 灰度图像 Gray \text{Gray} Gray ( H × W H \times W H×W)
①. 提取三个通道: # OpenCV使用BGR顺序
R = I [ : , : , 2 ] R = I[:,:,2] R=I[:,:,2]
G = I [ : , : , 1 ] G = I[:,:,1] G=I[:,:,1]
B = I [ : , : , 0 ] B = I[:,:,0] B=I[:,:,0]
②. 加权平均:
Gray = 0.299 × R + 0.587 × G + 0.114 × B \text{Gray} = 0.299 \times R + 0.587 \times G + 0.114 \times B Gray=0.299×R+0.587×G+0.114×B
③. 转换为整数:
Gray = Clip ( Gray , 0 , 255 ) . astype ( uint8 ) \text{Gray} = \text{Clip}(\text{Gray}, 0, 255).\text{astype}(\text{uint8}) Gray=Clip(Gray,0,255).astype(uint8)
- 返回 Gray \text{Gray} Gray
OpenCV实现:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
内部使用的权重系数:0.299, 0.587, 0.114
5.2 二值化(Binarization)
核心思想:根据阈值将像素分为两类------黑或白。
数学公式 :
I ′ [ i , j ] = { 255 , if I [ i , j ] > threshold 0 , otherwise I'[i,j] = \begin{cases} 255, & \text{if } I[i,j] > \text{threshold} \\ 0, & \text{otherwise} \end{cases} I′[i,j]={255,0,if I[i,j]>thresholdotherwise
Binarize算法流程:
输入 : 图像 I I I, 阈值 threshold \text{threshold} threshold (默认128)
输出 : 二值图像 I ′ I' I′
①. 将图像转为灰度: gray = RGB2Gray ( I ) \text{gray} = \text{RGB2Gray}(I) gray=RGB2Gray(I)
②. 对每个像素 ( i , j ) (i, j) (i,j):
if gray [ i , j ] > threshold \text{gray}[i,j] > \text{threshold} gray[i,j]>threshold: I ′ [ i , j ] = 255 I'[i,j] = 255 I′[i,j]=255 # 白色
else: I ′ [ i , j ] = 0 I'[i,j] = 0 I′[i,j]=0 # 黑色
③. 返回 I ′ I' I′
OpenCV实现:
_, result = cv2.threshold(gray, threshold, 255, cv2.THRESH_BINARY)
阈值选择:
- 固定阈值:手动指定(如128)
- 自适应阈值:根据局部区域自动计算(Otsu方法)
六、几何变换基础------缩放、平移、旋转
6.1 仿射变换的矩阵表示
仿射变换是一类保持直线平行性的变换,包括:缩放、平移、旋转、倾斜。
齐次坐标系统 :为了用矩阵乘法表示平移,我们引入齐次坐标 (Homogeneous Coordinates),将二维点 (x, y) 表示为三维向量 (x, y, 1)。
仿射变换矩阵 :
\\begin{bmatrix} x' \\ y' \\ 1 \\end{bmatrix} \\begin{bmatrix} a \& b \& c \\ d \& e \& f \\ 0 \& 0 \& 1 \\end{bmatrix} \\times \\begin{bmatrix} x \\ y \\ 1 \\end{bmatrix}
展开后:
x ′ = a × x + b × y + c y ′ = d × x + e × y + f \begin{aligned} x' &= a \times x + b \times y + c \\ y' &= d \times x + e \times y + f \end{aligned} x′y′=a×x+b×y+c=d×x+e×y+f
其中:
- ( a , b , d , e ) (a, b, d, e) (a,b,d,e) 控制:缩放、旋转、倾斜
- ( c , f ) (c, f) (c,f) 控制:平移
6.2 缩放(Scaling)
数学公式 :
x ′ = s x × x y ′ = s y × y \begin{aligned} x' &= s_x \times x \\ y' &= s_y \times y \end{aligned} x′y′=sx×x=sy×y
变换矩阵 :
s x 0 0 0 s y 0 0 0 1 \] \\begin{bmatrix} s_x \& 0 \& 0 \\\\ 0 \& s_y \& 0 \\\\ 0 \& 0 \& 1 \\end{bmatrix} sx000sy0001 其中: * s x \> 1 s_x \> 1 sx\>1:水平放大 * s x \< 1 s_x \< 1 sx\<1:水平缩小 * s y \> 1 s_y \> 1 sy\>1:垂直放大 * s y \< 1 s_y \< 1 sy\<1:垂直缩小 #### 6.3 平移(Translation) **数学公式** : x ′ = x + t x y ′ = y + t y \\begin{aligned} x' \&= x + t_x \\\\ y' \&= y + t_y \\end{aligned} x′y′=x+tx=y+ty **变换矩阵** : \[ 1 0 t x 0 1 t y 0 0 1 \] \\begin{bmatrix} 1 \& 0 \& t_x \\\\ 0 \& 1 \& t_y \\\\ 0 \& 0 \& 1 \\end{bmatrix} 100010txty1 其中: * t x \> 0 t_x \> 0 tx\>0:向右平移 * t y \> 0 t_y \> 0 ty\>0:向下平移 #### 6.4 旋转(Rotation) **数学公式** (绕原点逆时针旋转 θ \\theta θ 角度): x ′ = x × cos ( θ ) − y × sin ( θ ) y ′ = x × sin ( θ ) + y × cos ( θ ) \\begin{aligned} x' \&= x \\times \\cos(\\theta) - y \\times \\sin(\\theta) \\\\ y' \&= x \\times \\sin(\\theta) + y \\times \\cos(\\theta) \\end{aligned} x′y′=x×cos(θ)−y×sin(θ)=x×sin(θ)+y×cos(θ) **变换矩阵** : \[ cos ( θ ) − sin ( θ ) 0 sin ( θ ) cos ( θ ) 0 0 0 1 \] \\begin{bmatrix} \\cos(\\theta) \& -\\sin(\\theta) \& 0 \\\\ \\sin(\\theta) \& \\cos(\\theta) \& 0 \\\\ 0 \& 0 \& 1 \\end{bmatrix} cos(θ)sin(θ)0−sin(θ)cos(θ)0001 **绕任意点旋转**(如图像中心): 旋转中心 `(cx, cy)` 时,需要三步: 1. 平移到原点:`T(-cx, -cy)` 2. 旋转:`R(θ)` 3. 平移回去:`T(cx, cy)` **组合变换矩阵**: M = T ( c x , c y ) × R ( θ ) × T ( − c x , − c y ) M = T(cx, cy) \\times R(\\theta) \\times T(-cx, -cy) M=T(cx,cy)×R(θ)×T(−cx,−cy) 展开后: \[ cos ( θ ) − sin ( θ ) c x × ( 1 − cos ( θ ) ) + c y × sin ( θ ) sin ( θ ) cos ( θ ) c y × ( 1 − cos ( θ ) ) − c x × sin ( θ ) 0 0 1 \] \\begin{bmatrix} \\cos(\\theta) \& -\\sin(\\theta) \& cx \\times (1-\\cos(\\theta)) + cy \\times \\sin(\\theta) \\\\ \\sin(\\theta) \& \\cos(\\theta) \& cy \\times (1-\\cos(\\theta)) - cx \\times \\sin(\\theta) \\\\ 0 \& 0 \& 1 \\end{bmatrix} cos(θ)sin(θ)0−sin(θ)cos(θ)0cx×(1−cos(θ))+cy×sin(θ)cy×(1−cos(θ))−cx×sin(θ)1 #### 6.5 旋转变换算法流程 **算法**: RotateImage **输入** : 图像 I I I, 旋转角度 angle \\text{angle} angle (度), 旋转中心 ( c x , c y ) (cx, cy) (cx,cy) **输出** : 旋转后的图像 I ′ I' I′ ①. 将角度转为弧度: θ = angle × π / 180 \\theta = \\text{angle} \\times \\pi / 180 θ=angle×π/180 ②. 计算旋转矩阵: cos θ = cos ( θ ) \\cos_\\theta = \\cos(\\theta) cosθ=cos(θ) sin θ = sin ( θ ) \\sin_\\theta = \\sin(\\theta) sinθ=sin(θ) $$M = \\begin{bmatrix} \\cos_\\theta \& -\\sin_\\theta \& cx \\times (1-\\cos_\\theta) + cy \\times \\sin_\\theta \\ \\sin_\\theta \& \\cos_\\theta \& cy \\times (1-\\cos_\\theta) - cx \\times \\sin_\\theta \\end{bmatrix}$$ ③. 应用仿射变换: I ′ = WarpAffine ( I , M ) I' = \\text{WarpAffine}(I, M) I′=WarpAffine(I,M) 使用双线性插值采样 ④. 返回 I ′ I' I′ **OpenCV实现**: # 获取旋转矩阵 M = cv2.getRotationMatrix2D(center=(cx, cy), angle=angle, scale=1.0) # 应用仿射变换 I' = cv2.warpAffine(I, M, (width, height)) #### 6.6 倾斜变换(Skew/Shear) ### **水平倾斜** 的数学公式: x ′ = x + tan ( θ ) × y y ′ = y \\begin{aligned} x' \&= x + \\tan(\\theta) \\times y \\\\ y' \&= y \\end{aligned} x′y′=x+tan(θ)×y=y **变换矩阵** : \[ 1 tan ( θ ) 0 0 1 0 0 0 1 \] \\begin{bmatrix} 1 \& \\tan(\\theta) \& 0 \\\\ 0 \& 1 \& 0 \\\\ 0 \& 0 \& 1 \\end{bmatrix} 100tan(θ)10001 ### 七、算法实现的核心思想 #### 7.1 像素级操作(Point Operations) **特点**:输出像素仅依赖于输入像素自身的值 I ′ \[ i , j \] = f ( I \[ i , j \] ) I'\[i,j\] = f(I\[i,j\]) I′\[i,j\]=f(I\[i,j\]) **本文涉及的操作**: * 亮度调整: f ( x ) = x + Δ f(x) = x + \\Delta f(x)=x+Δ * 对比度调整: f ( x ) = x × factor f(x) = x \\times \\text{factor} f(x)=x×factor * 饱和度调整:在HSV空间对S通道缩放 * 自动颜色:每通道乘以校正因子 * 二值化:阈值判断 **优势**: * 计算简单,可并行化 * 不需要访问邻域像素 #### 7.2 坐标变换(Geometric Transformations) **特点**:改变像素的空间位置 I ′ \[ x , y \] = I \[ T ( x , y ) \] I'\[x,y\] = I\[T(x,y)\] I′\[x,y\]=I\[T(x,y)
本文涉及的操作:
- 缩放: T ( x , y ) = ( s x × x , s y × y ) T(x,y) = (s_x \times x, s_y \times y) T(x,y)=(sx×x,sy×y)
- 平移: T ( x , y ) = ( x + t x , y + t y ) T(x,y) = (x + t_x, y + t_y) T(x,y)=(x+tx,y+ty)
- 旋转: T ( x , y ) T(x,y) T(x,y) 由旋转矩阵计算
关键问题:
-
正向映射 vs 逆向映射
- 正向:从源像素计算目标位置 → 可能产生空洞
- 逆向:从目标像素反算源位置 → 保证每个像素都有值(推荐)
-
插值
- 当反算的源位置不是整数时,需要插值
- 常用:最近邻、双线性、双三次
八、扩展阅读
8.1 相关算法
- 直方图均衡化:自动增强对比度的另一种方法
- Gamma校正:非线性亮度调整
- 白平衡:更高级的颜色校正
- 色调映射:HDR图像的压缩
8.2 性能优化技巧
向量化操作:
- 使用NumPy进行批量运算,避免Python循环
- 示例:
I' = np.clip(I + 50, 0, 255)
OpenCV内置函数:
cv2.normalize()比手动实现更快cv2.cvtColor()高度优化的颜色空间转换
10.3 参考文献
- Gonzalez, R. C., & Woods, R. E. (2018). Digital Image Processing (4th ed.). Pearson.
- OpenCV Documentation. https://docs.opencv.org/
- NumPy Documentation. https://numpy.org/doc/
结语
本文介绍了图像处理的基础运算:
- ✅ 亮度、对比度、饱和度:最基本的像素级操作
- ✅ 自动颜色校正:让图像"自动变好看"的算法
- ✅ 二值化与灰度化:图像分割与简化的基础
- ✅ 几何变换:缩放、平移、旋转的矩阵表示
这些看似简单的操作,是理解所有高级滤镜的基石 。在下一篇文章中,我们将深入探讨图像中的数学原理------矩阵运算、卷积与微分运算,解锁模糊、锐化、边缘检测等更强大的技术。
系列文章导航:
- 📖 当前位置:第1篇 - 基本运算
- ➡️ 下一篇:第2篇 - 图像中的数学原理
- 🔙 系列首页:总览篇
标签 :图像处理 像素操作 亮度调整 对比度 饱和度 二值化 几何变换 仿射变换 Python OpenCV
本文是"图像特效与滤镜技术"系列的第1篇。所有算法都基于Python+OpenCV+NumPy实现,完整代码开源在GitHub。