画像分割 --- 閾値処理に基づく基本的な手法


序文

この文書では主に、しきい値処理に基づく画像セグメンテーションのいくつかの基本的な方法を紹介します。


1. 閾値ベースの分割方法

1.1 固定閾値法 - ヒストグラム二峰性法

この方法は、画像ヒストグラムに現れる二重ピークの現象に基づいています。画像に二峰性がある場合、画像内の 2 つの異なる色または輝度領域に対応する 2 つのピークがヒストグラムに表示されます。このとき、ヒストグラム二峰性法を使用して、適切なしきい値を自動的に決定できます。基本的な考え方は次のとおりです。

  1. 画像のグレースケール ヒストグラムを計算します。
  2. ヒストグラムの2つのピークの位置に応じて、2つのピークの間の閾値が画像の閾値として計算される。
  3. 計算された閾値に従って画像が二値化され、画像が対象物と背景の 2 つの部分に分割されます。

注:この方法は、二重ピークを持つ画像にのみ適しています。単一ピークまたは目立たないピークを持つ画像の場合は、他のしきい値セグメンテーション方法を使用する必要があります。

使用cv2.threshold(src, thresh, maxval, type)函数。
ここに画像の説明を挿入

一般的に使用されるしきい値処理方法は次のとおりです。

1.THRESH_BINARY 二值阈值化
该方法将像素值与设定的阈值进行比较,若像素值大于等于阈值,则将该像素值设为最大值,否则设为0。可以用于处理灰度图像与彩色图像。

2.THRESH_BINARY_INV 反二值阈值化
该方法将像素值与设定的阈值进行比较,若像素值小于阈值,则将该像素值设为最大值,否则设为0。可以用于处理灰度图像与彩色图像。

3.THRESH_TRUNC 截断阈值化
该方法将像素值与设定的阈值进行比较,若像素值大于等于阈值,则将该像素值设为阈值,否则不更改。可以用于处理灰度图像。

4.THRESH_TOZERO 零阈值化
该方法将像素值与设定的阈值进行比较,若像素值大于等于阈值,则不更改,否则设为0。可以用于处理灰度图像。

5.THRESH_TOZERO_INV 反零阈值化
该方法将像素值与设定的阈值进行比较,若像素值小于等于阈值,则不更改,否则设为0。可以用于处理灰度图像

コード:

# 直方图双峰法
import cv2
import numpy as np
from matplotlib import pyplot as plt

# 读取图像(阈值处理方法不同)
img = cv2.imread('house.tif',0)
x,img1 = cv2.threshold(img,150,255,cv2.THRESH_BINARY)
x,img2 = cv2.threshold(img,150,255,cv2.THRESH_TRUNC)
x,img3 = cv2.threshold(img,150,255,cv2.THRESH_TOZERO)

# 显示原始图像和恢复后的图像
plt.figure(figsize=(20, 20))
plt.subplot(221), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(img1, cmap='gray')
plt.title('seg img THRESH_BINARY'), plt.xticks([]), plt.yticks([])
plt.subplot(223), plt.imshow(img2, cmap='gray')
plt.title('seg img THRESH_TRUNC'), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(img3, cmap='gray')
plt.title('seg img THRESH_TOZERO'), plt.xticks([]), plt.yticks([])
plt.show()

ここに画像の説明を挿入
このグローバル閾値処理方法の欠点は、ノイズ処理の効果が悪く、平滑化処理が必要なことである。

import cv2
import random
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('house.tif',0)

# 加上高斯噪声
noise = np.random.normal(0,100,size=img.size).reshape(img.shape[0],img.shape[1])
img1 = img + noise
img1 = np.clip(img1,0,255)


# 平滑处理
img2 = cv2.GaussianBlur(img1,(5,5),0)

# 直方图双峰法
x,img3 = cv2.threshold(img,150,255,cv2.THRESH_BINARY)
x,img4 = cv2.threshold(img1,150,255,cv2.THRESH_BINARY)
x,img5 = cv2.threshold(img2,150,255,cv2.THRESH_BINARY)

# 显示原始图像和恢复后的图像
plt.figure(figsize=(20, 20))
plt.subplot(221), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(img1, cmap='gray')
plt.title('noise img'), plt.xticks([]), plt.yticks([])
plt.subplot(223), plt.imshow(img4, cmap='gray')
plt.title('seg noise img '), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(img5, cmap='gray')
plt.title('seg blur img '), plt.xticks([]), plt.yticks([])
plt.show()

ここに画像の説明を挿入

1.2 反復閾値画像セグメンテーション

この適応型画像セグメンテーション法の主なアイデアは、画像のグレー値を反復することにより、しきい値を継続的に調整してセグメンテーションをより正確にすることです。
セグメンテーションの手順は次のとおりです。

  1. 初期しきい値をランダムに選択します (画像の平均グレー値を使用できます)
  2. しきい値に従って、画像は 2 つの部分に分割されます。しきい値以下の部分が前景、しきい値を超える部分が背景になります。
  3. 前景と背景の平均グレー値を計算します。
  4. 前景と背景の平均グレー値の平均を新しいしきい値として使用します
  5. 新しいしきい値が元のしきい値と同じ場合、セグメント化は終了します。それ以外の場合は、ステップ 2 に戻り、収束するまで反復を繰り返します。

コード:

#  迭代阈值图像分割法
import numpy as np
from PIL import Image

# 读取图像
img = Image.open('house.tif').convert('L')
width, height = img.size
pixels = img.load()

# 初始化阈值
threshold = 150
delta = 1
while delta > 0:
    # 根据阈值将图像分割
    foreground = []
    background = []
    for y in range(height):
        for x in range(width):
            if pixels[x, y] > threshold:
                background.append(pixels[x, y]) #大于阈值的部分为背景
            else:
                foreground.append(pixels[x, y]) #小于等于阈值的部分为前景
    avr_foreground = sum(foreground) // len(foreground)
    avr_background = sum(background) // len(background)
    # 更新阈值
    new_threshold = (avr_foreground + avr_background) // 2
    delta = abs(new_threshold - threshold)
    threshold = new_threshold

# 重新分割图像
for y in range(height):
    for x in range(width):
        if pixels[x, y] > threshold:
            pixels[x, y] = 255
        else:
            pixels[x, y] = 0

# 显示分割后的图像
img.show('result.jpg')

ここに画像の説明を挿入

优点:
	1.迭代阈值图像分割相对于静态阈值分割而言,具有更高的实用性和鲁棒性。
	2.该方法能够有效地应对光照变化、背景复杂多样等情况下的图像分割问题。
缺点:
	对于大尺寸图像,迭代阈值图像分割的计算速度可能成为其一个缺点。

1.3 適応閾値画像セグメンテーション

1.3.1 従来手法

セグメンテーションの手順は次のとおりです。

  1. 入力グレースケール画像の場合、 N × NN×Nのサイズを定義します。N×Nのウィンドウで、ウィンドウの中央のピクセルを処理のコア ピクセルとして選択します。
  2. ウィンドウ内のピクセル情報に従ってローカルしきい値を計算します。現在のピクセルのしきい値として、このしきい値は平均値、中央値、最頻値などの統計値にすることができます。
  3. 処理されたピクセルを現在のピクセルのローカルしきい値と比較し、しきい値以上のピクセルは白に設定され、しきい値より小さいピクセルは黒に設定され、新しい 2 値画像がセグメント化されます。
  4. ウィンドウを画像の他の領域に移動し、画像のすべての領域がバイナリ イメージにセグメント化されるまで、各領域でガウス適応しきい値セグメンテーションを実行し続けます。

コード:

# 自适应阈值图像分割
import numpy as np
from PIL import Image

# 图像预处理
img = Image.open('house.tif').convert('L')
width, height = img.size
pixels = img.load()
block_size = 11  # 设置块大小

# 分割图像并计算局部阈值
for y in range(0, height, block_size):
    for x in range(0, width, block_size):
        # 获取局部区域
        region = []
        for j in range(y, y+block_size):
            for i in range(x, x+block_size):
                if i < width and j < height:
                    region.append(pixels[i, j])
        # 计算局部区域平均值作为阈值
        threshold = sum(region) // len(region)
        # 对区域进行二值化处理
        for j in range(y, y+block_size):
            for i in range(x, x+block_size):
                if i < width and j < height:
                    if pixels[i, j] > threshold:
                        pixels[i, j] = 255
                    else:
                        pixels[i, j] = 0

#显示分割后的图像
img.show('result.jpg')

ここに画像の説明を挿入

cv2.adaptiveThreshold()関数実装を直接呼び出すこともできます。

import cv2
# 读取原始图像
img = cv2.imread('house.tif', 0)
# 自适应阈值分割
img_thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
# 显示结果
cv2.imshow('Original Image', img)
cv2.imshow('Adaptive Thresholding', img_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

ここに画像の説明を挿入

1.3.2 大津法(OTSU)

大津法基于以下观察结果:
当图像被分为多个区域时,如果区域内的像素值差异较小,区域的均值方差就会较小。
而当区域内像素值差异较大时,区域的均值方差就会较大。
因此,局部图像的全局最佳阈值是能使类间方差最大的那个灰度级。

手順:
ここに画像の説明を挿入
コード:

import cv2

# 读取图片
img = cv2.imread('house.tif', 0)

# 大津法阈值分割
ret, img_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 显示结果
cv2.imshow('Original Image', img)
cv2.imshow('OTSU Thresholding', img_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

ここに画像の説明を挿入

优点:
	多种检测任务效果较好。
缺点:
	计算量比较大,适用于数据量较小的图像分割场合。

参考文献:

[1] Ruan Qiuqi、Ruan Yuzhi 訳、(米国) Raphael C. Gonzalez、Richard E. Woods、デジタル画像処理、外国の電子書籍およびコミュニケーション教科書シリーズ第 4 版 [M]、北京: Electronic Industry Press、2020

おすすめ

転載: blog.csdn.net/m0_46366547/article/details/129979318