如何使用opencv旋转和平移图像而不丢失屏幕外数据

dtcbnfnu  于 2023-02-09  发布在  其他
关注(0)|答案(1)|浏览(261)

我尝试使用opencv来执行后续的图像转换。我有一个图像,我想同时旋转和平移,同时保持整体图像大小不变。我一直使用warpAffine函数与旋转和平移矩阵来执行转换,但问题是在执行一次转换后,一些图像数据丢失,无法结转到下一次转换。

原件x1c 0d1x
旋转

**平移和旋转。**注意原始图像的角是如何被剪切掉的。

所需输出

我想要的是一个与这里的转换图像非常相似的图像,但没有角被剪掉。我理解这是因为在执行第一次仿射变换后角数据被删除。但是,我真的不知道如何在保留这些数据的同时仍然保持图像相对于其中心的原始大小。我对计算机视觉很陌生,在线性代数或矩阵数学方面没有很强的背景。我设法使工作的大多数代码都是从在线教程中学习的,所以任何和所有可访问的帮助解决这个问题将不胜感激!
下面是用于生成上述图像的代码:

import numpy as np
import cv2

def rotate_image(image, angle):
    w, h = (image.shape[1], image.shape[0])
    cx, cy = (w//2,h//2)

    M = cv2.getRotationMatrix2D((cx,cy), -1*angle, 1.0)
    rotated = cv2.warpAffine(image, M, (w,h))
    return rotated

def translate_image(image, d_x, d_y):
    M = np.float32([
        [1,0,d_x],
        [0,1,d_y]
    ])
    
    return cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

path = "dog.jpg"
image = cv2.imread(path)
angle = 30.0
d_x = 200
d_y = 300
rotated = rotate_image(image, angle)
translated = translate_image(rotated, d_x, d_y)
a14dhokn

a14dhokn1#

链接旋转和平移变换正是您所需要的。
代替一个接一个地应用旋转和平移,我们可以应用具有等效链式变换矩阵的cv2.warpAffine
仅使用cv2.warpAffine一次,可防止中间图像(仅中间旋转图像,带有切角)导致的切角。
链接两个变换矩阵是通过将两个矩阵相乘来完成的。
在OpenCV约定中,第一变换从左侧相乘。
2D仿射变换矩阵的最后一行总是[0,0,1]。
OpenCV转换省略了最后一行,因此M为2x3矩阵。
链接OpenCV转换M0M1应用以下阶段:

  • 将"省略最后一行" [0, 0, 1]插入M0M1
T0 = np.vstack((M0, np.array([0, 0, 1])))
 T1 = np.vstack((M1, np.array([0, 0, 1])))
  • 矩阵乘法链变换:
T = T1 @ T0
  • 删除最后一行(等于[0, 0, 1])以匹配OpenCV 2x3约定:
M = T[0:2, :]

高级解决方案应用以下阶段:

  • 计算旋转变换矩阵。
  • 计算平移变换矩阵。
  • 链接旋转和平移变换。
  • 使用链接的变换矩阵应用仿射变换。

代码示例:

import numpy as np
import cv2

def get_rotation_mat(image, angle):
    w, h = (image.shape[1], image.shape[0])
    cx, cy = (w//2,h//2)

    M = cv2.getRotationMatrix2D((cx, cy), -1*angle, 1.0)
    #rotated = cv2.warpAffine(image, M, (w,h))
    return M

def get_translation_mat(d_x, d_y):
    M = np.float64([
        [1, 0, d_x],
        [0, 1, d_y]
    ])
    
    #return cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    return M

def chain_affine_transformation_mats(M0, M1):
    """ 
    Chaining affine transformations given by M0 and M1 matrices.
    M0 - 2x3 matrix applying the first affine transformation (e.g rotation).
    M1 - 2x3 matrix applying the second affine transformation (e.g translation).
    The method returns M - 2x3 matrix that chains the two transformations M0 and M1 (e.g rotation then translation in a single matrix).
    """
    T0 = np.vstack((M0, np.array([0, 0, 1])))  # Add row [0, 0, 1] to the bottom of M0 ([0, 0, 1] applies last row of eye matrix), T0 is 3x3 matrix.
    T1 = np.vstack((M1, np.array([0, 0, 1])))  # Add row [0, 0, 1] to the bottom of M1.
    T = T1 @ T0  # Chain transformations T0 and T1 using matrix multiplication.
    M = T[0:2, :]  # Remove the last row from T (the last row of affine transformations is always [0, 0, 1] and OpenCV conversion is omitting the last row).
    return M

path = "dog.jpg"
image = cv2.imread(path)
angle = 30.0
d_x = 200
d_y = 300
#rotated = rotate_image(image, angle)
#translated = translate_image(rotated, d_x, d_y)
rotationM = get_rotation_mat(image, angle)  # Compute rotation transformation matrix
translationM = get_translation_mat(d_x, d_y)  # Compute translation transformation matrix

M = chain_affine_transformation_mats(rotationM, translationM)  # Chain rotation and translation transformations (translation after rotation)

transformed_image = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))  # Apply affine transformation with the chained (unified) matrix M.

cv2.imwrite("transformed_dog.jpg", transformed_image)  # Store output for testing

输出:

相关问题