動画の解説を参照
今回は白黒の画像を元にして膨張 (白いエリアを大きくする)・収縮 (黒いエリアを大きくする) の処理を行います。
そのために、以下の条件を満たす元画像を用意します。
- すべてのピクセルが「完全な黒」か「完全な白」のどちらか
- 黒い背景の中に白で塗りつぶされた図形がある
- サイズが400x400ピクセル
(動画ではWindowsのペイントを使って元画像を作る方法について解説します)
膨張・収縮の処理はノイズ消去にも使えます。
その結果を確認するため、白いエリアの中には黒、黒いエリアの中に白のノイズを追加します。
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, 400))
# 念のため二値化
img1 = cv2.threshold(img1, 127, 255, cv2.THRESH_BINARY)[1]
# 400個のノイズを追加
for i in range (400):
x = np.random.randint(0, 400)
y = np.random.randint(0, 400)
img1[y, x] = 255 - img1[y, x]
cv2.imwrite('ex1.png', img1)
条件を満たす元画像を作成し、400個のノイズを追加した画像 ex1.png を出力してください。
(例)
動画の解説を参照
膨張処理では、それぞれのピクセルについて「自分と上下左右に接するもののうちどれか1つでも白」なら、そのピクセルを白に変えます。

その結果、白いノイズは十字の形に膨らみ、黒いノイズが消えます。
また、白いエリアが1ピクセル分広がります。
OpenCVではこのようなマスクを用意して
mask = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8)
dilate関数を使うと膨張処理が行われます。
img2_dilate = cv2.dilate(img1, mask, iterations=1)
第8回のトゥーン化で輪郭の太線を作るときにもdilate関数を使いました。
このときに使ったマスクはこのようなものです。5x5の範囲をすべて判定に使うため、一気に太い線になります。
np.ones((5, 5), np.uint8)
収縮処理では、それぞれのピクセルについて「自分と上下左右に接するもののうちどれか1つでも黒」なら、そのピクセルを黒に変えます。

その結果、黒いノイズは十字の形に膨らみ、白いノイズが消えます。
また、黒いエリアが1ピクセル分広がります (白いエリアが1ピクセル分狭くなります)。
OpenCVでは、erode関数を使うと収縮処理が行われます。
判定に使う範囲は膨張処理と同じなので、上のコードの mask を使いまわします。
img2_dilate = cv2.erode(img1, mask, iterations=1)
mask = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8)
img2_dilate = cv2.dilate(img1, mask, iterations=1)
cv2.imwrite('ex2_dilate.png', img2_dilate)
img2_erode = cv2.erode(img1, mask, iterations=1)
cv2.imwrite('ex2_erode.png', img2_erode)
動画の解説を参照
膨張・収縮ではそれぞれ黒・白のノイズを消せますが、もう一方のノイズは大きくなってしまいます。
そこで、「収縮→膨張」の順に処理を行ってみます。
すると、いったん大きくなった黒いノイズは元の大きさに戻ります。一方、白いノイズは消えたままです。
また、いったん広がった黒いエリアも元の大きさに戻ります。
この処理を
オープニングといいます。
逆に「膨張→収縮」の順に処理を行うと、
すると、いったん大きくなった白いノイズは元の大きさに戻ります。一方、黒いノイズは消えたままです。
また、いったん広がった白いエリアも元の大きさに戻ります。
この処理を
クロージングといいます。
オープニング・クロージングの処理は、前項の dilate関数、erode関数を組み合わせてもできますが、OpenCVではmorphologyEx関数で実行できます。
img3_oepning = cv2.morphologyEx(img1, cv2.MORPH_OPEN, mask)
cv2.imwrite('ex3_oepning.png', img3_oepning)
img3_closing = cv2.morphologyEx(img1, cv2.MORPH_CLOSE, mask)
cv2.imwrite('ex3_closing.png', img3_closing)
課題1で作成したノイズ画像を元にしてオープニング・クロージングを行った画像 ex3_oepning.png, ex3_closing.png を出力してください。
※ 画像をダウンロードしてツールで開いて拡大し、ノイズがどうなったかを確認してください。
動画の解説を参照
元の(ノイズ入り)画像とオープニングした画像を比べると、「白いノイズがあるかどうか」だけが違います。
この「異なっている部分」だけを白、同じ部分を黒とした画像を作ると、白ノイズがあった場所だけが白くなります。
この処理を
トップハットといいます。
元の(ノイズ入り)画像とクロージングした画像を比べると、「黒いノイズがあるかどうか」だけが違います。
この「異なっている部分」だけを白、同じ部分を黒とした画像を作ると、黒ノイズがあった場所だけが白くなります。
この処理を
ブラックハットといいます。
トップハット・ブラックハットの処理は第1項のと第3項の画像の各ピクセルの明度で排他的論理和をとればできますが、OpenCVでは前項と同じmorphologyEx関数で実行できます。
img4_tophat = cv2.morphologyEx(img1, cv2.MORPH_TOPHAT, mask)
cv2.imwrite('ex4_tophat.png', img4_tophat)
img4_blackhat = cv2.morphologyEx(img1, cv2.MORPH_BLACKHAT, mask)
cv2.imwrite('ex4_blackhat.png', img4_blackhat)
トップハット・ブラックハットは、例えば回路基板の写真などに含まれる埃などを見つけたり、宇宙の写真などから未発見の小惑星を見つけるのに役立ちます
(天文観測では白黒反転した写真を使うことが多いので、白背景に黒の天体が見えます)。
課題1で作成したノイズ画像を元にしてトップハット・ブラックハットを行った画像 ex4_tophat.png, ex4_blackhat.png を出力してください。
※ 画像をダウンロードしてツールで開いて拡大し、ノイズがどうなったかを確認してください。
動画の解説を参照
今回作成したノートブックを「imgprc2024@gmail.com」と共有してください。
※ 第2回で共有した、画像共有用の「画像処理」フォルダの中に「第10回」フォルダを作り、その中に今回の元画像と出力画像を入れてください。
※ 課題の再提出の際は、ノートブックの再度の共有はせずにチャットで連絡してください。