图像旋转分两类:90度倍数用坐标置换,任意角度用三角变换加双线性插值;前者高效确定,后者保真但计算重。

图像旋转本质上是像素坐标的重新映射,用数组实现的关键在于明确坐标变换规则 + 控制遍历顺序 + 处理边界与内存布局。不需要依赖OpenCV或PIL,纯数组操作就能完成,尤其适合嵌入式、游戏引擎底层或算法教学场景。
顺时针90度:最简实用的二维数组变换
这是最常用于图标切换、屏幕适配、矩阵预处理的操作,逻辑清晰、无浮点运算、无插值损耗。
- 原图是
n × m的二维数组(如img[i][j]表示第i行、第j列像素) - 旋转后变为
m × n新数组,每个像素满足:
新位置(j, n−1−i)← 原位置(i, j)
(即:原第i行第j列 → 新第j行、倒数第i+1列)
例如 3×3 矩阵:
原始:
1 2 3
4 5 6
7 8 9
→ 旋转后第0行来自原第2列(从上到下):7 4 1
→ 新数组 `rotated[j][n-1-i] = original[i][j]`
原地旋转(n×n方阵):节省内存的关键技巧
当图像为正方形且要求“不新建数组”时,可用两步到位法:
- 第一步:沿主对角线转置(交换
matrix[i][j] ↔ matrix[j][i],j > i) - 第二步:每行水平翻转(
matrix[i][j] ↔ matrix[i][n−1−j],j )
好处是空间复杂度 O(1),所有操作在原数组内完成。
比如 `[[1,2,3],[4,5,6],[7,8,9]]`:
→ 转置得 `[[1,4,7],[2,5,8],[3,6,9]]`
→ 每行翻转得 `[[7,4,1],[8,5,2],[9,6,3]]` —— 完全匹配目标
任意角度旋转:需坐标变换与重采样
非90度倍数(如30°、45°)必须用几何公式,并处理两个核心问题:
-
中心对齐:先平移使图像中心
(cx, cy) = (w/2, h/2)成为坐标原点 -
逆向映射:对新画布中每个
(x', y'),反推它来自原图哪一点(x, y):new_x = (x − cx)·cosθ − (y − cy)·sinθ + cx
new_y = (x − cx)·sinθ + (y − cy)·cosθ + cy
但注意:直接正向映射会导致空洞或重叠;实际编码中应采用「逆向映射 + 双线性插值」——即对目标图每个像素,计算其在原图的浮点源坐标,再加权取邻近4个像素值。
实战中像素变量的新位置计算要点
无论哪种旋转,都要小心以下细节:
- 数组索引从0开始,而数学公式常默认从1,需统一偏移(如
n−1−i中的-1) - 图像数组通常按「行优先」存储:
arr[i][j]对应第i行、第j列,对应屏幕坐标(j, i)(x横向,y纵向) - 旋转后尺寸变化:90°时宽高互换;任意角需重算画布大小:
new_w = w·|cosθ| + h·|sinθ|new_h = w·|sinθ| + h·|cosθ| - 若用C/Python等语言,注意通道顺序(如BMP是BGR,PNG读出常为RGB),旋转时不改变通道维度,只动空间索引
一句话总结:90度倍数靠索引置换,任意角度靠三角变换+重采样;前者快而确定,后者准而稍重。选哪种,取决于你是否需要保真、是否允许新建缓冲区、以及性能约束。










