【6】python-opencv3教程:阈值分割(全阈值分割,局部阈值分割,直方图技术法,熵算法,自适应算法,Otsu算法)
第六节:阈值分割
一: 全阈值分割
实例代码:
image = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)
the = 100 # 设置阈值为100
maxval = 255
dst, img = cv2.threshold(image, the, maxval, cv2.THRESH_BINARY)
cv2.imshow('hand_thresh', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
给出你的阈值 ,然后告诉你的最大阈值是多少 。。。也就是你二值图中一个阈值为0,另外一个阈值可以指定为多少。。这里指定为255
看一下输出结果。。
二:局部阈值分割
局部阈值分割的核心是计算阈值矩阵。。比较常用的是后面提到的自适应阈值算法。。我们等会后面讲实现。。
三:直方图技术法
代码实现:
import numpy as np
import cv2
def calcGrayHist(image):
'''
统计像素值
:param image:
:return:
'''
# 灰度图像的高,宽
rows, cols = image.shape
# 存储灰度直方图
grayHist = np.zeros([256], np.uint64)
for r in range(rows):
for c in range(cols):
grayHist[image[r][c]] += 1
return grayHist
def threshTwoPeaks(image):
# 计算灰度直方图
histogram = calcGrayHist(image)
# 找到灰度直方图的最大峰值对应的灰度值
maxLoc = np.where(histogram == np.max(histogram))
firstPeak = maxLoc[0][0]
# 寻找灰度直方图的第二个峰值对应的灰度值
measureDists = np.zeros([256], np.float32)
for k in range(256):
measureDists[k] = pow(k - firstPeak, 2)*histogram[k]
maxLoc2 = np.where(measureDists == np.max(measureDists))
secondPeak = maxLoc2[0][0]
# 找两个峰值之间的最小值对应的灰度值,作为阈值
thresh = 0
if firstPeak > secondPeak:
temp = histogram[int(secondPeak): int(firstPeak)]
minLoc = np.where(temp == np.min(temp))
thresh = secondPeak + minLoc[0][0] + 1
else:
temp = histogram[int(firstPeak): int(secondPeak)]
minLoc = np.where(temp == np.min(temp))
thresh = firstPeak + minLoc[0][0] + 1
# 找到阈值,我们进行处理
img = image.copy()
img[img > thresh] = 255
img[img <= thresh] = 0
cv2.imshow('deal_image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
image = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)
threshTwoPeaks(image)
输出结果:
四:熵算法
代码实现:
import numpy as np
import cv2
import math
def calcGrayHist(image):
'''
统计像素值
:param image:
:return:
'''
# 灰度图像的高,宽
rows, cols = image.shape
# 存储灰度直方图
grayHist = np.zeros([256], np.uint64)
for r in range(rows):
for c in range(cols):
grayHist[image[r][c]] += 1
return grayHist
def threshEntroy(image):
rows, cols = image.shape
# 求灰度直方图
grayHist = calcGrayHist(image)
# 归一化灰度直方图,即概率直方图
normGrayHist = grayHist / float(rows*cols)
# 第一步:计算累加直方图,也称零阶累积矩
zeroCumuMoment = np.zeros([256], np.float32)
for k in range(256):
if k == 0:
zeroCumuMoment[k] = normGrayHist[k]
else:
zeroCumuMoment[k] = zeroCumuMoment[k-1] + normGrayHist[k]
# 第二步:计算各个灰度级的熵
entropy = np.zeros([256], np.float32)
for k in range(256):
if k == 0:
if normGrayHist[k] == 0:
entropy[k] = 0
else:
entropy[k] = -normGrayHist[k]*math.log10(normGrayHist[k])
else:
if normGrayHist[k] == 0:
entropy[k] = entropy[k-1]
else:
entropy[k] = entropy[k-1] - normGrayHist[k]*math.log10(normGrayHist[k])
# 第三步:找阈值
fT = np.zeros([256], np.float32)
ft1, ft2 = 0.0, 0.0
totalEntropy = entropy[255]
for k in range(255):
# 找最大值
maxFront = np.max(normGrayHist[0: k+1])
maxBack = np.max(normGrayHist[k+1: 256])
if (maxFront == 0 or zeroCumuMoment[k] == 0
or maxFront == 1 or zeroCumuMoment[k] == 1 or totalEntropy == 0):
ft1 = 0
else:
ft1 = entropy[k] / totalEntropy*(math.log10(zeroCumuMoment[k])/math.log10(maxFront))
if (maxBack == 0 or 1-zeroCumuMoment[k] == 0
or maxBack == 1 or 1-zeroCumuMoment[k] == 1):
ft2 = 0
else:
if totalEntropy == 0:
ft2 = (math.log10(1-zeroCumuMoment[k]) / math.log10(maxBack))
else:
ft2 = (1-entropy[k]/totalEntropy)*(math.log10(1-zeroCumuMoment[k])/math.log10(maxBack))
fT[k] = ft1 + ft2
# 找最大值的索引,作为得到的阈值
threshLoc = np.where(fT == np.max(fT))
thresh = threshLoc[0][0]
# 阈值处理
threshold = np.copy(image)
threshold[threshold > thresh] = 255
threshold[threshold <= thresh] = 0
return threshold
if __name__ == '__main__':
image = cv2.imread('img5.jpg', cv2.IMREAD_GRAYSCALE)
img = threshEntroy(image)
cv2.imshow('origin', image)
cv2.imshow('deal_image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
五:Otsu算法
这里就不具体实现了。。我们调用opencv给的API
image = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)
maxval = 255
otsuThe = 0
otsuThe, dst_Otsu = cv2.threshold(image, otsuThe, maxval, cv2.THRESH_OTSU)
cv2.imshow('Otsu', dst_Otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
六:自适应阈值算法
代码实现:
import cv2
import numpy as np
def adaptiveThresh(I, winSize, ratio=0.15):
# 第一步:对图像矩阵进行均值平滑
I_mean = cv2.boxFilter(I, cv2.CV_32FC1, winSize)
# 第二步:原图像矩阵与平滑结果做差
out = I - (1.0 - ratio) * I_mean
# 第三步:当差值大于或等于0时,输出值为255;反之,输出值为0
out[out >= 0] = 255
out[out < 0] = 0
out = out.astype(np.uint8)
return out
if __name__ == '__main__':
image = cv2.imread('img7.jpg', cv2.IMREAD_GRAYSCALE)
img = adaptiveThresh(image, (5, 5))
cv2.imshow('origin', image)
cv2.imshow('deal_image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示: