gpt4 book ai didi

python - 旋转图像并裁剪黑色边框

转载 作者:IT老高 更新时间:2023-10-28 20:25:19 24 4
gpt4 key购买 nike

我的应用程序:我正在尝试旋转图像(使用 OpenCV 和 Python)

Rotating Images

目前我开发了以下代码,它旋转输入图像,用黑色边框填充它,给我 A。我想要的是 B - 旋转图像中最大可能的区域裁剪窗口。我称之为轴对齐boundED box。

这与 Rotate and crop 基本相同,但是我无法得到该问题的答案。此外,该答案显然仅对方形图像有效。我的图片是矩形的。

给出A的代码:

import cv2
import numpy as np


def getTranslationMatrix2d(dx, dy):
"""
Returns a numpy affine transformation matrix for a 2D translation of
(dx, dy)
"""
return np.matrix([[1, 0, dx], [0, 1, dy], [0, 0, 1]])


def rotateImage(image, angle):
"""
Rotates the given image about it's centre
"""

image_size = (image.shape[1], image.shape[0])
image_center = tuple(np.array(image_size) / 2)

rot_mat = np.vstack([cv2.getRotationMatrix2D(image_center, angle, 1.0), [0, 0, 1]])
trans_mat = np.identity(3)

w2 = image_size[0] * 0.5
h2 = image_size[1] * 0.5

rot_mat_notranslate = np.matrix(rot_mat[0:2, 0:2])

tl = (np.array([-w2, h2]) * rot_mat_notranslate).A[0]
tr = (np.array([w2, h2]) * rot_mat_notranslate).A[0]
bl = (np.array([-w2, -h2]) * rot_mat_notranslate).A[0]
br = (np.array([w2, -h2]) * rot_mat_notranslate).A[0]

x_coords = [pt[0] for pt in [tl, tr, bl, br]]
x_pos = [x for x in x_coords if x > 0]
x_neg = [x for x in x_coords if x < 0]

y_coords = [pt[1] for pt in [tl, tr, bl, br]]
y_pos = [y for y in y_coords if y > 0]
y_neg = [y for y in y_coords if y < 0]

right_bound = max(x_pos)
left_bound = min(x_neg)
top_bound = max(y_pos)
bot_bound = min(y_neg)

new_w = int(abs(right_bound - left_bound))
new_h = int(abs(top_bound - bot_bound))
new_image_size = (new_w, new_h)

new_midx = new_w * 0.5
new_midy = new_h * 0.5

dx = int(new_midx - w2)
dy = int(new_midy - h2)

trans_mat = getTranslationMatrix2d(dx, dy)
affine_mat = (np.matrix(trans_mat) * np.matrix(rot_mat))[0:2, :]
result = cv2.warpAffine(image, affine_mat, new_image_size, flags=cv2.INTER_LINEAR)

return result

最佳答案

这个解决方案/实现背后的数学相当于 this solution of an analagous question ,但公式被简化并避免了奇异性。这是与其他解决方案中的 largest_rotated_rect 具有相同接口(interface)的 python 代码,但在几乎所有情况下都提供更大的区域(始终被证明是最佳的):

def rotatedRectWithMaxArea(w, h, angle):
"""
Given a rectangle of size wxh that has been rotated by 'angle' (in
radians), computes the width and height of the largest possible
axis-aligned rectangle (maximal area) within the rotated rectangle.
"""
if w <= 0 or h <= 0:
return 0,0

width_is_longer = w >= h
side_long, side_short = (w,h) if width_is_longer else (h,w)

# since the solutions for angle, -angle and 180-angle are all the same,
# if suffices to look at the first quadrant and the absolute values of sin,cos:
sin_a, cos_a = abs(math.sin(angle)), abs(math.cos(angle))
if side_short <= 2.*sin_a*cos_a*side_long or abs(sin_a-cos_a) < 1e-10:
# half constrained case: two crop corners touch the longer side,
# the other two corners are on the mid-line parallel to the longer line
x = 0.5*side_short
wr,hr = (x/sin_a,x/cos_a) if width_is_longer else (x/cos_a,x/sin_a)
else:
# fully constrained case: crop touches all 4 sides
cos_2a = cos_a*cos_a - sin_a*sin_a
wr,hr = (w*cos_a - h*sin_a)/cos_2a, (h*cos_a - w*sin_a)/cos_2a

return wr,hr

以下是该功能与其他解决方案的比较:

>>> wl,hl = largest_rotated_rect(1500,500,math.radians(20))
>>> print (wl,hl),', area=',wl*hl
(828.2888697391496, 230.61639227890998) , area= 191016.990904
>>> wm,hm = rotatedRectWithMaxArea(1500,500,math.radians(20))
>>> print (wm,hm),', area=',wm*hm
(730.9511000407718, 266.044443118978) , area= 194465.478358

[0,pi/2[中的角度angle旋转图像的边界框(宽度w,高度 h) 具有以下维度:

  • 宽度w_bb = w*cos_a + h*sin_a
  • 高度h_bb = w*sin_a + h*cos_a

如果 w_r, h_r 是计算出的裁剪图像的最佳宽度和高度,则边界框的插入为:

  • 水平方向:(w_bb-w_r)/2
  • 垂直方向:(h_bb-h_r)/2

证明:

寻找具有最大面积的两条平行线之间的轴对齐矩形是一个具有一个参数的优化问题,例如x 如下图: animated parameter

s 表示两条平行线之间的距离(它将变成旋转矩形的较短边)。那么求知矩形的边ab分别与xs-xs-x的比例恒定.,即 x = a sin α 和 (s-x) = b cos α:

enter image description here

所以最大化面积a*b意味着最大化x*(s-x)。由于直角三角形的“高度定理”,我们知道 x*(s-x) = p*q = h*h。因此在 x = s-x = s/2 处达到最大面积,即平行线之间的两个角 E、G 在中线上:

enter image description here

此解决方案仅在此最大矩形适合旋转矩形时才有效。因此,对角线 EG 不得长于旋转矩形的另一边 l。自从

EG = AF + DH = s/2*(cot α + tan α) = s/(2sin αcos α) = s/sin 2*α

我们有条件 s ≤ lsin 2α,其中 s 和 l 是旋转矩形的短边和长边。

在 s > lsin 2α 的情况下,参数 x 必须小于(小于 s/2)并且 s.t.广受欢迎的矩形的所有角都位于旋转矩形的一侧。这导致方程

x*cot α + (s-x)*tan α = l

给出 x = sin α*(lcos α - ssin α)/cos 2*α。从 a = x/sin α 和 b = (s-x)/cos α 我们得到上面用到的公式。

关于python - 旋转图像并裁剪黑色边框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16702966/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com