问询:基于Numpy从零实现图像任意角度剪切的朴素仿射变换方法
从零实现任意角度图像剪切
1. 剪切变换原理
沿X轴的水平剪切(剪切角度为θ),剪切因子 s = tan(θ)。正向变换为:
x_out = x_in + s * y_in y_out = y_in
为避免像素空洞,采用反向映射:从输出像素位置反推原始输入坐标,再提取像素值。
2. 实现步骤
- 计算剪切后图像的尺寸,确保完整容纳变换内容
- 生成输出图像的坐标网格
- 反向映射得到输入图像的对应坐标
- 过滤超出原始图像范围的坐标,设置背景色
- 通过插值获取像素值(这里用最简单的最近邻插值)
3. 完整代码
import numpy as np import matplotlib.pyplot as plt def shear_image(image, shear_angle_deg): # 角度转弧度,计算剪切因子 shear_angle_rad = np.radians(shear_angle_deg) s = np.tan(shear_angle_rad) height, width, channels = image.shape # 计算输出图像尺寸:水平剪切后宽度增加height*|s| new_width = int(width + abs(s) * height) new_height = height # 初始化输出图像为黑色背景 sheared_image = np.zeros((new_height, new_width, channels), dtype=image.dtype) # 生成输出图像的坐标网格 y_out, x_out = np.meshgrid(np.arange(new_height), np.arange(new_width), indexing='ij') # 反向映射到输入图像坐标 x_in = x_out - s * y_out y_in = y_out # 筛选有效坐标(在原始图像范围内) valid_mask = (x_in >= 0) & (x_in < width) & (y_in >= 0) & (y_in < height) # 最近邻插值:取坐标整数部分 x_in_int = x_in[valid_mask].astype(np.int32) y_in_int = y_in[valid_mask].astype(np.int32) # 赋值像素值 sheared_image[y_out[valid_mask], x_out[valid_mask]] = image[y_in_int, x_in_int] return sheared_image # 测试示例 if __name__ == "__main__": # 替换为你的图像路径 # image = plt.imread("test_image.jpg") # 测试用随机图像 image = np.random.randint(0, 255, size=(200, 300, 3), dtype=np.uint8) # 30度剪切 sheared_img = shear_image(image, 30) plt.figure(figsize=(10, 5)) plt.subplot(121) plt.imshow(image) plt.title("原始图像") plt.subplot(122) plt.imshow(sheared_img) plt.title("30度剪切后的图像") plt.show()
4. 扩展说明
- 垂直剪切(沿Y轴错切):修改变换公式为
y_out = y_in + s * x_in,反向映射y_in = y_out - s * x_out,同时调整输出图像高度。 - 更平滑效果:将最近邻插值替换为双线性插值,对坐标小数部分加权计算周围像素的平均值。
内容的提问来源于stack exchange,提问作者Academic
相关产品推荐
相关产品推荐

