python环境是黑框吗_python-旋转图像并裁剪出黑色边框

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

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

KWoeo.jpg

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

这基本上与“旋转并裁剪”相同,但是我无法获得该问题的答案。 此外,该答案显然仅对方形图像有效。 我的图像是矩形的。

代码提供给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

10个解决方案

86 votes

该解决方案/实现的背后的数学原理等同于类似问题的解决方案,但是公式被简化并且避免了奇异之处。 这是python代码,具有与其他解决方案中的x相同的接口,但在几乎所有情况下都提供更大的区域(总是被证明是最优的):

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

对于l中的角度x,旋转图像的边界框(宽度x*(s-x) = p*q = h*h,高度x = s-x = s/2)具有以下尺寸:

宽度x

高度x

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

在水平方向上:x

垂直方向:x

证明:

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

coemJ.gif

让x表示两条平行线之间的距离(结果将是旋转矩形的较短边)。 然后,所寻求的矩形的边l、x*(s-x) = p*q = h*h与x = s-x = s/2、s-x分别具有恒定的比率,即x = a sinα和(s-x)= b cosα:

cqx4e.jpg

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

xW1lc.jpg

仅当此最大矩形适合旋转的矩形时,此解决方案才有效。 因此,对角线x的长度不得大于旋转矩形的另一侧l。 以来

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

我们有条件s≤lsin2α,其中s和l是旋转矩形的较短和较长的一面。

如果s> lsin2α,则参数x必须小于(小于s / 2)和s.t。 搜寻矩形的所有角均位于旋转矩形的一侧。 这导致方程

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

给出x = sinα(lcosα-ssinα)/ cos2α。 从a = x / sinα和b =(s-x)/ cosα可以得到上面使用的公式。

coproc answered 2019-11-13T21:55:56Z

25 votes

因此,在研究了许多要求保护的解决方案之后,我终于找到了一种可行的方法。 Andri和Magnus Hoff的答案是“计算旋转矩形中的最大矩形”。

以下Python代码包含感兴趣的方法-largest_rotated_rect-和一个简短的演示。

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 degrees). 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()

76nJM.jpg

只需将此图像(裁剪以显示它可用于非正方形图像)放置在与上述文件相同的目录中,然后运行它。

aaronsnoswell answered 2019-11-13T21:56:33Z

14 votes

祝贺您的出色工作! 我想在带有C ++库的OpenCV中使用您的代码,所以我进行了下面的转换。 也许这种方法可能对其他人有帮助。

#include

#include

#define PI 3.14159265359

using namespace std;

double degree_to_radian(double angle)

{

return angle * PI / 180;

}

cv::Mat rotate_image (cv::Mat image, double angle)

{

// Rotates an OpenCV 2 image about its centre by the given angle

// (in radians). The returned image will be large enough to hold the entire

// new image, with a black background

cv::Size image_size = cv::Size(image.rows, image.cols);

cv::Point image_center = cv::Point(image_size.height/2, image_size.width/2);

// Convert the OpenCV 3x2 matrix to 3x3

cv::Mat rot_mat = cv::getRotationMatrix2D(image_center, angle, 1.0);

double row[3] = {0.0, 0.0, 1.0};

cv::Mat new_row = cv::Mat(1, 3, rot_mat.type(), row);

rot_mat.push_back(new_row);

double slice_mat[2][2] = {

{rot_mat.col(0).at(0), rot_mat.col(1).at(0)},

{rot_mat.col(0).at(1), rot_mat.col(1).at(1)}

};

cv::Mat rot_mat_nontranslate = cv::Mat(2, 2, rot_mat.type(), slice_mat);

double image_w2 = image_size.width * 0.5;

double image_h2 = image_size.height * 0.5;

// Obtain the rotated coordinates of the image corners

std::vector rotated_coords;

double image_dim_d_1[2] = { -image_h2, image_w2 };

cv::Mat image_dim = cv::Mat(1, 2, rot_mat.type(), image_dim_d_1);

rotated_coords.push_back(cv::Mat(image_dim * rot_mat_nontranslate));

double image_dim_d_2[2] = { image_h2, image_w2 };

image_dim = cv::Mat(1, 2, rot_mat.type(), image_dim_d_2);

rotated_coords.push_back(cv::Mat(image_dim * rot_mat_nontranslate));

double image_dim_d_3[2] = { -image_h2, -image_w2 };

image_dim = cv::Mat(1, 2, rot_mat.type(), image_dim_d_3);

rotated_coords.push_back(cv::Mat(image_dim * rot_mat_nontranslate));

double image_dim_d_4[2] = { image_h2, -image_w2 };

image_dim = cv::Mat(1, 2, rot_mat.type(), image_dim_d_4);

rotated_coords.push_back(cv::Mat(image_dim * rot_mat_nontranslate));

// Find the size of the new image

vector x_coords, x_pos, x_neg;

for (int i = 0; i < rotated_coords.size(); i++)

{

double pt = rotated_coords[i].col(0).at(0);

x_coords.push_back(pt);

if (pt > 0)

x_pos.push_back(pt);

else

x_neg.push_back(pt);

}

vector y_coords, y_pos, y_neg;

for (int i = 0; i < rotated_coords.size(); i++)

{

double pt = rotated_coords[i].col(1).at(0);

y_coords.push_back(pt);

if (pt > 0)

y_pos.push_back(pt);

else

y_neg.push_back(pt);

}

double right_bound = *max_element(x_pos.begin(), x_pos.end());

double left_bound = *min_element(x_neg.begin(), x_neg.end());

double top_bound = *max_element(y_pos.begin(), y_pos.end());

double bottom_bound = *min_element(y_neg.begin(), y_neg.end());

int new_w = int(abs(right_bound - left_bound));

int new_h = int(abs(top_bound - bottom_bound));

// We require a translation matrix to keep the image centred

double trans_mat[3][3] = {

{1, 0, int(new_w * 0.5 - image_w2)},

{0, 1, int(new_h * 0.5 - image_h2)},

{0, 0, 1},

};

// Compute the transform for the combined rotation and translation

cv::Mat aux_affine_mat = (cv::Mat(3, 3, rot_mat.type(), trans_mat) * rot_mat);

cv::Mat affine_mat = cv::Mat(2, 3, rot_mat.type(), NULL);

affine_mat.push_back(aux_affine_mat.row(0));

affine_mat.push_back(aux_affine_mat.row(1));

// Apply the transform

cv::Mat output;

cv::warpAffine(image, output, affine_mat, cv::Size(new_h, new_w), cv::INTER_LINEAR);

return output;

}

cv::Size largest_rotated_rect(int h, int w, double 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 (https://stackoverflow.com/questions/16702966/rotate-image-and-crop-out-black-borders)

// Converted to C++ by Eliezer Bernart

int quadrant = int(floor(angle/(PI/2))) & 3;

double sign_alpha = ((quadrant & 1) == 0) ? angle : PI - angle;

double alpha = fmod((fmod(sign_alpha, PI) + PI), PI);

double bb_w = w * cos(alpha) + h * sin(alpha);

double bb_h = w * sin(alpha) + h * cos(alpha);

double gamma = w < h ? atan2(bb_w, bb_w) : atan2(bb_h, bb_h);

double delta = PI - alpha - gamma;

int length = w < h ? h : w;

double d = length * cos(alpha);

double a = d * sin(alpha) / sin(delta);

double y = a * cos(gamma);

double x = y * tan(gamma);

return cv::Size(bb_w - 2 * x, bb_h - 2 * y);

}

// for those interested in the actual optimum - contributed by coproc

#include

cv::Size really_largest_rotated_rect(int h, int w, double 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.

if (w <= 0 || h <= 0)

return cv::Size(0,0);

bool width_is_longer = w >= h;

int side_long = w, side_short = h;

if (!width_is_longer)

std::swap(side_long, side_short);

// since the solutions for angle, -angle and pi-angle are all the same,

// it suffices to look at the first quadrant and the absolute values of sin,cos:

double sin_a = fabs(math.sin(angle)), cos_a = fabs(math.cos(angle));

double wr,hr;

if (side_short <= 2.*sin_a*cos_a*side_long)

{

// 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 = x/sin_a;

hr = x/cos_a;

if (!width_is_longer)

std::swap(wr,hr);

}

else

{

// fully constrained case: crop touches all 4 sides

double cos_2a = cos_a*cos_a - sin_a*sin_a;

wr = (w*cos_a - h*sin_a)/cos_2a;

hr = (h*cos_a - w*sin_a)/cos_2a;

}

return cv::Size(wr,hr);

}

cv::Mat crop_around_center(cv::Mat image, int height, int width)

{

// Given a OpenCV 2 image, crops it to the given width and height,

// around it's centre point

cv::Size image_size = cv::Size(image.rows, image.cols);

cv::Point image_center = cv::Point(int(image_size.height * 0.5), int(image_size.width * 0.5));

if (width > image_size.width)

width = image_size.width;

if (height > image_size.height)

height = image_size.height;

int x1 = int(image_center.x - width * 0.5);

int x2 = int(image_center.x + width * 0.5);

int y1 = int(image_center.y - height * 0.5);

int y2 = int(image_center.y + height * 0.5);

return image(cv::Rect(cv::Point(y1, x1), cv::Point(y2,x2)));

}

void demo(cv::Mat image)

{

// Demos the largest_rotated_rect function

int image_height = image.rows;

int image_width = image.cols;

for (float i = 0.0; i < 360.0; i+=0.5)

{

cv::Mat image_orig = image.clone();

cv::Mat image_rotated = rotate_image(image, i);

cv::Size largest_rect = largest_rotated_rect(image_height, image_width, degree_to_radian(i));

// for those who trust math (added by coproc):

cv::Size largest_rect2 = really_largest_rotated_rect(image_height, image_width, degree_to_radian(i));

cout << "area1 = " << largest_rect.height * largest_rect.width << endl;

cout << "area2 = " << largest_rect2.height * largest_rect2.width << endl;

cv::Mat image_rotated_cropped = crop_around_center(

image_rotated,

largest_rect.height,

largest_rect.width

);

cv::imshow("Original Image", image_orig);

cv::imshow("Rotated Image", image_rotated);

cv::imshow("Cropped image", image_rotated_cropped);

if (char(cv::waitKey(15)) == 'q')

break;

}

}

int main (int argc, char* argv[])

{

cv::Mat image = cv::imread(argv[1]);

if (image.empty())

{

cout << "> The input image was not found." << endl;

exit(EXIT_FAILURE);

}

cout << "Press [s] to begin or restart the demo" << endl;

cout << "Press [q] to quit" << endl;

while (true)

{

cv::imshow("Original Image", image);

char opt = char(cv::waitKey(0));

switch (opt) {

case 's':

demo(image);

break;

case 'q':

return EXIT_SUCCESS;

default:

break;

}

}

return EXIT_SUCCESS;

}

Eliezer Bernart answered 2019-11-13T21:56:58Z

4 votes

TensorFlow中的旋转和裁剪

我个人在TensorFlow中需要此功能,感谢Aaron Snoswell,我可以实现此功能。

def _rotate_and_crop(image, output_height, output_width, rotation_degree, do_crop):

"""Rotate the given image with the given rotation degree and crop for the black edges if necessary

Args:

image: A `Tensor` representing an image of arbitrary size.

output_height: The height of the image after preprocessing.

output_width: The width of the image after preprocessing.

rotation_degree: The degree of rotation on the image.

do_crop: Do cropping if it is True.

Returns:

A rotated image.

"""

# Rotate the given image with the given rotation degree

if rotation_degree != 0:

image = tf.contrib.image.rotate(image, math.radians(rotation_degree), interpolation='BILINEAR')

# Center crop to ommit black noise on the edges

if do_crop == True:

lrr_width, lrr_height = _largest_rotated_rect(output_height, output_width, math.radians(rotation_degree))

resized_image = tf.image.central_crop(image, float(lrr_height)/output_height)

image = tf.image.resize_images(resized_image, [output_height, output_width], method=tf.image.ResizeMethod.BILINEAR, align_corners=False)

return image

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

Source: http://stackoverflow.com/questions/16702966/rotate-image-and-crop-out-black-borders

"""

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

)

如果您需要在TensorFlow中进一步实现示例和可视化,则可以使用此存储库。我希望这对其他人有帮助。

ByungSoo Ko answered 2019-11-13T21:57:35Z

4 votes

为了简短起见,使用了出色的imutils库进行了小幅更新。

def 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

"""

angle = math.radians(angle)

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(img, w, h):

x, y = int(img.shape[1] * .5), int(img.shape[0] * .5)

return img[

int(np.ceil(y - h * .5)) : int(np.floor(y + h * .5)),

int(np.ceil(x - w * .5)) : int(np.floor(x + h * .5))

]

def rotate(img, angle):

# rotate, crop and return original size

(h, w) = img.shape[:2]

img = imutils.rotate_bound(img, angle)

img = crop(img, *rotated_rect(w, h, angle))

img = cv2.resize(img,(w,h),interpolation=cv2.INTER_AREA)

return img

Artemi Krymski answered 2019-11-13T21:58:00Z

1 votes

更正了Coprox在2013年5月27日给出的最受青睐的解决方案:当cosa = cosb无穷大导致最后两行出现时。 通过在前面的if选择器中添加“或cosa等于cosb”来解决。

另外:如果您不知道原始的未旋转的nx和ny,但仅具有旋转的框架(或图像),则找到仅包含该框架的框(我通过删除空白=单色边框来做到这一点),然后首先反向运行程序 它的大小可以找到nx和ny。 如果将图像旋转到一个很小的框架中,以致于将其沿侧面切割(变成八边形),我首先会找到整个容纳框架的x和y扩展。但是,这也不适用于45度左右的角度,在该角度结果变为正方形而不是保持非旋转的宽高比。 对我来说,此例程只能在30度以下正常工作。

还是一个很好的例程! 它解决了我在天文图像对准方面的棘手问题。

Rob Rutten answered 2019-11-13T21:58:39Z

1 votes

受Coprox出色工作的启发,我编写了一个函数,该函数与Coprox的代码一起构成了一个完整的解决方案(因此可以轻松地进行复制和粘贴来使用它)。 下面的rotate_max_area函数仅返回没有黑色边界的旋转图像。

def rotate_bound(image, angle):

# CREDIT: https://www.pyimagesearch.com/2017/01/02/rotate-images-correctly-with-opencv-and-python/

(h, w) = image.shape[:2]

(cX, cY) = (w // 2, h // 2)

M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)

cos = np.abs(M[0, 0])

sin = np.abs(M[0, 1])

nW = int((h * sin) + (w * cos))

nH = int((h * cos) + (w * sin))

M[0, 2] += (nW / 2) - cX

M[1, 2] += (nH / 2) - cY

return cv2.warpAffine(image, M, (nW, nH))

def rotate_max_area(image, angle):

""" image: cv2 image matrix object

angle: in degree

"""

wr, hr = rotatedRectWithMaxArea(image.shape[1], image.shape[0],

math.radians(angle))

rotated = rotate_bound(image, angle)

h, w, _ = rotated.shape

y1 = h//2 - int(hr/2)

y2 = y1 + int(hr)

x1 = w//2 - int(wr/2)

x2 = x1 + int(wr)

return rotated[y1:y2, x1:x2]

Naofumi answered 2019-11-13T21:59:04Z

0 votes

迅捷解决方案

感谢coproc的出色解决方案。 这是迅速的代码

// Given a rectangle of size.width x size.height 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.

func rotatedRectWithMaxArea(size: CGSize, angle: CGFloat) -> CGSize {

let w = size.width

let h = size.height

if(w <= 0 || h <= 0) {

return CGSize.zero

}

let widthIsLonger = w >= h

let (sideLong, sideShort) = widthIsLonger ? (w, h) : (w, h)

// 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:

let (sinA, cosA) = (sin(angle), cos(angle))

if(sideShort <= 2*sinA*cosA*sideLong || abs(sinA-cosA) < 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

let x = 0.5*sideShort

let (wr, hr) = widthIsLonger ? (x/sinA, x/cosA) : (x/cosA, x/sinA)

return CGSize(width: wr, height: hr)

} else {

// fully constrained case: crop touches all 4 sides

let cos2A = cosA*cosA - sinA*sinA

let (wr, hr) = ((w*cosA - h*sinA)/cos2A, (h*cosA - w*sinA)/cos2A)

return CGSize(width: wr, height: hr)

}

}

Josh Bernfeld answered 2019-11-13T21:59:30Z

0 votes

也许更简单的解决方案是:

def crop_image(image, angle):

h, w = image.shape

tan_a = abs(np.tan(angle * np.pi / 180))

b = int(tan_a / (1 - tan_a ** 2) * (h - w * tan_a))

d = int(tan_a / (1 - tan_a ** 2) * (w - h * tan_a))

return image[d:h - d, b:w - b]

与其像许多人一样计算旋转矩形的高度和宽度,还不如寻找旋转图像时形成的黑色三角形的高度。

Federico Corazza answered 2019-11-13T22:00:01Z

-1 votes

有一个简单的方法可以解决此问题,该方法使用另一个称为PIL的模块(仅在您可以不使用opencv的情况下才有用)

下面的代码做的完全一样,并且旋转图像,使您不会得到黑色像素

from PIL import Image

def array_to_img(x, scale=True):

x = x.transpose(1, 2, 0)

if scale:

x += max(-np.min(x), 0)

x /= np.max(x)

x *= 255

if x.shape[2] == 3:

return Image.fromarray(x.astype("uint8"), "RGB")

else:

return Image.fromarray(x[:,:,0].astype("uint8"), "L")

def img_to_array(img):

x = np.asarray(img, dtype='float32')

if len(x.shape)==3:

# RGB: height, width, channel -> channel, height, width

x = x.transpose(2, 0, 1)

else:

# grayscale: height, width -> channel, height, width

x = x.reshape((1, x.shape[0], x.shape[1]))

return x

if __name__ == "__main__":

# Calls a function to convert image to array

image_array = img_to_array(image_name)

# Calls the function to rotate the image by given angle

rotated_image = array_to_img(random_rotation(image_array, rotation_angle))

# give the location where you want to store the image

rotated_image_name=+'roarted_image.png'

# Saves the image in the mentioned location

rotated_image.save(rotated_image_name)

Neeraj Komuravalli answered 2019-11-13T22:00:31Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值