旋转图像和裁剪出的黑色边框 [英] Rotate image and crop out black borders

查看:536
本文介绍了旋转图像和裁剪出的黑色边框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序:我想旋转(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆