import cv2
import numpy as np
from matplotlib import pyplot as plt
import math
import numba as nb
@nb.jit()
def nearest(img, x, y):
if x < 0 or y < 0:
return 0
new_x = round(x)
new_y = round(y)
sp = img.shape
if new_x < 0 or new_y < 0 or new_x > sp[1] or new_y > sp[0]:
return 0
return img[new_y, new_x]
@nb.jit()
def bilinear(img, x, y):
x1 = math.floor(x)
x2 = math.ceil(x)
y1 = math.floor(y)
y2 = math.ceil(y)
sp = img.shape
if x1 < 0 or x2 < 0 or y1 < 0 or y2 < 0 or x1 > sp[1] or x2 > sp[1] or y1 > sp[0] or y2 > sp[0]:
return 0
wx1 = x - math.floor(x)
wx2 = math.ceil(x) - x
wy1 = y - math.floor(y)
wy2 = math.ceil(y) - y
if wx1 == wx2:
if x1 == 0:
wx2 = 1
x2 += 1
else:
wx1 = 1
x1 -= 1
if wy1 == wy2:
if y1 == 0:
wy2 = 1
y2 += 1
else:
wy1 = 1
y1 -= 1
w = np.array([wx2 * wy1, wx1 * wy1, wx2 * wy2, wx1 * wy2])
v = np.array([img[y2, x1], img[y2, x2], img[y1, x1], img[y1, x2]])
return (w * v).sum() / w.sum()
@nb.jit()
def translation(img, tx, ty):
sp = img.shape
new_img = np.zeros((sp[0] + ty, sp[1] + tx), dtype=img.dtype)
new_sp = new_img.shape
T = np.array([[1, 0, tx], [0, 1, ty], [0, 0, 1]], dtype=np.float64)
T_inv = np.linalg.inv(T)
for i in range(new_sp[1]):
for j in range(new_sp[0]):
tmp = np.dot(T_inv, np.array([[i], [j], [1]], dtype=np.float64))
new_img[j][i] = nearest(img, tmp[0, 0], tmp[1, 0])
return new_img
@nb.jit()
def scale(img, cx, cy):
sp = img.shape
new_img = np.zeros((int(sp[0] * cy), int(sp[1] * cx)), dtype=img.dtype)
new_sp = new_img.shape
T = np.zeros((3, 3), dtype=np.float64)
T[0, 0] = cx
T[1, 1] = cy
T[2, 2] = 1
T_inv = np.linalg.inv(T)
for i in range(new_sp[1]):
for j in range(new_sp[0]):
tmp = np.dot(T_inv, np.array([[i], [j], [1]], dtype=np.float64))
new_img[j][i] = bilinear(img, tmp[0, 0], tmp[1, 0])
return new_img
@nb.jit()
def rotate(img, theta):
cos_theta = math.cos(theta)
sin_theta = math.sin(theta)
sp = img.shape
shift = int(math.sqrt(sp[0] ** 2 + sp[1] ** 2))
new_img = np.zeros(
(int(math.sqrt(sp[0] ** 2 + sp[1] ** 2)) * 2 + 1, int(math.sqrt(sp[0] ** 2 + sp[1] ** 2)) * 2 + 1),
dtype=img.dtype)
new_sp = new_img.shape
T = np.zeros((3, 3), dtype=np.float64)
T[0, 0] = cos_theta
T[0, 1] = -sin_theta
T[1, 0] = sin_theta
T[1, 1] = cos_theta
T[2, 2] = 1
T_inv = np.linalg.inv(T)
for i in range(new_sp[1]):
for j in range(new_sp[0]):
tmp = np.dot(T_inv, np.array([[i - shift], [j - shift], [1]], dtype=np.float64))
new_img[j][i] = bilinear(img, tmp[0, 0], tmp[1, 0])
return new_img
def euclidean(img, theta, tx, ty):
return translation(rotate(img, theta), tx, ty)
def similarity(img, theta, tx, ty, cx, cy):
return translation(rotate(scale(img, cx, cy), theta), tx, ty)
@nb.jit()
def affine(img, a11, a12, a21, a22, tx, ty):
sp = img.shape
corner = [[0, 0], [sp[1], 0], [0, sp[0]], [sp[1], sp[0]]]
T = np.zeros((3, 3), dtype=np.float64)
T[0, 0] = a11
T[0, 1] = a12
T[1, 0] = a21
T[1, 1] = a22
T[0, 2] = tx
T[1, 2] = ty
T[2, 2] = 1
new_corner = [np.dot(T, np.array([[c[0]], [c[1]], [1]], dtype=np.float64)) for c in corner]
shift_x = min([int(c[0][0]) for c in new_corner])
shift_y = min([int(c[1][0]) for c in new_corner])
if shift_x > 0:
shift_x = 0
if shift_y > 0:
shift_y = 0
new_img = np.zeros((max([int(c[1][0]) for c in new_corner]) - shift_y,
max([int(c[0][0]) for c in new_corner]) - shift_x), dtype=img.dtype)
new_sp = new_img.shape
T_inv = np.linalg.inv(T)
for i in range(new_sp[1]):
for j in range(new_sp[0]):
tmp = np.dot(T_inv, np.array([[i + shift_x], [j + shift_y], [1]], dtype=np.float64))
new_img[j][i] = bilinear(img, tmp[0, 0], tmp[1, 0])
return new_img
@nb.jit()
def projective(img, h11, h12, h13, h21, h22, h23, h31, h32):
sp = img.shape
corner = [[0, 0], [sp[1], 0], [0, sp[0]], [sp[1], sp[0]]]
T = np.zeros((3, 3), dtype=np.float64)
T[0, 0] = h11
T[0, 1] = h12
T[0, 2] = h13
T[1, 0] = h21
T[1, 1] = h22
T[1, 2] = h23
T[2, 0] = h31
T[2, 1] = h32
T[2, 2] = 1
new_corner = [np.dot(T, np.array([[c[0]], [c[1]], [1]], dtype=np.float64)) for c in corner]
shift_x = min([int(c[0][0] / c[2][0]) for c in new_corner])
shift_y = min([int(c[1][0] / c[2][0]) for c in new_corner])
if shift_x > 0:
shift_x = 0
if shift_y > 0:
shift_y = 0
new_img = np.zeros((max([int(c[1][0] / c[2][0]) for c in new_corner]) - shift_y,
max([int(c[0][0] / c[2][0]) for c in new_corner]) - shift_x), dtype=img.dtype)
new_sp = new_img.shape
T_inv = np.linalg.inv(T)
for i in range(new_sp[1]):
for j in range(new_sp[0]):
tmp = np.dot(T_inv, np.array([[i + shift_x], [j + shift_y], [1]], dtype=np.float64))
new_img[j][i] = bilinear(img, tmp[0, 0] / tmp[2, 0], tmp[1, 0] / tmp[2, 0])
return new_img
if __name__ == '__main__':
img = cv2.imread('lena.tif', cv2.IMREAD_GRAYSCALE)
plt.rcParams['figure.figsize'] = (7, 4)
plt.rcParams['figure.dpi'] = 200
plt.subplot(2, 4, 1)
plt.title('origin')
plt.imshow(img, cmap='gray')
tx = 50
ty = 200
new_img = translation(img, tx, ty)
plt.subplot(2, 4, 2)
plt.title('translation')
plt.imshow(new_img, cmap='gray')
cx = 0.5
cy = 2
new_img = scale(img, cx, cy)
plt.subplot(2, 4, 3)
plt.title('scale')
plt.imshow(new_img, cmap='gray')
theta = 0.3
new_img = rotate(img, theta)
plt.subplot(2, 4, 4)
plt.title('rotate')
plt.imshow(new_img, cmap='gray')
theta = 0.3
tx = 200
ty = 100
new_img = euclidean(img, theta, tx, ty)
plt.subplot(2, 4, 5)
plt.title('euclidean')
plt.imshow(new_img, cmap='gray')
theta = 0.3
tx = 200
ty = 100
cx = 2
cy = 0.5
new_img = similarity(img, theta, tx, ty, cx, cy)
plt.subplot(2, 4, 6)
plt.title('similarity')
plt.imshow(new_img, cmap='gray')
tx = 100
ty = 200
a11 = 1
a12 = 0
a21 = 2
a22 = 1
new_img = affine(img, a11, a12, a21, a22, tx, ty)
plt.subplot(2, 4, 7)
plt.title('affine')
plt.imshow(new_img, cmap='gray')
h11 = 0.97
h12 = -0.14
h13 = 167
h21 = 0.02
h22 = 1.02
h23 = 116
h31 = 0.0005
h32 = 0.0005
new_img = projective(img, h11, h12, h13, h21, h22, h23, h31, h32)
plt.subplot(2, 4, 8)
plt.title('projective')
plt.imshow(new_img, cmap='gray')
plt.show()