Pyhonでアフィン変換をつかって2次元の画像を回転、平行移動させる

座標(x,y)のピクセルをアフィン変換で回転させる場合、変換後の座標(x', y')は以下の式で表すことができます。
f:id:steavevaivai:20180715125722p:plain

それからx軸にx_t, y軸にy_t平行移動も加える場合、は以下の式になります。 f:id:steavevaivai:20180715125738p:plain

これをPythonで実装する場合、変換対象の画像が2次元の配列で表せられるのであれば以下のようになります。

import cv2
import math
import numpy as np
from matplotlib import pyplot as plt

rotate_matrix = lambda radian, x_t, y_t : [[math.cos(radian), math.sin(radian), x_t],
                                           [-math.sin(radian), math.cos(radian), y_t]]
def dot_gen(map_matrix):    
    return lambda x: np.dot(map_matrix, x)

def afin_image(afintrans, image, x_length, y_length, ):
    afin_result = np.zeros((y_length, x_length))
    for y in range(len(image)):
        for x in range(len(image[y])):
            if image[y][x] == 0:
                continue
            trans_posi = afintrans([[x],[y],[1]])
            new_x = math.floor(trans_posi[0][0])
            new_y = math.floor(trans_posi[1][0])
            if new_x >= 0 and new_x < x_length and new_y >= 0 and new_y < y_length:
                afin_result[new_y][new_x] = image[y][x]
    return afin_result


afintrans = dot_gen(rotate_matrix(math.radians(-10), 30, 10))
rows,cols = edges.shape
afin_result = afin_image(afintrans, edges, cols, rows)
plt.subplot(122),plt.imshow(afin_result,cmap = 'gray')
plt.title('Rotate Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()
cv2.imwrite("rotate.png", afin_result)

ここでは画像を-10度回転させてx軸に30, y軸に10移動させています。 これにより以下のように画像が変換されます。

  • 変換前
    f:id:steavevaivai:20180715004748p:plain

  • 変換後 f:id:steavevaivai:20180715125813p:plain

OpenCVのアフィン変換で回転、平行移動させる

Pythonで愚直に実装する場合はこのようになると思うのですが、実際使うとしたら遅かったり、OpenCVですでに実装されているのでそちらで動かしてみたいと思います。 OpenCVでは以下のように簡単に使えます。

import cv2
import numpy as np
from matplotlib import pyplot as plt

radian = math.radians(-10)
rows,cols = edges.shape

afin_matrix = np.float32([[math.cos(radian), math.sin(radian), 30],
  [-math.sin(radian), math.cos(radian), 10]])
dst = cv2.warpAffine(edges,afin_matrix,(cols,rows))

plt.subplot(122),plt.imshow(dst,cmap = 'gray')
plt.title('Rotate Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()
cv2.imwrite("rotate.png", afin_result)