Python opencv画像セグメンテーションアルゴリズムの深い理解
この記事では、Python Opencvによる画像分割の実装を基に、以下のopencv関数を使用しています。
- OpenCV の関数 cv::filter2D を用いて,ラプラシアンフィルタリングを行い,画像を鮮明にします.
- OpenCV の関数 cv::distanceTransform を使って,2値画像の派生表現を得ます.ここで,各ピクセルの値は,最も近い背景ピクセルとの距離に置き換えられます.
- OpenCV の関数 cv::watershed を用いて,画像中のオブジェクトと背景を分離します.
ソース画像を読み込み、問題なく読み込まれることを確認した後、以下の場所に表示します。
# Load the image
parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\
Sample code showing how to segment overlapping objects using Laplacian filtering, \
in addition to Watershed and Distance Transformation')
parser.add_argument('--input', help='Path to input image.', default='cards.png')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Show source image
cv.imshow('Source Image', src)
オリジナル画像
背景を白から黒に変更すると、後のDistance Transformでより良い結果を引き出すことができます。
src[np.all(src == 255, axis=2)] = 0
numpy.allの使い方がよくわからない場合は、以下のサイトを参考にしてください。 ここで
その後、前景のオブジェクトのエッジを鮮明にするために、画像をシャープにします。ラプラシアンフィルター(2階微分の近似)をかなり強いフィルターでかけることにします。
# Create a kernel that we will use to sharpen our image
# An approximation to the second order derivative, a very powerful kernel
kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32)
# do the laplacian filtering as it is
# well, we need to convert everything in something more deeper then CV_8U
# because the kernel has some negative values,
# and we can expect in general to have a Laplacian image with negative values
# BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
# so the possible negative number will be truncated
imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel)
sharp = np.float32(src)
imgResult = sharp - imgLaplacian
# convert back to 8bits gray scale
imgResult = np.clip(imgResult, 0, 255)
imgResult = imgResult.astype('uint8')
imgLaplacian = np.clip(imgLaplacian, 0, 255)
imgLaplacian = np.uint8(imgLaplacian)
#cv.imshow('Laplace Filtered Image', imgLaplacian)
cv.imshow('New Sharped Image', imgResult)
シャープネス処理の主な目的は、グレースケールの過剰な部分を強調することである。ラプラスは微分演算子なので、使用する定義が負の中心係数を持つ場合、シャープ化結果を得るためには、ラプラス変換された画像に加算するのではなく、元の画像を減算する必要があります。---- デジタル画像処理(第3版)より
ここで、新たにシャープにした元画像をそれぞれグレースケールとバイナリに変換する。
# Create binary image from source image
bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY)
_, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow('Binary Image', bw)
これで、2値画像に距離変換を適用する準備が整いました。さらに、結果の可視化と閾値処理を可能にするために、出力画像を正規化します。
# Perform the distance transform algorithm
dist = cv.distanceTransform(bw, cv.DIST_L2, 3)
# Normalize the distance image for the range = {0.0, 1.0}
# so that we can visualize and threshold it
cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX)
cv.imshow('Distance Transform Image', dist)
distanceTransformの使用法
cv.distanceTransform( src, distanceType, maskSize[, dst[, dstType]] ) .
src: 入力画像.データ型は CV_8U のシングルチャンネル画像.
dst: 出力画像.入力画像と同じサイズのシングルチャンネル画像で,データ型は CV_8U または CV_32F です.
distanceType: 2つのピクセル間の距離を計算する距離法のフラグを選択し、その共通の距離メトリック、DIST_L1 (distance = |x1-x2| + |y1-y2| neighborhood distance), DIST_L2 (Euclidean distance ユークリッド距離) を選択する。
maskSize: 距離変換マスク行列のサイズ、パラメータは DIST_MASK_3 (3×3) と DIST_MASK_5 (5×5) から選択できる。
Dist画像を閾値処理し、モルフォロジー操作(インフレーション)を行い、上記画像からピークを抽出する。
# Threshold to obtain the peaks
# This will be the markers for the foreground objects
_, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY)
# Dilate a bit the dist image
kernel1 = np.ones((3,3), dtype=np.uint8)
dist = cv.dilate(dist, kernel1)
cv.imshow('Peaks', dist)
各 blob から,cv::findContours 関数を用いて,watershed アルゴリズムのための種やタグを生成します.
# Create the CV_8U version of the distance image
# It is needed for findContours()
dist_8u = dist.astype('uint8')
# Find total markers
contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# Create the marker image for the watershed algorithm
markers = np.zeros(dist.shape, dtype=np.int32)
# Draw the foreground markers
for i in range(len(contours)):
cv.drawContours(markers, contours, i, (i+1), -1)
# Draw the background marker
cv.circle(markers, (5,5), 3, (255,255,255), -1)
markers_8u = (markers * 10).astype('uint8')
cv.imshow('Markers', markers_8u)
最後に、流域アルゴリズムを適用して、その結果を次のように可視化します。
# Perform the watershed algorithm
cv.watershed(imgResult, markers)
# mark = np.zeros(markers.shape, dtype=np.uint8)
mark = markers.astype('uint8')
mark = cv.bitwise_not(mark)
# uncomment this if you want to see how the mark
# image looks like at that point
# cv.imshow('Markers_v2', mark)
# Generate random colors
colors = []
for contour in contours:
colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)))
# Create the result image
dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8)
# Fill labeled objects with random colors
for i in range(markers.shape[0]):
for j in range(markers.shape[1]):
index = markers[i,j]
if index > 0 and index <= len(contours):
dst[i,j,:] = colors[index-1]
# Visualize the final image
cv.imshow('Final Result', dst)
機械学習による画像セグメンテーション
ピクセリブ は、画像や動画中のオブジェクトをセグメンテーションするためのライブラリです。主に2種類の画像セグメンテーションをサポートしています。
1. セマンティック・セグメンテーション
2. インスタンスセグメンテーション
PixelLibは画像分割のための2つのディープラーニングライブラリ、PytorchとTensorflowをサポートしています。
上記はopencv画像分割アルゴリズムのPythonの深い理解の詳細です、Pythonの詳細については、スクリプトハウスの他の関連記事に注意を払うしてください
関連
-
Pythonの非常に便利な2つのデコレーターを解説
-
[解決済み] pygame.error: ビデオシステムが初期化されていません。
-
[解決済み] np.load()はopenと一緒にする必要があります。
-
[解決済み] 文の多クラス分類のためのBertForSequenceClassificationとBertForMultipleChoiceの比較
-
[解決済み] "通常のsite-packagesが書き込み可能ではないため、ユーザーインストールをデフォルトとする" pythonメッセージ
-
[解決済み] "'generator' object is not subscriptable "エラー
-
Pythonの各種実行時エラー(SyntaxError : invalid syntaxなど)。
-
jinja2.exceptionsでTemplateNotFoundエラーが発生しました。
-
XXX型のオブジェクトがJSONシリアライズ可能でない問題を解決する
-
python raise JSONDecodeError("Expecting value", s, err.value) from None when using json.loads
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PicgoのイメージベッドツールをPythonで実装する
-
[解決済み】PEP8のE128:ビジュアルインデントで継続行がアンダーインデントになるのは何?
-
[解決済み】Python 2: AttributeError: 'list' オブジェクトに 'strip' 属性がない。
-
Python --- AttributeError: 'NoneType' オブジェクトに 'xxxx' という属性がない問題
-
[解決済み] ImportError: Cython.Distutilsという名前のモジュールはありません。
-
[解決済み] データフレーム全体に対するpandas.factorize
-
[解決済み] Pythonでガンマ関数
-
[解決済み] spyder - メモリから変数と一緒に変数エクスプローラをクリアします。
-
python オブジェクトはアイテムの割り当てをサポートしない
-
TypeError: **またはpow()でサポートされていないオペランド型: 'str' および 'int'