为了账号安全,请及时绑定邮箱和手机立即绑定

图像的二维旋转

图像的二维旋转

jeck猫 2023-05-16 14:54:41
我正在尝试将图像旋转任何给定角度。我以图像的中心为原点旋转。但是代码没有按预期进行旋转。我附上下面的代码。import mathimport numpy as npimport cv2im = cv2.imread("Samples\\baboon.jpg", cv2.IMREAD_GRAYSCALE)new = np.zeros(im.shape,np.uint8)new_x = im.shape[0] // 2new_y = im.shape[1] // 2x = int(input("Enter the angle : "))trans_mat = np.array([[math.cos(x), math.sin(x), 0],[-math.sin(x), math.cos(x), 0],[0, 0, 1]])for i in range(-new_x, im.shape[0] - new_x):    for j in range(-new_y, im.shape[1] - new_y):        vec = np.matmul([i, j, 1], trans_mat)        if round(vec[0] + new_x) < 512 and round(vec[1] + new_y) < 512:            new[round(vec[0]+new_x), round(vec[1]+new_y)] = im[i+new_x,j+new_y]cv2.imshow("rot",new)cv2.imshow("1",im)cv2.waitKey(0)cv2.destroyAllWindows()
查看完整描述

3 回答

?
慕少森

TA贡献2019条经验 获得超9个赞

看起来您正在尝试实施最近邻重采样器。您正在做的是遍历图像并将每个输入像素映射到输出图像中的新位置。这可能会导致像素错误地相互覆盖、输出像素留空等问题。


我会建议(根据经验)你正在向后看问题。您不应查看输入像素在输出中的最终位置,而应考虑每个输出像素在输入中的起始位置。这样,您就不会对最近的邻居产生歧义,并且整个图像数组都将被填充。


你想绕中心旋转。您正在使用的当前旋转矩阵围绕 旋转(0, 0)。为了弥补这一点,您需要将图像的中心平移到(0, 0),旋转,然后再平移回来。我不会开发完整的仿射矩阵,而是会向您展示如何手动执行各个操作,然后如何将它们组合到变换矩阵中。


人工计算


首先得到一张输入输出图像:


im = cv2.imread("Samples\\baboon.jpg", cv2.IMREAD_GRAYSCALE)

new = np.zeros_like(im)

然后确定旋转中心。清楚你的维度x通常是列 (dim 1),而不是行 (dim 0):


center_row = im.shape[0] // 2

center_col = im.shape[1] // 2

计算图像中每个像素的径向坐标,整形为相应的维度:


row_coord = np.arange(im.shape[0])[:, None] - center_row

col_coord = np.arange(im.shape[1]) - center_col

row_coord是输出col_coord图像中距中心的距离。现在计算它们在输入中的位置。请注意,我们可以使用广播来避免循环的需要。我在这里遵循您最初的角度定义约定,并找到反向旋转以确定源位置。这里的最大区别在于度数的输入被转换为弧度,因为这是三角函数所期望的:


angle = float(input('Enter Angle in Degrees: ')) * np.pi / 180.0 

source_row = row_coord * np.cos(angle) - col_coord * np.sin(angle) + center_row

source_col = row_coord * np.sin(angle) + col_coord * np.cos(angle) + center_col

如果保证所有索引都落在输入图像中,您甚至不需要预先分配输出。你可以从字面上做new = im[source_row, source_col]。但是,您需要屏蔽索引:


mask = source_row >= 0 & source_row < im.shape[0] & source_col >= 0 & source_col < im.shape[1]

new[mask] = im[source_row[mask].round().astype(int), source_col[mask].round().astype(int)]

仿射变换


现在让我们看一下使用仿射变换。首先,您想从坐标中减去中心。假设您有一个列向量[[r], [c], [1]]。转换为零将是矩阵


[[r']    [[1  0 -rc]  [[r]

 [c']  =  [0  1 -cc] . [c]

 [1 ]]    [0  0  1 ]]  [1]]

然后应用(向后)旋转:


[[r'']    [[cos(a) -sin(a) 0]  [[r']

 [c'']  =  [sin(a)  cos(a) 0] . [c']

 [ 1 ]]    [  0       0    1]]  [1 ]]

最后,你需要翻译回中心:


[[r''']    [[1  0 rc]  [[r'']

 [c''']  =  [0  1 cc] . [c'']

 [ 1  ]]    [0  0  1]]  [ 1 ]]

如果你从右到左依次将这三个矩阵相乘,你会得到


   [[cos(a)   -sin(a)    cc * sin(a) - rc * cos(a) + rc]

M = [sin(a)    cos(a)   -cc * cos(a) - rc * sin(a) + cc]

    [  0         0                      1              ]]

如果您构建一个完整的输出坐标矩阵而不是我们开始的子集数组,您可以使用np.matmul,也就是@运算符为您进行乘法运算。对于这样一个简单的案例,不需要这种复杂程度:


matrix = np.array([[np.cos(angle), -np.sin(angle),  col_center * np.sin(angle) - row_center * np.cos(angle) + row_center],

                   [np.sin(angle),  np.cos(angle), -col_center * np.cos(angle) - row_center * np.sin(angle) + col_center],

                   [0, 0, 1]])


coord = np.ones((*im.shape, 3, 1))

coord[..., 0, :] = np.arange(im.shape[0]).reshape(-1, 1, 1, 1)

coord[..., 1, :] = np.arange(im.shape[1]).reshape(-1, 1, 1)


source = (matrix @ coord)[..., :2, 0]

处理的其余部分与手动计算非常相似:


mask = (source >= 0 & source_row < im.shape).all(axis=-1)

new[mask] = im[source[0, mask].round().astype(int), source_col[1, mask].round().astype(int)]



查看完整回答
反对 回复 2023-05-16
?
跃然一笑

TA贡献1826条经验 获得超6个赞

我试图实现 Madphysicist 的矩阵乘法方法。这是实现,对于那些关心的人:


#!/usr/bin/env python

# -*- coding: utf-8 -*-


import numpy as np

import matplotlib.pyplot as plt

from pathlib import Path


path = Path(".")

img = plt.imread(path.resolve().parent / "img_align" / "faces_imgs" / "4.jpg")

angle = 15



def _transform(rot_mat, x, y):

    """

    conveninece method for matrix multiplication

    """

    return np.matmul(rot_mat, np.array([x, y, 1]))



def rotate(img, angle):

    angle %= 360

    angle = np.radians(angle)

    new = np.zeros_like(img)

    cx, cy = tuple(x / 2 for x in img.shape[:2])


    # Angles are reverse as we are interpolating from destination to source

    rot_mat = np.array(

        [

            [np.cos(-angle), -np.sin(-angle), 0],

            [np.sin(-angle), np.cos(-angle), 0],

            [0, 0, 1],

        ]

    )


    rot_mat[0, 2], rot_mat[1, 2], _ = _transform(rot_mat, -cx, -cy)


    # build combined affine transformation matrrix

    rot_mat[0, 2] += cx

    rot_mat[1, 2] += cy


    coord = np.ones((*img.shape, 3, 1))  # [576x336x3x3x1]

    coord[..., 0, :] = np.arange(img.shape[0]).reshape(-1, 1, 1, 1)

    coord[..., 1, :] = np.arange(img.shape[1]).reshape(-1, 1, 1)


    source = (rot_mat @ coord)[..., :2, 0]

    x_mask = source[..., 0]

    y_mask = source[..., 1]

    mask = (

        (x_mask >= 0)

        & (x_mask < img.shape[0])

        & (y_mask >= 0)

        & (y_mask < img.shape[1])

    ).all(axis=-1)


    # Clipping values to avoid IndexError

    new[mask] = img[

        x_mask[..., 0][mask].round().astype(int).clip(None, img.shape[0] - 1),

        y_mask[..., 1][mask].round().astype(int).clip(None, img.shape[1] - 1),

    ]

    plt.imsave("test.jpg", new)



if __name__ == "__main__":

    rotate(img, angle)


查看完整回答
反对 回复 2023-05-16
?
噜噜哒

TA贡献1784条经验 获得超7个赞

我认为这就是您要寻找的 

这是代码

ang = int(input("Enter the angle : "))

im = cv2.imread("Samples\\baboon.jpg", cv2.IMREAD_GRAYSCALE)



def rotimage(image):

    row,col = image.shape[0:2]

    center=tuple(np.array([col,row])/2)

    rot_mat = cv2.getRotationMatrix2D(center,ang,1.0)

    new_image = cv2.warpAffine(image, rot_mat, (col,row))

    return new_image



new_image = rotimage(im)

cv2.imshow("1",new_image)

cv2.waitKey(0)


查看完整回答
反对 回复 2023-05-16
  • 3 回答
  • 0 关注
  • 120 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信