【画像処理】Numpyで図形描画

Numpyで画像に図形描画してみます。

まず、使用する画像を読み込んでおきます。

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/18f5237c-6a66-5d7f-f86a-ed98fad52909.png)


## 円

塗りつぶしの円です。

```python
def fill_circle(image, color, center, radius):
  coord = np.fromfunction(lambda y, x: np.dstack((y + 0.5, x + 0.5)), image.shape[:2])
  dist2 = (coord[:,:,1] - center[0]) ** 2 + (coord[:,:,0] - center[1]) ** 2
  condition = dist2 <= radius ** 2
  if image.ndim == 3:
    condition = np.tile(condition.reshape(condition.shape + (1,)), (1, 1, image.shape[2]))
  return np.where(condition, color, image)

fill_circle_image = fill_circle(original_image,  np.array([1.0, 0.0, 1.0]), (80, 120), 40)
plt.imshow(fill_circle_image)
```

![CircleFillImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/2347fec4-7732-4634-0a2e-c8ad368c919e.png)

線の円です。

```python
def stroke_circle(image, color, weight, center, radius):
  coord = np.fromfunction(lambda y, x: np.dstack((y + 0.5, x + 0.5)), image.shape[:2])
  dist2 = (coord[:,:,1] - center[0]) ** 2 + (coord[:,:,0] - center[1]) ** 2
  condition = abs(np.sqrt(dist2) - radius) - weight * 0.5 <= 0
  if image.ndim == 3:
    condition = np.tile(condition.reshape(condition.shape + (1,)), (1, 1, image.shape[2]))
  return np.where(condition, color, image)

stroke_circle_image = stroke_circle(original_image, np.array([1.0, 0.0, 1.0]), 3.0, (80, 120), 40)
plt.imshow(stroke_circle_image)
```

![CircleStrokeImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/559c8702-cb1b-9ecd-7b6b-8747b31426ec.png)

## 四角形

塗りつぶしの四角形です。

```python
def fill_rectangle(image, color, center, size):
  coord = np.fromfunction(lambda y, x: np.dstack((y + 0.5, x + 0.5)), image.shape[:2])
  dist = np.dstack((abs(coord[:,:,1] - center[0]) - size[0] / 2, abs(coord[:,:,0] - center[1]) - size[1] / 2)).max(axis=2)
  condition = dist <= 0
  if image.ndim == 3:
    condition = np.tile(condition.reshape(condition.shape + (1,)), (1, 1, image.shape[2]))
  return np.where(condition, color, image)

fill_rectangle_image = fill_rectangle(original_image, np.array([1.0, 0.0, 1.0]), (80, 120), (120, 80))
plt.imshow(fill_rectangle_image)
```

![RectangleFillImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/064e9a2f-b49a-9e60-5ac6-6c8296079476.png)

線の四角形です。

```python
def stroke_rectangle(image, color, weight, center, size):
  coord = np.fromfunction(lambda y, x: np.dstack((y + 0.5, x + 0.5)), image.shape[:2])
  dist = np.dstack((abs(coord[:,:,1] - center[0]) - size[0] / 2, abs(coord[:,:,0] - center[1]) - size[1] / 2)).max(axis=2)
  condition = abs(dist) - weight * 0.5 <= 0
  if image.ndim == 3:
    condition = np.tile(condition.reshape(condition.shape + (1,)), (1, 1, image.shape[2]))
  return np.where(condition, color, image)

stroke_rectangle_image = stroke_rectangle(original_image, np.array([1.0, 0.0, 1.0]), 3.0, (80, 120), (120, 80))
plt.imshow(stroke_rectangle_image)
```

![RectangleStrokeImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/6cb30271-7513-fc27-018d-2d0708330401.png)

## 直線

二点間を結ぶ直線です。

```python
def line(image, color, weight, point1, point2):
  coord = np.fromfunction(lambda y, x: np.dstack((y + 0.5, x + 0.5)), image.shape[:2])
  p12 = np.array([point2[1] - point1[1], point2[0] - point1[0]])
  p12_norm = np.linalg.norm(p12)
  p12_dir = p12 / p12_norm
  p1c = np.dstack(([coord[:,:,0] - point1[1], coord[:,:,1] - point1[0]]))
  dot = np.einsum('ijk,k->ij', p1c, p12_dir)
  dist = np.sqrt(p1c[:,:,0] ** 2 + p1c[:,:,1] ** 2 - dot ** 2)
  condition = (dot >= 0) & (dot <= p12_norm) & (dist <= weight * 0.5)
  if image.ndim == 3:
    condition = np.tile(condition.reshape(condition.shape + (1,)), (1, 1, image.shape[2]))
  return np.where(condition, color, image)

line_image = line(original_image, np.array([1.0, 0.0, 1.0]), 3.0, (30, 40), (200, 150))
plt.imshow(line_image)
```

![LineImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/52a9b0d1-8cfa-7b14-2d91-74c7d520d654.png)

---

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

https://colab.research.google.com/drive/1tajKerusFlJvgTGh_hIw-0Yt4v6JEZEv?usp=sharing