使用库函数实现旋转,仿射变换
import cv2 # 3.4.2 py37
import matplotlib.pyplot as plt
img = cv2.imread('D:\\Chapter2_1.pgm')
rows, cols, channel = img.shape
degree = 15
M = cv2.getRotationMatrix2D((int(cols / 2), int(rows / 2)), -degree, 1) # 仿射矩阵
dst = cv2.warpAffine(img, M, (cols, rows), flags=cv2.INTER_NEAREST) # 仿射变换
plt.imshow(dst)
plt.show()
自己写函数实现旋转
# coding:utf-8
# py37
# 2019年4月21日14:29:18
# 自己写的图像旋转函数,最近邻插值和双线性插值,旋转矩阵形状是(3,3),OpenCV调库的仿射矩阵是(2,3)的,省略了最后一行的 [0, 0, 1]
# 核心思想是将原始图像上的点的值赋值给旋转后的图像。即找到每一个旋转后的点在原图像上的值(最近邻值,或者双线性插值等)
import cv2 # 3.4.2
import numpy as np
import math
import matplotlib.pyplot as plt
def rgetRotationMatrix(img, centerPoint, angle=0):
"""
:param img: 图像的矩阵
:param centerPoint: 旋转的中心点
:param angle: 顺时针旋转的角度
:return: 仿射矩阵(左乘原始矩阵可以得到仿射变换后的矩阵)
"""
CX, CY = centerPoint[0], centerPoint[1]
height, width, channel = img.shape
angle *= math.pi / 180 # 单位转换
# A0 将图片中心移动到原点的矩阵
A0 = np.array([[1, 0, -CX],
[0, 1, -CY],
[0, 0, 1]])
# A1旋转图片的矩阵
A1 = np.array([[math.cos(angle), -math.sin(angle), 0],
[math.sin(angle), math.cos(angle), 0],
[0, 0, 1]])
# A2 将图片中心 移回
A2 = np.array([[1, 0, CX],
[0, 1, CY],
[0, 0, 1]])
A = A2.dot(A1).dot(A0) # 连乘求仿射矩阵
return A
def rotate(img, A, flag=0):
"""
:param img: 待旋转矩阵
:param A: 仿射变换矩阵
:param flag: 插值法 0为最近邻插值,1为双线性插值
:return: 旋转后的矩阵
"""
height, width, channel = img.shape
newImg = np.zeros((height, width, channel), dtype=int)
A_ = np.linalg.inv(A) # 求逆矩阵
for new_r in range(height): # 遍历新图片,在原图片上找对应的点(最近邻)
for new_c in range(width):
old_c = A_.dot(np.array([[new_c], [new_r], [1]]))[0] # 当前点对应的原图中的坐标
old_r = A_.dot(np.array([[new_c], [new_r], [1]]))[1]
if flag == 0: # 最近邻法
# 四舍五入后取整 相当于找最近的点
old_c = int(old_c.round())
old_r = int(old_r.round())
if old_r >= 0 and old_r < height and old_c >= 0 and old_c < width:
for ch in range(channel):
newImg[new_r][new_c][ch] = img[old_r][old_c][ch]
elif flag == 1: # 双线性插值法
# 在原图中周围四个点的坐标
x0 = int(old_c)
y0 = int(old_r)
x1 = int(old_c) + 1
y1 = int(old_r) + 1
a = old_c - int(old_c) # 将偏差距离作为权重
b = old_r - int(old_r)
# 线性插值取值公式:
if y1 >= 0 and y1 < height - 1 and x1 >= 0 and x1 < width - 1:
for ch in range(channel):
val = a * b * (int(img[y0][x0][ch]) + int(img[y1][x1][ch]) - int(img[y1][x0][ch]) - int(
img[y0][x1][ch])) \
+ a * (int(img[y1][x0][ch]) - int(img[y0][x0][ch])) + b * (
int(img[y0][x1][ch]) - int(img[y0][x0][ch])) \
+ int(img[y0][x0][ch]) # 这里计算的时候需要将所有的数据转成是 整型之后再加减 否者会相见后的数字会特别大,图片就会有大量的白点??为什么不懂
newImg[new_r][new_c][ch] = int(val)
# if val > 250 or val < 0:
# print(val)
return newImg
if __name__ == "__main__":
print(cv2.__version__) # 3.4.2
img = cv2.imread('D:\\Chapter2_1.pgm')
for c in range(img.shape[2]):
img[50:100, 50:100, c] = 255
height, width, channel = img.shape
CX = int((height + 1) / 2)
CY = int((width + 1) / 2)
for f in range(2):
M = rgetRotationMatrix(img, [0, 0], angle=15) # 顺时针旋转15度的仿射矩阵
# M_ = rgetRotationMatrix(img, [0, 0], angle=-15) # 逆时针旋转15度的仿射矩阵
M_ = np.linalg.inv(M) # 逆时针旋转15度的仿射矩阵
newImg1 = rotate(img, M, flag=f) # 顺时针旋转15度
newImg1_ = rotate(newImg1, M_, flag=f) # 旋转回去15度
# 作图并显示
plt.subplot(221), plt.imshow(img), plt.title('Input')
plt.subplot(222), plt.imshow(newImg1), plt.title('newImg1')
plt.subplot(223), plt.imshow(newImg1_), plt.title('newImg1_')
plt.subplot(224), plt.imshow(img - newImg1_), plt.title('img - newImg1_')
plt.show()
END