python使用numpy实现图像旋转

注释都在代码中:

from skimage import io, data
import numpy as np
import matplotlib.pyplot as plt
import math

# 加载图像
image = data.coffee()
# image = data.camera()


# 建立灰度图旋转函数
def image_rotate(img, degrees=0, x0=0, y0=0, resize=False):
    """
    :param img:
    :param degrees:
    :param x0: 这个是图像的宽
    :param y0: 这个是图像的高
    :param resize:
    :return:
    """
    # 建立旋转需要的全部矩阵
    # 将角度转为弧度和正弦余弦值
    radians = math.radians(degrees)
    sinA = math.sin(radians)
    cosA = math.cos(radians)
    # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标
    mat2dika2mat = np.mat([[1, 0, 0], [0, -1, 0], [-x0, y0, 1]]) * \
                   np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]) * \
                   np.mat([[1, 0, 0], [0, -1, 0], [x0, y0, 1]])
    # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标(这是用于反向转回的矩阵)
    mat2dika2mat_r = np.mat([[1, 0, 0], [0, -1, 0], [-x0, y0, 1]]) * \
                     np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]).I * \
                     np.mat([[1, 0, 0], [0, -1, 0], [x0, y0, 1]])

    # 给旋转后的图像大小一个初始值
    img_h, img_w = img.shape[:2]
    if len(img.shape) == 2:
        img_d = 0
    else:
        img_d = img.shape[2]
    # 首先求出旋转之后图像的大小
    if resize:
        # 将四个顶点分别进行计算旋转后的位置,以此确定旋转后图像多大
        # 注意:设定好的矩阵的运算中,横着向右代表矩阵坐标的横轴正方形,竖着向下代表矩阵坐标的竖轴正方向
        tops = np.mat([[0, 0, 1],
                         [0, img_h-1, 1],
                         [img_w-1, 0, 1],
                         [img_w-1, img_h-1, 1]])
        # 四个点分别进行旋转
        for i in range(tops.shape[0]):
            tops[i] = tops[i] * mat2dika2mat
        # 取出行和列的最大最小值
        max_hw = tops.max(axis=0)
        min_hw = tops.min(axis=0)
        max_w, max_h = max_hw[0, 0], max_hw[0, 1]
        min_w, min_h = min_hw[0, 0], min_hw[0, 1]
        # 设置旋转后图像的大小
        img_h, img_w = abs(int(max_h - min_h)), abs(int(max_w - min_w))
        # 重新建立新旋转中心的运算矩阵
        # 新的旋转中心找到之后,只需要替换旋转时从笛卡尔坐标系转换为矩阵坐标系那个公式中的旋转中心坐标
        x0_ = x0 * img_w // img.shape[1]
        y0_ = y0 * img_h // img.shape[0]
        # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标
        mat2dika2mat = np.mat([[1, 0, 0], [0, -1, 0], [-x0, y0, 1]]) * \
                       np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]) * \
                       np.mat([[1, 0, 0], [0, -1, 0], [x0_, y0_, 1]])
        # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标(这是用于反向转回的矩阵)
        mat2dika2mat_r = np.mat([[1, 0, 0], [0, -1, 0], [-x0_, y0_, 1]]) * \
                         np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]).I * \
                         np.mat([[1, 0, 0], [0, -1, 0], [x0, y0, 1]])
    # 建立空白图像
    if img_d:
        img_new = np.zeros((img_h+1, img_w+1, img_d), dtype='uint8')
    else:
        img_new = np.zeros((img_h + 1, img_w + 1), dtype='uint8')
    # 循环旋转每一个像素点
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            temp = np.mat([j, i, 1]) * mat2dika2mat
            x, y, t = temp[0, 0], temp[0, 1], temp[0, 2]
            x = int(x)
            y = int(y)
            if x > img_new.shape[1] - 1 or x < 0 or y > img_new.shape[0] - 1 or y < 0:
                continue
            img_new[y, x] = img[i, j]
    # 对全部的值进行双线性插值运算
    for i in range(img_new.shape[0]):
        for j in range(img_new.shape[1]):
            # if img[i, j] != 0:
            #     continue
            temp = np.mat([j, i, 1]) * mat2dika2mat_r
            x, y, t = temp[0, 0], temp[0, 1], temp[0, 2]
            if x > img.shape[1] - 1 or x < 0 or y > img.shape[0] - 1 or y < 0:
                continue
            n = int(x)
            m = int(y)
            u = x - n
            v = y - m
            if n >= img.shape[1] - 1:
                n = img.shape[1] - 2
            if m >= img.shape[0] - 1:
                m = img.shape[0] - 2
            img_new[i, j] = (1 - v) * (1 - u) * img[m, n] + (1 - v) * u * img[m, n + 1] + v * (1 - u) * img[
                m + 1, n] + v * u * img[m + 1, n + 1]
    # 返回旋转完成的图像
    return img_new


# 调用旋转函数
img = image_rotate(image, 60, image.shape[1]//2, image.shape[0]//2, False)
# 展示旋转图像
plt.imshow(img, cmap="gray")
plt.show()

不够好的地方,希望大家礼貌指出,谢谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值