固定阈值法------直方图双峰法
手动设定一个全局阈值 T。 简单、速度快。
缺点:对光照不均、对比度变化敏感。
python
img_ori = cv2.imread('./test/test_img.jpg', 0)
width, height = img_ori.shape
cv2.imshow('img', img_ori)
''' 直方图双峰法 '''
img = copy.deepcopy(img_ori)
x, img1 = cv2.threshold(img_ori, 150, 255, cv2.THRESH_BINARY)
x, img2 = cv2.threshold(img_ori, 150, 255, cv2.THRESH_TRUNC)
x, img3 = cv2.threshold(img_ori, 150, 255, cv2.THRESH_TOZERO)
cv2.imshow('BINARY', img1)
cv2.imshow('TRUNC', img2)
cv2.imshow('TOZERO', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
迭代阈值图像分割
通过对图像的灰度值进行迭代,不断调整阈值使得分割更加准确。
对于大尺寸图像,迭代阈值图像分割的计算速度可能成为其一个缺点。
python
img = copy.deepcopy(img_ori)
threshold = 150
delta = 1
while delta > 0:
foreground = []
background = []
for y in range(height):
for x in range(width):
if img[x, y] > threshold:
background.append(img[x, y])
else:
foreground.append(img[x, y])
avr_foreground = np.mean(foreground)
avr_background = np.mean(background)
new_threshold = (avr_foreground + avr_background) // 2
delta = abs(new_threshold - threshold)
print('delta', delta)
threshold = new_threshold
for y in range(height):
for x in range(width):
if img[x, y] > threshold:
img[x, y] = 255
else:
img[x, y] = 0
cv2.imshow('iter result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
自适应阈值图像分割
根据像素邻域的灰度分布(如均值、高斯加权和)动态计算阈值。 能处理光照不均或渐变图像。
缺点:速度较慢,可能有"块效应"。
python
img = copy.deepcopy(img_ori)
block_size = 3
img_thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('adapt result', img_thresh)
大津法(OTSU)
自动寻找使类间方差最大的阈值。 全自动,对双峰直方图效果极佳。
缺点:对非双峰直方图或噪声敏感。
python
img = copy.deepcopy(img_ori)
ret, img_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow('OTSU result', img_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
全部代码
python
import cv2
import numpy as np
import copy
img_ori = cv2.imread('./test/test_img.jpg', 0)
width, height = img_ori.shape
''' 直方图双峰法 '''
img = copy.deepcopy(img_ori)
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)
cv2.imshow('img', img_ori)
cv2.imshow('BINARY', img1)
cv2.imshow('TRUNC', img2)
cv2.imshow('TOZERO', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
''' 迭代阈值图像分割 '''
img = copy.deepcopy(img_ori)
threshold = 150
delta = 1
while delta > 0:
foreground = []
background = []
for y in range(height):
for x in range(width):
if img[x, y] > threshold:
background.append(img[x, y])
else:
foreground.append(img[x, y])
avr_foreground = np.mean(foreground)
avr_background = np.mean(background)
new_threshold = (avr_foreground + avr_background) // 2
delta = abs(new_threshold - threshold)
print('delta', delta)
threshold = new_threshold
for y in range(height):
for x in range(width):
if img[x, y] > threshold:
img[x, y] = 255
else:
img[x, y] = 0
cv2.imshow('img', img_ori)
cv2.imshow('iter result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
''' 自适应阈值图像分割 '''
img = copy.deepcopy(img_ori)
block_size = 3
img_thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('img', img_ori)
cv2.imshow('adapt result', img_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
''' 大津法(OTSU) '''
# 大津法阈值分割
img = copy.deepcopy(img_ori)
ret, img_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow('img', img_ori)
cv2.imshow('OTSU result', img_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()