代码来源:https://github.com/shouxieai/tensorRT_Pro
# 实现一个仿射变换,采用双线性插值方式实现一个warpaffine
def pyWarpAffine(image, M, dst_size, constant=(0,0,0)):
M = cv.invertAffineTransform(M) # 求仿射变换的逆矩阵,因为我们是把目的图片作为输入图片,因此需要使用逆矩阵求取原始图片的点
constant = np.array(constant)
ih,iw = image.shape[:2]
dw,dh = dst_size
dst = np.full((dh,dw,3), constant, dtype=np.uint8)
irange = lambda p:p[0]>=0 and p[0]<iw and p[1]>=0 and p[1]<ih # 边界判断
# 开始遍历像素点
# 这里需要确定的是这里为了尽量降低计算量,采用遍历目标图片的像素,显然目标图片的像素大小是确定的,无论输入的图片大小是多大
# 最后我都会变换到目标图片大小,如输入到深度学习模型的图片应该是640x640,原始图片的大小为1080x1920,显然遍历原始图片的计算很大
# 遍历目标的图片是固定的且不大,那么这个仿射变换如何做呢?
# 1. 首先输入的仿射变换矩阵是从原始图片的点--->目标图片的点,因此需要取逆变换获取到从目标图像的点--->原始图片的点
# 2. 当变换到原始图片的点位置时,将采用双线性变换的方法计算该点在原始位置的像素值
# 3. 如何计算呢?这里需要想明白,双线的本质是通过四个点的值计算一个点的值,那么变换到原始图片的点就是我们需要求的点值,
# 这个计算出来的值将直接赋值到目标图片对应位置,但是这四个点如何选取?其实很简单,就取相邻的四个点即可如:
# (0,0) (1,0) (250,250) (251,250)
# (0,1) (1,1) (250,251) (251,251)
# 这个四个点的选取就是变换过来的点的相邻四个点即可,如何做呢?上下取整即可如上面我举例两个点,
# 假如从目标的点变换到原始图片的点为(250.35,250.65),那么这个点正好在上面的四个点的范围内,计算相对位置就是(0.35,0.65)
# 然后通过双线性计算该点的值,把该点的值直接赋值目标待求点位置即可,理解到这一步基本就完全理解了
for y in range(dh):
for x in range(dw):
# 构造一个齐次矩阵
homogeneous = np.array([[x,y,1]]).T # 一个列矩阵
ox, oy = M @ homogeneous # 把目标的点仿射变换为原始图像的点
low_ox = int(np.floor(ox)) # 向下取整
low_oy = int(np.floor(oy)) # 向下取整
high_ox = low_ox + 1 # 向上取整
high_oy = low_oy + 1 # 向上取整
# 双线性插值
# p0 p1
# 0
# p2 p3
# 针对图片来说
pos = ox - low_ox, oy - low_oy # 获取相对位置
p0_area = (1 - pos[0]) * (1 - pos[1])
p1_area = pos[0] * (1 - pos[1])
p2_area = (1 - pos[0]) * pos[1]
p3_area = pos[0] * pos[1]
p0 = low_ox, low_oy
p1 = high_ox, low_oy
p2 = low_ox, high_oy
p3 = high_ox, high_oy
print(image[p0[1], p0[0]])
p0_value = image[p0[1], p0[0]] if irange(p0) else constant
p1_value = image[p1[1], p1[0]] if irange(p1) else constant
p2_value = image[p2[1], p2[0]] if irange(p2) else constant
p3_value = image[p3[1], p3[0]] if irange(p3) else constant
dst[y, x] = p0_area * p0_value + p1_area * p1_value + p2_area * p2_value + p3_area * p3_value
return dst
cat1 = cv.imread("cat1.png")
#acat1_cv, M, inv = align(cat1, (100, 100))
M = cv.getRotationMatrix2D((0, 0), -30, 3)
acat1_cv = cv.warpAffine(cat1, M, (640, 640))
acat1_py = pyWarpAffine(cat1, M, (640, 640))
plt.figure(figsize=(10, 10))
plt.subplot(1, 2, 1)
plt.title("OpenCV")
plt.imshow(acat1_cv[..., ::-1])
plt.subplot(1, 2, 2)
plt.title("PyWarpAffine")
plt.imshow(acat1_py[..., ::-1])
plt.show()