第11回 細線化

本題に入る前に、必ず 連絡 の動画を見てください。
Google Colabへのリンク

1. 元画像の作成

動画の解説を参照

今回は白黒の画像を元にして細線化の処理を行います。
細線化とは、黒背景の中の太さのある白い線を、太さ1になるまで細くする処理です。
そのために、以下の条件を満たす元画像が必要になります。 ただし、描画ツールでこのような画像を作ろうとするとミスしがちなポイントがいくつかあります。
(欲しい画像)

そこで、ここではWindowsのペイントを使って下図のような画像を作り、Pythonのコードを使って上図のような画像に変換します。
(自分で作る画像)

普通にペイントで文字を書くと、左図のように白でも黒でもないピクセルができてしまいます。
そこで、閾値を極端に高くした二値化を行い、完全な白以外のピクセルをすべて黒に置き換えます。
img1 = cv2.threshold(img1, 254, 255, cv2.THRESH_BINARY)[1]

その画像の白黒を反転させれば、以下の項での処理に必要な画像ができます。
img1 = cv2.bitwise_not(img1)
以降の処理のため、ファイル形式をカラーから白黒に変換します (色じたいは変わりません)。
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

import cv2
import numpy as np
from google.colab import files

file = files.upload()
filename = next(iter(file))
img = cv2.imread(filename)

# 念のためサイズを400x400pxに
img1 = cv2.resize(img, (400, 200))
# 二値化 (完全な白以外を黒にする)
img1 = cv2.threshold(img1, 254, 255, cv2.THRESH_BINARY)[1]
# 白黒反転
img1 = cv2.bitwise_not(img1)
# グレースケール化
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

cv2.imwrite('ex1.png', img1)

課題1

手書きで自分の姓 (苗字) を書いた画像を作り、白黒反転した画像 ex1.png を出力してください。
(例)

2. 細線化

動画の解説を参照

太さのある線を細くするには、白いエリアの周辺のピクセルを1層ずつ削っていきます。
例えば「左上端」「右下端」「右上端」「右下端」「左上端」「右下端」… のように、斜め端にあたるピクセルを見つけ、削るものがなくなるまで続けることで太さ1の線のみが残ります。

ここでは、skimage.morphology モジュールの skeletonize関数を使って細線化処理を行います。
img2 = skeletonize(img1)
ただし、ここで得られるのはboolean型の値のリストなので、これを画像の形式に変換します。
img2 = img2.astype(np.uint8) * 255

これで白い部分を細線化した画像が得られます。
from skimage.morphology import skeletonize

img2 = skeletonize(img1)
img2 = img2.astype(np.uint8) * 255

cv2.imwrite('ex2.png', img2)

課題2

課題1で作成した画像を元にして細線化を行った画像 ex2.png を出力してください。
(例)

3. ノイズ追加と細線化

動画の解説を参照

実際の運用を考えると、例えば本をスキャンした画像などにはノイズが入る可能性があります。
その場合に細線化したらどうなるかを再現してみましょう。
前回の第1項と同様の方法でノイズを追加すると、白の中に黒、黒の中に白のピクセルができます。

これを細線化すると、黒ピクセルを囲むように「ダマ」ができてしまいます。
img_noise = img1.copy()
# 800個のノイズを追加
for i in range (800):
  x = np.random.randint(0, 400)
  y = np.random.randint(0, 200)
  img_noise[y, x] = 255 - img_noise[y, x]

img3 = skeletonize(img_noise)
img3 = img3.astype(np.uint8) * 255

cv2.imwrite('ex3.png', img3)

課題3

課題1で作成した画像にノイズを追加して細線化を行った画像 ex3.png を出力してください。
※ 画像をダウンロードしてツールで開いて拡大し、線の形がどうなったかを確認してください。
(例)

4. 膨張・収縮の組合せによるノイズ除去

動画の解説を参照

ノイズの入った画像に、膨張→収縮→収縮の順に処理を行うと、ノイズを削除できます。
(元の画像よりも線はひとまわり細くなりますが、細線化の元画像としてはこのまま使えます)

これを細線化すると、ノイズの影響なしに文字の中心線だけが奇麗に残ります。

mask = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8)
img4 = cv2.dilate(img_noise, mask, iterations=1)
img4 = cv2.erode(img4, mask, iterations=1)
img4 = cv2.erode(img4, mask, iterations=1)

img4 = skeletonize(img4)
img4 = img4.astype(np.uint8) * 255

cv2.imwrite('ex4.png', img4)

課題4

課題3で作成したノイズ画像に膨張・収縮・収縮の処理を行ったものを細線化した画像 ex4.png を出力してください。
※ 画像をダウンロードしてツールで開いて拡大し、線の形がどうなったかを確認してください。
(例)

提出

動画の解説を参照

今回作成したノートブックを「imgprc2024@gmail.com」と共有してください。
※ 第2回で共有した、画像共有用の「画像処理」フォルダの中に「第11回」フォルダを作り、その中に今回の元画像と出力画像を入れてください。
※ 課題の再提出の際は、ノートブックの再度の共有はせずにチャットで連絡してください。