Skip to content

Instantly share code, notes, and snippets.

@crackwitz
Last active August 8, 2020 20:15
Show Gist options
  • Save crackwitz/32eaee7d923c139a6393de1ed2af80ee to your computer and use it in GitHub Desktop.
Save crackwitz/32eaee7d923c139a6393de1ed2af80ee to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import os
import sys
import numpy as np
import cv2 as cv
def translation(tx, ty):
result = np.eye(3)
result[0:2, 2] = (tx, ty) # set last column
return result
def rotation_by_angle(degrees):
# let's be lazy
result = np.eye(3)
result[0:2, 0:3] = cv.getRotationMatrix2D(center=(0,0), angle=degrees, scale=1.0)
return result
def normalize(vector):
vector = np.array(vector)
length = np.linalg.norm(vector)
return vector / length
def rotation_by_axis(xaxis):
xaxis = normalize(xaxis)
(dx, dy) = xaxis
result = np.eye(3)
result[0:2, 0] = (dx, dy) # x coordinates are mapped to this
result[0:2, 1] = (-dy, dx) # y: 90 degree rotated vector
return result
def shear(xaxis, yaxis):
result = np.eye(3)
result[0:2, 0] = xaxis # x coordinates (x,0) are mapped to this
result[0:2, 1] = yaxis # (0,y) are mapped to this
return result
def scale(sx, sy):
result = np.eye(3)
result[0,0] = sx
result[1,1] = sy
return result
### MAIN PROGRAM ###
if len(sys.argv) >= 2:
srcpath = sys.argv[1]
else:
srcpath = cv.samples.findFile("lena.jpg")
src = cv.imread(srcpath)
sh, sw = src.shape[:2]
dw, dh = (1024, 768) # of anything you like
#dw, dh = sw, sh
# let's build two transformations
# first, shake and bake
M1 = cv.getRotationMatrix2D(center=(sw/2, sh/2), angle=20, scale=1.0)
# second, DIY
# let's use the forward transform, i.e. source point transformed into dest point
# p_dest = T2 * R * T1 * p_src
# T1 moves the rotation center in the source to the origin (subtract)
# R rotates (around "origin")
# T2 moves points to the rotation center in the destination (add)
T1 = translation(tx=-sw/2, ty=-sh/2)
T2 = translation(tx=+dw/2, ty=+dh/2)
# try these:
#R = rotation_by_angle(degrees=20) # replicates the rotation part of getRotationMatrix2D
R = rotation_by_axis((+10, +5)) # uses a (normalized) vector instead
R = shear(xaxis=(1, -0.1), yaxis=(0.5, 0.5)) # notice how the axes are mapped in the output, y is turned diagonal, x is slightly ascending (negative y)
H = T2 @ R @ T1 # @ is np.dot
# I'm calling it H because a 3x3 matrix of this purpose is generally called homography
# homographies can do perspective transformations
# we built an affine transformation
# so the "homography" part should be (0,0,1), i.e. not used at all
assert np.isclose(a=H[2], b=(0,0,1)).all() # check that the last row is (0,0,1)
M2 = H[0:2, :] # take 2x3 part
# WARP_INVERSE_MAP so it's using the matrix as is (by default would invert it)
# try it without that flag too, may give a different intuition
#dest = cv.warpAffine(src, M=M, dsize=(dw, dh), flags=cv.WARP_INVERSE_MAP | cv.INTER_CUBIC)
dest1 = cv.warpAffine(src, M=M1, dsize=(dw, dh), flags=cv.INTER_CUBIC)
dest2 = cv.warpAffine(src, M=M2, dsize=(dw, dh), flags=cv.INTER_CUBIC)
cv.imshow("src", src)
cv.imshow("dest1", dest1)
cv.imshow("dest2", dest2)
cv.waitKey(-1)
cv.destroyAllWindows()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment