旋转图像后计算属于矩形角的像素

Calculate pixels belonging to corners of rectangle after rotating image

我看到了一些与此主题相关的问题,但即使关注了这些问题,我也无法得到我想要的结果,所以我假设我的数学有问题。这是场景。

我有一张图片必须旋转 90 度。同时,我得到了在某个对象上绘制的矩形角的坐标(x_min、y_min)和(x_max、y_max)在图像中。让我们以下图为例,这里使用的矩形由 (4, 196) 和 (145, 269) 定义。

那么,我的目标是旋转图像并对矩形执行相同操作,确保它始终包围目标对象。

首先,我使用 imutils 将图像旋转 90 度(顺时针)。

90_rotated_image = imutils.rotate_bound(original_image, 90)

然后,我正在计算矩形的新坐标。为此,我需要知道 imutils 旋转图像所围绕的点。我尝试了一些组合,包括 (0,0),但这里我假设它是图像本身的中心。

radians = math.radians(90)

h, w, c = original_image.shape

center_x = w/2
center_y = h/2

# Changes to solve the problem. Center of rotated image is now considered.

h_rotated, w_rotated, c = 90_rotated_image.shape

center_x_rotated = w_rotated/2
center_y_rotated = h_rotated/2

x_min_90 = center_x_rotated + math.cos(radians) * (x_min - center_x) - math.sin(radians) * (y_min - center_y)
y_min_90 = center_y_rotated + math.sin(radians) * (x_min - center_x) + math.cos(radians) * (y_min - center_y)

x_max_90 = center_x_rotated + math.cos(radians) * (x_max - center_x) - math.sin(radians) * (y_max - center_y)
y_max_90 = center_y_rotated + math.sin(radians) * (x_max - center_x) + math.cos(radians) * (y_max - center_y)

最后,我在旋转后的图像上绘制新的旋转矩形。

start_point = (x_min_90, y_min_90) 
end_point = (x_max_90, y_max_90)

image = cv2.rectangle(90_rotated_image, start_point, end_point, (255, 0, 0), 2)

这是我得到的结果。

问题是:这里出了什么问题?为什么矩形不能正确旋转并给我预期的结果,如下所示。

编辑: 对于遇到同样问题的任何人来说,使用矩形图像进行旋转的解决方案非常简单。添加到旋转结果的 center_x 和 center_y 变量(涉及 sin 和 cos 的乘法)必须与图像的中心相关 post - 旋转而不是预旋转我最初写进了代码。 post 已更新以反映解决方案。

首先,一般情况下全局坐标中的图像中心应该是这样的(我不知道你的旋转中心到底是什么):

center_x = min_x + w/2
center_y = min_y + h/2

其次:三角函数的参数必须是弧度,而不是度数,所以math.cos(math.radians(degrees_angle))等等

第三:如果旋转前min_corner是左下,旋转后变成右下(或者可能是左顶部取决于您的坐标系方向); max_corner 也一样。同样使用围绕某个中心的旋转,你必须在最后添加中心坐标。

所以min/max旋转矩形的坐标是:

x_min_90 = center_x + (y_min - center_y)
y_min_90 = center_y - (x_max - center_x)

x_max_90 = center_x + (y_max - center_y)
y_max_90 = center_y - (x_min - center_x)

对于这个例子 ABCD -> FGHI:

xmin = 2  ymin = 1
xmax = 8  ymax = 5

center_x = 2 + 3 = 5
center_y = 1 + 2 = 3

xmin90 = 5 + (1 - 3) = 3
y_min_90 = 3 - (8 - 5) = 0
x_max_90 = 5 + (5 - 3) = 7
y_max_90 = 3 - (2 - 5) = 6

注:

  1. 我用的是数学坐标系(OX在右,OY在上),如果你的OY轴往下,就根据需要改变方向。
  2. 我用 0 和 1 替换了 90 的 cos 和 sin。对于其他角度,使用 cos 和 sin 但不要忘记弧度:

如何使用问题中的公式获得 90,180,270 度角的正确结果:

x_a_90 = center_x + math.cos(radians) * (x_min - center_x) - math.sin(radians) * (y_min - center_y)
y_a_90 = center_y + math.sin(radians) * (x_min - center_x) + math.cos(radians) * (y_min - center_y)

x_b_90 = center_x + math.cos(radians) * (x_max - center_x) - math.sin(radians) * (y_max - center_y)
y_b_90 = center_y + math.sin(radians) * (x_max - center_x) + math.cos(radians) * (y_max - center_y)

x_min_90 = min(x_a_90, x_b_90)
x_max_90 = max(x_a_90, x_b_90)
y_min_90 = min(y_a_90, y_b_90)
y_max_90 = max(y_a_90, y_b_90)