2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【画像処理】Numpyで幾何学的変換

Posted at

Numpyで画像の幾何学的変換を実装してみます。

まず、使用する画像を読み込みます。

import numpy as np
import matplotlib.pyplot as plt

original_image = plt.imread(image_name)
if np.issubdtype(original_image.dtype, np.integer):
  original_image = original_image / np.iinfo(original_image.dtype).max
plt.imshow(original_image)

OriginalImage.png

画像の変換は同次座標を用いて3x3の行列で表現することができるので、画像に行列を適用する関数を定義します。
この関数内では、変換後の画像座標に対して逆行列をかけて原画像での位置を求め、二アレストネイバー法で補間しています。

def apply_matrix(image, matrix, background):
  if image.ndim == 2 and background.ndim == 3:
    image = np.tile(image.reshape(image.shape + (1,)), (1, 1, background.shape[2]))
  if image.ndim == 3 and background.ndim == 2:
    background = np.tile(background.reshape(background.shape + (1,)), (1, 1, image.shape[2]))

  coord = np.fromfunction(lambda y, x: np.dstack((x + 0.5, y + 0.5, np.ones(background.shape[:2]))), background.shape[:2])
  sample_coord = np.einsum('ijk,lk->ijl', coord, np.linalg.inv(matrix))

  sample_coord_x = np.round(sample_coord[:,:,0]).astype(int)
  sample_coord_y = np.round(sample_coord[:,:,1]).astype(int)
  clip_sample_coord_x = np.clip(sample_coord_x, 0, image.shape[1] - 1)
  clip_sample_coord_y = np.clip(sample_coord_y, 0, image.shape[0] - 1)

  samplable = (sample_coord_x >= 0) & (sample_coord_x < image.shape[1]) & (sample_coord_y >=0) & (sample_coord_y < image.shape[0])
  if image.ndim == 3:
    samplable = np.tile(samplable.reshape(samplable.shape + (1,)), (1, 1, image.shape[2]))

  return np.where(samplable, image[clip_sample_coord_y, clip_sample_coord_x], background)

この記事では画像の原点は左上になっています。

平行移動

x方向に$t_x$、y方向に$t_y$だけ平行移動させる変換を表す行列は次のようになります。

\begin{pmatrix}
   1 & 0 & t_x \\
   0 & 1 & t_y \\
   0 & 0 & 1 \\
\end{pmatrix}
def translate(x, y):
  return np.array([[1, 0, x],
                   [0, 1, y],
                   [0, 0, 1]])

平行移動を適用します。

background = np.full((512, 512, 3), 0.5)
translate_matrix = translate(100, 200)
translate_image = apply_matrix(original_image, translate_matrix, background)
plt.figure(figsize=(8, 8))
plt.imshow(translate_image)

TranslateImage.png

拡大・縮小

x方向に$s_x$倍、y方向に$s_y$倍の拡大・縮小を表す行列は次のようになります。

\begin{pmatrix}
   s_x & 0 & 0 \\
   0 & s_y & 0 \\
   0 & 0 & 1 \\
\end{pmatrix}
def scale(x, y):
  return np.array([[x, 0, 0],
                   [0, y, 0],
                   [0, 0, 1]])

拡大・縮小を適用します。

background = np.full((512, 512, 3), 0.5)
scale_matrix = scale(1.3, 1.6)
scale_image = apply_matrix(original_image, scale_matrix, background)
plt.figure(figsize=(8, 8))
plt.imshow(scale_image)

ScaleImage.png

回転

原点を中心に$\theta$だけ回転させる変換を表す行列は次のようになります。

\begin{pmatrix}
   \cos\theta & -\sin\theta & 0 \\
   \sin\theta & \cos\theta & 0 \\
   0 & 0 & 1 \\
\end{pmatrix}
def rotate(angle):
  c = np.cos(angle)
  s = np.sin(angle)
  return np.array([[c, -s, 0],
                   [s, c, 0],
                   [0, 0, 1]])

回転を適用します。

background = np.full((512, 512, 3), 0.5)
rotate_matrix = rotate(np.pi / 6.0)
rotate_image = apply_matrix(original_image, rotate_matrix, background)
plt.figure(figsize=(8, 8))
plt.imshow(rotate_image)

RotateImage.png

変換の合成

変換を合成するには行列の積をとります。

background = np.full((512, 512, 3), 0.5)

matrix1 = translate(-original_image.shape[0] / 2, -original_image.shape[1] / 2)
matrix2 = rotate(np.pi / 2)
matrix3 = translate(original_image.shape[0] / 2, original_image.shape[1] / 2)
matrix4 = scale(2.0, 2.0)

composite_matrix = matrix4 @ matrix3 @ matrix2 @ matrix1

composite_image = apply_matrix(original_image, composite_matrix, background)
plt.figure(figsize=(8, 8))
plt.imshow(composite_image)

CompositeImage.png


実装したコードはGoogle Colaboratoryに置いてあります。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?