旋转图像和裁剪出的黑色边框 [英] Rotate image and crop out black borders
问题描述
我的应用程序:我想旋转(OpenCV的使用和Python)的图像
目前,我已经开发出了低于code的旋转输入图像,搭配黑色边框填充它,给我答:我要的为B - 旋转图像内的最大可能范围裁剪窗口。我把这个轴对齐有界框。
这是基本相同旋转和作物,但我不能得到答案对这个问题上班。此外,这个问题的答案显然是仅适用于正方形图像。我的图像是矩形的。
code给答:
进口CV2
进口numpy的为NP
高清getTranslationMatrix2d(DX,DY):
返回numpy的仿射变换矩阵的二维转换
(DX,DY)
返回np.matrix([[1,0,DX],[0,1,镝],[0,0,1]])
高清rotateImage(图像,角度):
旋转给定的图像有关它的中心
IMAGE_SIZE =(image.shape [1],image.shape [0])
image_center =元组(np.array(IMAGE_SIZE)/ 2)
rot_mat = np.vstack([cv2.getRotationMatrix2D(image_center,角度,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([西二环,-H2)* rot_mat_notranslate).A [0]
x_coords = [PT [0] PT中[TL,TR,BL,BR]
X_POS = [X对于x在x_coords如果x> 0]
x_neg = [X对于x在x_coords如果x< 0]
y_coords = [PT [1]在PT [TL,TR,BL,BR]
Y_POS = [Y Y的在y_coords如果y> 0]
y_neg = [Y Y的在y_coords如果y< 0]
right_bound = MAX(X_POS)
left_bound =分钟(x_neg)
top_bound = MAX(Y_POS)
bot_bound =分钟(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:]
结果= cv2.warpAffine(图像,affine_mat,new_image_size,旗帜= cv2.INTER_LINEAR)
返回结果
所以,调查许多人声称的解决方案后,我终于找到了那个工作方法;通过安德里和答案的马格努斯·霍夫中的<一个href="http://stackoverflow.com/questions/5789239/calculate-largest-rectangle-in-a-rotated-rectangle#7519376">Calculate在一个旋转矩形的最大矩形
下面的Python code包含感兴趣的方法 - largest_rotated_rect
- 和一个简短的演示
进口数学
进口CV2
进口numpy的为NP
高清rotate_image(图像,角度):
旋转的OpenCV的2 / NumPy的图像有关它的中心通过预定角度
(弧度)。返回的图像将足以容纳整个大
新形象,黑色背景
#获取的图像大小
#不,这不是一个错误 - NumPy的店面形象基质中向后
IMAGE_SIZE =(image.shape [1],image.shape [0])
image_center =元组(np.array(IMAGE_SIZE)/ 2)
#转换OpenCV的3x2的旋转矩阵为3×3
rot_mat = np.vstack(
[cv2.getRotationMatrix2D(image_center,角度,1.0),[0,0,1]]
)
rot_mat_notranslate = np.matrix(rot_mat [0:2,0:2])
#速记下面Calcs(计算)
image_w2 = IMAGE_SIZE [0] * 0.5
image_h2 = IMAGE_SIZE [1] * 0.5
#获取图像四角的旋转坐标
rotated_coords = [
(np.array([ - image_w2,image_h2])* rot_mat_notranslate).A [0],
(np.array([image_w2,image_h2])* rot_mat_notranslate).A [0],
(np.array([ - image_w2,-image_h2])* rot_mat_notranslate).A [0],
(np.array([image_w2,-image_h2])* rot_mat_notranslate).A [0]
]
#寻找新的图像的大小
x_coords = [PT [0] rotated_coords的葡文]
X_POS = [X对于x在x_coords如果x&GT; 0]
x_neg = [X对于x在x_coords如果x&LT; 0]
y_coords = [PT [1] rotated_coords的葡文]
Y_POS = [Y Y的在y_coords如果y&GT; 0]
y_neg = [Y Y的在y_coords如果y&LT; 0]
right_bound = MAX(X_POS)
left_bound =分钟(x_neg)
top_bound = MAX(Y_POS)
bot_bound =分钟(y_neg)
new_w = INT(ABS(right_bound - left_bound))
new_h = INT(ABS(top_bound - bot_bound))
#我们需要一个转换矩阵,以保持居中图像
trans_mat = np.matrix([
[1,0,INT(new_w * 0.5 - image_w2)],
[0,1,中间体(new_h * 0.5 - image_h2)],
[0,0,1]
])
#计算变换分析的联合旋转和平移
affine_mat =(np.matrix(trans_mat)* np.matrix(rot_mat))[0:2:]
#应用转换
结果= cv2.warpAffine(
图像,
affine_mat,
(new_w,new_h)
标志= cv2.INTER_LINEAR
)
返回结果
高清largest_rotated_rect(W,H,角度):
鉴于已经旋转通过'角度'尺寸宽x高的矩形(在
弧度),计算的最大可能的宽度和高度
轴对齐的旋转矩形内的矩形。
原JS code。通过'安德里和马格努斯霍夫从堆栈溢出
亚伦Snoswell转换到Python
象限= INT(math.floor(角度/(math.pi / 2)))及3
如果sign_alpha =角度((象限&安培; 1)== 0)其它math.pi - 角
阿尔法=(sign_alpha%math.pi + math.pi)%math.pi
bb_w = W * math.cos(阿尔法)+ H * math.sin(阿尔法)
bb_h = W * math.sin(阿尔法)+ H * math.cos(阿尔法)
伽马= math.atan2(bb_w,bb_w)如果(W&LT; H)其他math.atan2(bb_w,bb_w)
三角洲= math.pi - 阿尔法 - γ
如果长度= H(W&LT; H)其他W¯¯
D =长度* math.cos(阿尔法)
A = D * math.sin(阿尔法)/ math.sin(增量)
Y = A * math.cos(伽马)
X = Y * math.tan(伽马)
返回 (
bb_w - 2 * X,
bb_h - 2 * Y
)
高清crop_around_center(图像,宽度,高度):
给定一个NumPy的/ OpenCV的2图像,作物它给定的宽度和高度,
围绕它的中心点
IMAGE_SIZE =(image.shape [1],image.shape [0])
image_center =(中间体(IMAGE_SIZE [0] * 0.5),INT(IMAGE_SIZE [1] * 0.5))
如果(宽度GT; IMAGE_SIZE [0]):
宽度= IMAGE_SIZE [0]
如果(高度&GT; IMAGE_SIZE [1]):
高度= IMAGE_SIZE [1]
X1 = INT(image_center [0] - 宽* 0.5)
X2 = INT(image_center [0] +宽* 0.5)
Y1 = INT(image_center [1] - 高度* 0.5)
Y2 = INT(image_center [1] +高* 0.5)
返回图像[Y1:Y2,X1:X2]
高清演示():
演示的largest_rotated_rect功能
图像= cv2.imread(lenna_rectangle.png)
IMAGE_HEIGHT,IMAGE_WIDTH = image.shape [0:2]
cv2.imshow(原始图像,图像)
打印preSS [进入]开始演示
打印preSS [Q]或逃脱退出
键= cv2.waitKey(0)
如果key == ORD(Q)或键== 27:
出口()
因为我在np.arange(0,360,0.5):
image_orig = np.copy(图)
image_rotated = rotate_image(图像,I)
image_rotated_cropped = crop_around_center(
image_rotated,
* largest_rotated_rect(
IMAGE_WIDTH,
IMAGE_HEIGHT,
math.radians㈠
)
)
键= cv2.waitKey(2)
如果(关键== ORD(Q)或键== 27):
出口()
cv2.imshow(原始图像,image_orig)
cv2.imshow(旋转图像,image_rotated)
cv2.imshow(裁剪图像,image_rotated_cropped)
打印完成
如果__name__ ==__main__:
演示()
只需将这个图片(裁剪,以证明它的工作原理与非正方形图像)在同一个目录如上面的文件,然后运行它。
My application: I am trying to rotate an image (using OpenCV and Python)
At the moment I have developed the below code which rotates an input image, padding it with black borders, giving me A. What I want is B - the largest possible area crop window within the rotated image. I call this the axis-aligned boundED box.
This is essentially the same as Rotate and crop, however I cannot get the answer on that question to work. Additionally, that answer is apparently only valid for square images. My images are rectangular.
Code to give 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
So, after investigating many claimed solutions, I have finally found a method that works; The answer by Andri and Magnus Hoff on Calculate largest rectangle in a rotated rectangle.
The below Python code contains the method of interest - largest_rotated_rect
- and a short demo.
import math
import cv2
import numpy as np
def rotate_image(image, angle):
"""
Rotates an OpenCV 2 / NumPy image about it's centre by the given angle
(in radians). The returned image will be large enough to hold the entire
new image, with a black background
"""
# Get the image size
# No that's not an error - NumPy stores image matricies backwards
image_size = (image.shape[1], image.shape[0])
image_center = tuple(np.array(image_size) / 2)
# Convert the OpenCV 3x2 rotation matrix to 3x3
rot_mat = np.vstack(
[cv2.getRotationMatrix2D(image_center, angle, 1.0), [0, 0, 1]]
)
rot_mat_notranslate = np.matrix(rot_mat[0:2, 0:2])
# Shorthand for below calcs
image_w2 = image_size[0] * 0.5
image_h2 = image_size[1] * 0.5
# Obtain the rotated coordinates of the image corners
rotated_coords = [
(np.array([-image_w2, image_h2]) * rot_mat_notranslate).A[0],
(np.array([ image_w2, image_h2]) * rot_mat_notranslate).A[0],
(np.array([-image_w2, -image_h2]) * rot_mat_notranslate).A[0],
(np.array([ image_w2, -image_h2]) * rot_mat_notranslate).A[0]
]
# Find the size of the new image
x_coords = [pt[0] for pt in rotated_coords]
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 rotated_coords]
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))
# We require a translation matrix to keep the image centred
trans_mat = np.matrix([
[1, 0, int(new_w * 0.5 - image_w2)],
[0, 1, int(new_h * 0.5 - image_h2)],
[0, 0, 1]
])
# Compute the tranform for the combined rotation and translation
affine_mat = (np.matrix(trans_mat) * np.matrix(rot_mat))[0:2, :]
# Apply the transform
result = cv2.warpAffine(
image,
affine_mat,
(new_w, new_h),
flags=cv2.INTER_LINEAR
)
return result
def largest_rotated_rect(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 within the rotated rectangle.
Original JS code by 'Andri' and Magnus Hoff from Stack Overflow
Converted to Python by Aaron Snoswell
"""
quadrant = int(math.floor(angle / (math.pi / 2))) & 3
sign_alpha = angle if ((quadrant & 1) == 0) else math.pi - angle
alpha = (sign_alpha % math.pi + math.pi) % math.pi
bb_w = w * math.cos(alpha) + h * math.sin(alpha)
bb_h = w * math.sin(alpha) + h * math.cos(alpha)
gamma = math.atan2(bb_w, bb_w) if (w < h) else math.atan2(bb_w, bb_w)
delta = math.pi - alpha - gamma
length = h if (w < h) else w
d = length * math.cos(alpha)
a = d * math.sin(alpha) / math.sin(delta)
y = a * math.cos(gamma)
x = y * math.tan(gamma)
return (
bb_w - 2 * x,
bb_h - 2 * y
)
def crop_around_center(image, width, height):
"""
Given a NumPy / OpenCV 2 image, crops it to the given width and height,
around it's centre point
"""
image_size = (image.shape[1], image.shape[0])
image_center = (int(image_size[0] * 0.5), int(image_size[1] * 0.5))
if(width > image_size[0]):
width = image_size[0]
if(height > image_size[1]):
height = image_size[1]
x1 = int(image_center[0] - width * 0.5)
x2 = int(image_center[0] + width * 0.5)
y1 = int(image_center[1] - height * 0.5)
y2 = int(image_center[1] + height * 0.5)
return image[y1:y2, x1:x2]
def demo():
"""
Demos the largest_rotated_rect function
"""
image = cv2.imread("lenna_rectangle.png")
image_height, image_width = image.shape[0:2]
cv2.imshow("Original Image", image)
print "Press [enter] to begin the demo"
print "Press [q] or Escape to quit"
key = cv2.waitKey(0)
if key == ord("q") or key == 27:
exit()
for i in np.arange(0, 360, 0.5):
image_orig = np.copy(image)
image_rotated = rotate_image(image, i)
image_rotated_cropped = crop_around_center(
image_rotated,
*largest_rotated_rect(
image_width,
image_height,
math.radians(i)
)
)
key = cv2.waitKey(2)
if(key == ord("q") or key == 27):
exit()
cv2.imshow("Original Image", image_orig)
cv2.imshow("Rotated Image", image_rotated)
cv2.imshow("Cropped Image", image_rotated_cropped)
print "Done"
if __name__ == "__main__":
demo()
Simply place this image (cropped to demonstrate that it works with non-square images) in the same directory as the above file, then run it.
这篇关于旋转图像和裁剪出的黑色边框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!