如何通过矩阵运算实现numpy reshape后灰度图像的旋转与插值
图像绕指定点旋转的向量式实现思路
首先明确基础映射关系:假设输入灰度图像尺寸为高H、宽W,C风格展平为一维向量时,二维坐标(h, w)(h为行索引、w为列索引)对应的一维索引为idx = h * W + w。
核心逻辑说明
你需要的变换公式中,A是稀疏采样权重矩阵,形状为(M, N),其中M是输出图像总像素数、N是输入图像总像素数:
- 每行对应一个输出像素,行内非零值为输入像素对当前输出像素的贡献权重
- 要支持双线性插值的话,每行最多4个非零权重,总和为1
- 偏移向量
b如果仅做坐标旋转的话全为0,仅当需要调整整体灰度偏置时才需赋值,坐标变换的偏移已经隐含在A的权重分布中
如果要用齐次坐标简化为单矩阵运算,只需给输入一维向量补1个值为1的维度,构造形状为(M, N+1)的增广矩阵[A | b]即可直接完成乘法运算。
具体实现步骤
1. 计算输出图像尺寸
首先对输入图像四个角点做旋转变换,计算旋转后的坐标范围,避免内容截断:
import numpy as np # 输入参数:原始图像img,旋转中心(cx, cy),旋转角theta(弧度,逆时针为正) H, W = img.shape corners = np.array([[0, 0], [W-1, 0], [0, H-1], [W-1, H-1]]) cos_t, sin_t = np.cos(theta), np.sin(theta) # 角点旋转 rot_corners = np.zeros_like(corners) rot_corners[:, 0] = (corners[:,0] - cx)*cos_t - (corners[:,1] - cy)*sin_t + cx rot_corners[:, 1] = (corners[:,0] - cx)*sin_t + (corners[:,1] - cy)*cos_t + cy # 计算输出尺寸 min_w, max_w = rot_corners[:,0].min(), rot_corners[:,0].max() min_h, max_h = rot_corners[:,1].min(), rot_corners[:,1].max() W_out = int(np.ceil(max_w - min_w)) + 1 H_out = int(np.ceil(max_h - min_h)) + 1
2. 构造权重矩阵A
如果图像尺寸较大,建议用scipy.sparse.csr_matrix存储稀疏矩阵,避免内存溢出:
from scipy.sparse import csr_matrix N = H * W M = H_out * W_out data = [] row_idx = [] col_idx = [] for h_out in range(H_out): for w_out in range(W_out): # 输出坐标映射回旋转后的世界坐标 w_rot = w_out + min_w h_rot = h_out + min_h # 逆旋转得到输入图像上的浮点采样坐标(避免正向变换产生孔洞) w_float = cx + (w_rot - cx)*cos_t + (h_rot - cy)*sin_t h_float = cy - (w_rot - cx)*sin_t + (h_rot - cy)*cos_t # 边界过滤:超出输入图像范围的像素直接填0 if w_float < 0 or w_float >= W or h_float <0 or h_float >= H: continue # 双线性插值权重计算 w0, w1 = int(np.floor(w_float)), int(np.ceil(w_float)) h0, h1 = int(np.floor(h_float)), int(np.ceil(h_float)) dw = w_float - w0 dh = h_float - h0 # 四个相邻点的权重 weights = [ (1-dw)*(1-dh), # w0,h0 dw*(1-dh), # w1,h0 (1-dw)*dh, # w0,h1 dw*dh # w1,h1 ] # 四个相邻点的输入一维索引 cols = [ h0 * W + w0, h0 * W + w1 if w1 < W else h0*W +w0, h1 * W + w0 if h1 < H else h0*W +w0, h1 * W + w1 if (w1 < W and h1 < H) else h0*W +w0 ] # 写入稀疏矩阵参数 current_row = h_out * W_out + w_out for w, col in zip(weights, cols): if w > 0: data.append(w) row_idx.append(current_row) col_idx.append(col) # 构造稀疏矩阵A A = csr_matrix((data, (row_idx, col_idx)), shape=(M, N))
3. 执行变换得到结果
# 输入向量C风格展平 input_vec = img.reshape(-1) # 执行变换,b全0时可省略 rotated_vec = A @ input_vec # reshape为二维图像 rotated_img = rotated_vec.reshape(H_out, W_out)
优化提示
如果不需要双线性插值改用最近邻插值,只需取h_float和w_float四舍五入后的整数坐标,每行仅存1个权重为1的非零元素,矩阵尺寸会更小,运算速度更快。
内容的提问来源于stack exchange,提问作者E.G.A.L.
相关产品推荐
相关产品推荐

