You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

图像旋转技术问询:如何实现以任意坐标为中心的任意角度旋转?

问题:实现以任意坐标为中心的图像任意角度旋转

需要实现以任意坐标为中心对图像进行任意角度旋转的功能,预期达成以指定中心旋转45度的效果。目前尝试以坐标[0,0]为中心旋转图像45度,但无法实现预期结果。以下是相关代码:

旋转函数代码

# Pivot 为旋转中心坐标
def rotateImage(self, img, angle, pivot):
    padX = int(pivot[1] - img.shape[1] / 2)
    padY = int(pivot[0] - img.shape[0] / 2)
    x1, x2, y1, y2 = 0,0,0,0
    if(pivot[1] > img.shape[1]/2):
        img = pad(img, ((0,0),(0, padX)), 'constant', constant_values=1)
        x2=padX
    elif(pivot[1] < img.shape[1]):
        img = pad(img, ((0,0),(abs(padX), 0)), 'constant', constant_values=1)
        x1=abs(padX)

    if (pivot[0] > img.shape[0] / 2):
        img = pad(img, ((0, padY), (0, 0)), 'constant', constant_values=(1,1))
        y2=padY
    elif (pivot[0] < img.shape[0]):
        img = pad(img, ((abs(padY), 0), (0, 0)), 'constant', constant_values=(1,1))
        y1=abs(padY)

    imgR = ndimage.rotate(img, angle, reshape=False, cval=1)
    return imgR[y1: imgR.shape[0]-y2, x1: imgR.shape[1]-x2]

调用代码

try:
    angle = float(self.rotation_value.toPlainText())
except:
    angle = 0
if (angle <= 360 and angle >= -360 and angle != 0):
    corrected = self.rotateImage(corrected, angle, [0, 0])

writeraw32(self.path_ImageJ + "/temp/LE_corr_rot.raw", corrected)

问题排查与修复方案

你的代码核心思路是通过平移旋转中心到图像原点再旋转,但存在几个关键错误:

1. 填充逻辑错误

  • 当旋转中心是[0,0]时,padX = 0 - img.shape[1]/2,padY = 0 - img.shape[0]/2,此时elif(pivot[1] < img.shape[1])判断永远成立,会在左侧填充abs(padX),但这并没有把[0,0]移到图像中心——正确的做法应该是把旋转中心平移到图像的中心位置,也就是需要在右侧和下侧填充对应宽度,让原[0,0]点变成新图像的中心。
  • 填充的判断条件逻辑混乱,比如pivot[1] < img.shape[1]这个条件几乎总是成立,导致填充逻辑完全错误。

2. ndimage.rotate参数理解偏差

ndimage.rotate默认以图像中心为旋转轴,你试图通过填充把目标中心移到图像中心,但填充后的旋转没有考虑后续裁剪的正确性,且reshape=False会强制保持原图像尺寸,导致旋转后的图像被裁剪,丢失关键内容。

修复后的完整代码

以下是修正后的rotateImage函数,核心逻辑是:

  1. 计算旋转中心到图像中心的偏移量
  2. 对图像进行填充,使旋转中心成为新图像的中心
  3. 执行旋转(确保有足够空间容纳旋转后的内容)
  4. 裁剪回原图像尺寸,保证输出大小与原图一致
import numpy as np
from scipy import ndimage

def rotateImage(self, img, angle, pivot):
    # 获取原图像的高和宽
    h, w = img.shape[:2]
    # 原图像的中心坐标
    img_center = (w / 2, h / 2)
    # 旋转中心与原图像中心的偏移量
    offset_x = pivot[1] - img_center[0]
    offset_y = pivot[0] - img_center[1]

    # 计算旋转后图像的外接矩形尺寸,避免内容被裁剪
    theta = np.radians(angle)
    cos_theta = np.abs(np.cos(theta))
    sin_theta = np.abs(np.sin(theta))
    new_w = int(h * sin_theta + w * cos_theta)
    new_h = int(h * cos_theta + w * sin_theta)

    # 计算填充量:让原旋转中心位于新图像的中心
    pad_left = int(new_w / 2 - pivot[1])
    pad_right = new_w - (new_w // 2 + (w - pivot[1]))
    pad_top = int(new_h / 2 - pivot[0])
    pad_bottom = new_h - (new_h // 2 + (h - pivot[0]))

    # 执行填充,填充值设为1
    padded_img = np.pad(img, 
                        ((pad_top, pad_bottom), (pad_left, pad_right)), 
                        mode='constant', 
                        constant_values=1)
    
    # 以新图像中心(即原旋转中心)进行旋转
    rotated_img = ndimage.rotate(padded_img, angle, reshape=False, cval=1)
    
    # 裁剪回原图像尺寸,确保位置匹配
    crop_x_start = int(new_w / 2 - img_center[0])
    crop_x_end = int(new_w / 2 + img_center[0])
    crop_y_start = int(new_h / 2 - img_center[1])
    crop_y_end = int(new_h / 2 + img_center[1])
    cropped_img = rotated_img[crop_y_start:crop_y_end, crop_x_start:crop_x_end]
    
    return cropped_img

关键改进点

  • 正确计算填充尺寸,确保指定的旋转中心被移到填充后图像的中心,让ndimage.rotate能以该点为轴旋转
  • 用旋转后的外接矩形尺寸填充,避免旋转时内容被裁剪
  • 最后裁剪回原图像尺寸,保证输出图像和原图像大小一致

调用时传入pivot=[0,0],即可实现以图像左上角为中心的45度旋转,符合预期效果。


内容的提问来源于stack exchange,提问作者user17811626

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:25:34