注释都在代码中:
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()
不够好的地方,希望大家礼貌指出,谢谢。