简体   繁体   English

图像的二维旋转

[英]2D Rotation of Image

尝试进行 90 度旋转时的图像。左图为原图。 I am trying to rotate the image for any given angle.我正在尝试将图像旋转到任何给定的角度。 I am rotating with the center of the image as the origin.我以图像的中心为原点旋转。

But the code is not doing the rotation as expected.但是代码没有按预期进行旋转。 I am attaching the code below.我附上下面的代码。

import math
import numpy as np
import cv2

im = cv2.imread("Samples\\baboon.jpg", cv2.IMREAD_GRAYSCALE)
new = np.zeros(im.shape,np.uint8)

new_x = im.shape[0] // 2
new_y = im.shape[1] // 2

x = 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()

It looks like you are trying to implement a nearest-neighbor resampler.看起来您正在尝试实现最近邻重采样器。 What you are doing is going through the image and mapping each input pixel to a new location in the output image.您正在做的是浏览图像并将每个输入像素映射到 output 图像中的新位置。 This can lead to problems like pixels overwriting each other incorrectly, output pixels being left empty, and similar.这可能会导致像素错误地相互覆盖、output 像素留空等问题。

I would suggest (based on experience) that you are looking at the problem backwards.我建议(根据经验)您正在向后看问题。 Rather than looking at where an input pixel ends up in the output, you should consider where each output pixel originates in the input.与其查看输入像素在 output 中的最终位置,不如考虑每个 output 像素在输入中的起源位置。 That way, you have no ambiguity about nearest neighbors, and the entire image array will be filled.这样,您对最近邻居就没有歧义,并且整个图像数组将被填充。

You want to rotate about the center.你想围绕中心旋转。 The current rotation matrix you are using rotates about (0, 0) .您正在使用的当前旋转矩阵围绕(0, 0)旋转。 To compensate for that, you need to translate the center of the image to (0, 0) , rotate, and then translate back.为了弥补这一点,您需要将图像的中心平移到(0, 0) ,旋转,然后再平移回来。 Rather than developing the full affine matrix, I will show you how to do the individual operations manually, and then how to combine them into the transform matrix.我不会开发完整的仿射矩阵,而是向您展示如何手动执行各个操作,然后如何将它们组合到变换矩阵中。

Manual Computation手动计算

First get an input and output image:首先得到一个输入和 output 图像:

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

Then determine the center of rotation.然后确定旋转中心。 Be clear about your dimensions x is usually the column (dim 1 ), not the row (dim 0 ):请清楚您的尺寸x通常是列 (dim 1 ),而不是行 (dim 0 ):

center_row = im.shape[0] // 2
center_col = im.shape[1] // 2

Compute the radial coordinates of each pixel in the image, shaped to the corresponding dimension:计算图像中每个像素的径向坐标,形成相应的尺寸:

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

row_coord and col_coord are the distances from center in the output image. row_coordcol_coordoutput图像中距中心的距离。 Now compute the locations where they came from in the input .现在计算它们在输入中来自的位置。 Notice that we can use broadcasting to avoid the need for a loop.请注意,我们可以使用广播来避免循环。 I'm following your original convention for angle definitions here, and finding the inverse rotation to determine the source location.我在此处遵循您对角度定义的原始约定,并找到反向旋转以确定源位置。 The big difference here is that the input in degrees is converted to radians, since that's what the trigonometric functions expect:这里最大的区别在于以度为单位的输入被转换为弧度,因为这是三角函数所期望的:

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

If all the indices were guaranteed to fall within the input image, you wouldn't even need to pre-allocate the output.如果保证所有索引都落在输入图像内,您甚至不需要预先分配 output。 You could literally just do new = im[source_row, source_col] .你可以直接做new = im[source_row, source_col] However, you need to mask the indices:但是,您需要屏蔽索引:

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)]

Affine Transforms仿射变换

Now let's take a look at using Affine transforms.现在让我们看看使用仿射变换。 First you want to subtract the center from your coordinates.首先,您要从坐标中减去中心。 Let's say you have a column vector [[r], [c], [1]] .假设您有一个列向量[[r], [c], [1]] A translation to zero would be the matrix转换为零将是矩阵

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

Then the (backwards) rotation is applied:然后应用(向后)旋转:

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

And finally, you need to translate back to center:最后,您需要翻译回中心:

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

If you multiply these three matrices out in order from right to left, you get如果你把这三个矩阵从右到左依次相乘,你会得到

   [[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              ]]

If you build a full matrix of output coordinates rather than the subset arrays we started with, you can use np.matmul , aka the @ operator to do the multiplication for you.如果您构建 output 坐标的完整矩阵,而不是我们开始使用的子集 arrays,您可以使用np.matmul ,也就是@运算符为您进行乘法运算。 There is no need for this level of complexity for such a simple case though:但是,对于这种简单的情况,不需要这种复杂程度:

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]

The remainder of the processing is fairly similar to the manual computations:处理的其余部分与手动计算非常相似:

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)]

I tried to implement Madphysicist's matrix multiplication method.我尝试实现 Madphysicist 的矩阵乘法方法。 Here's is the implementation, for those who care:对于那些关心的人,这是实现:

#!/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)

I think this is what you are looking for Properly rotate image in OpenCV?我认为这就是您正在寻找的正确旋转 OpenCV 中的图像?

Here is the code这是代码

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM