射影変換サンプル - you1025/my_something_flagments GitHub Wiki
概要
OpenCV を使って画像上で斜めに撮影された矩形を正面から撮影した画像に変換する。
散歩の途中で大宮八幡の良さげな標識を見つけたのでお賽銭を入れた後にゲット。
画像データの取得
github 上に保存した画像ファイルを一時ファイルとして読み込む。
# 画像データの取得
img_url = "https://github.com/you1025/my_something_flagments/raw/images/images/projective_transform/original.png"
data = requests.get(img_url).content
# 画像データを一時ファイルとしてオープンしデータを読み込む
fp = tempfile.NamedTemporaryFile()
fp.write(data)
src = cv2.imread(fp.name)
fp.close()
# BGR -> RGB
src_image = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
# 元画像の表示
plt.imshow(src_image)
plt.show()
元画像から切り抜く座標を指定
元画像上で斜めに撮影された矩形領域の四隅を指定する。
# 元画像から切り抜く際の四隅を指定(左上-右上-右下-左下)
src_points = np.array([
[1333, 1142],
[1660, 1270],
[1650, 1555],
[1325, 1453]
], dtype=np.float32)
# 元画像に対象領域の四隅の座標を追加した画像を表示
plt.imshow(src_image)
plt.scatter(src_points[:, 0], src_points[:, 1], marker="x", s=10, c="red")
plt.show()
画像上の赤いバッテンが対象領域。
射影変換の実施
上記でくり抜いた矩形領域を正面からの画像に変換する。
# 横幅の倍率を指定(後述)
width_ratio = 1.0
# 出力画像のサイズを設定
width = np.linalg.norm(src_points[1] - src_points[0]) # ベクトル (右上 - 左上) のノルムを算出
width = int(np.floor(width * width_ratio)) # 整数に切り上げ
height = np.linalg.norm(src_points[3] - src_points[0]) # ベクトル (左下 - 左上) のノルムを算出
height = int(np.floor(height)) # 整数に切り上げ
dst_points = np.array([
[ 0, 0],
[width, 0],
[width, height],
[ 0, height]
], dtype=np.float32) # 左上-右上-右下-左下
# 射影変換の実施
M = cv2.getPerspectiveTransform(src_points, dst_points)
output = cv2.warpPerspective(src_image, M, (width, height))
# 射影変換を実施した画像の表示
plt.imshow(output)
plt.show()
width_ratio
)を変更する
横幅の倍率(上記の変換では横幅の縮尺を変更しない版(width_ratio=1.0
)を出力した。
下記では倍率を変更して良さげな出力を検討する。
1.3 倍
見た感じだとこれが良さげかも。
1.5 倍
他の看板も試す
他にも色々と写したので同様に試してみる。
関数の用意
def get_projective_transform(file_path, src_points, width_ratio=1.0, height_ratio=1.0, show_image=True, figsize=(7, 7)):
# ファイルのオープン
src = cv2.imread(file_path)
src_image = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
# 出力画像のサイズを設定
width = np.linalg.norm(src_points[1] - src_points[0])
width = int(np.floor(width * width_ratio))
height = np.linalg.norm(src_points[3] - src_points[0])
height = int(np.floor(height * height_ratio))
dst_points = np.array([
[ 0, 0],
[width, 0],
[width, height],
[ 0, height]
], dtype=np.float32)
# 射影変換の実施
M = cv2.getPerspectiveTransform(src_points, dst_points)
output = cv2.warpPerspective(src_image, M, (width, height))
# 画像の表示
if show_image:
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=figsize)
axes[0].imshow(src_image)
axes[0].scatter(src_points[:, 0], src_points[:, 1], marker="x", s=10, c="red")
axes[1].imshow(output)
plt.show()
return output