Opencv之Otsu阈值处理(Python)

学习资料参考:

张平.《OpenCV算法精解:基于Python与C++》.[Z].北京.电子工业出版社.2017.


前言

在对图像进行阈值分割之时,所选取的分割阈值应使前景区域的平均灰度、背景区域的平均灰度与整幅图像的平均灰度之间的差异最大,这种差异用区域的方差来表示。


原理详解

假设输入图像为 I I I,高为 H H H、宽为 W W W, h i s t o g r a m I histogram_I histogramI代表归一化的图像的灰度直方图, h i s t o g r a m I ( k ) histogram_I(k) histogramI(k)代表灰度值等于 k k k的像素点个数在图像中所占的比率,其中k在0到255的范围。


实现步骤

  1. 计算灰度直方图的累加直方图
    在这里插入图片描述
    假设阈值为k,那么zeroCumuMomnet[k]就表示0k的的整体概率,而剩下k + 1255表示另一类的整体概率。

  2. 计算灰度直方图的一阶累积距
    在这里插入图片描述
    同理,假设阈值为k,那么oneCumuMomnet[k]表示0k的平均像素值,另一类的平均像素值就可表示为从i = k + 1到255的求和值。

  3. 计算图像 I I I总体的灰度平均值mean
    在这里插入图片描述

  4. 将每一个灰度级作为阈值时,前景区域的平均灰度、背景区域的平均灰度与整幅图像的平均灰度的方差。
    在这里插入图片描述
    上述表达式的成立需要明白下列两个公式:
    ``在这里插入图片描述
    第一个表达式左侧表示在第一类的像素平均值+第二类的像素平均值,右侧是整体的平均像素值。
    第二个表达式表示属于两类的概率总和为1。
    然后就可推算得到第一个最上面的求解方差的表达式。

  5. 找到最大的方差,其中该方差对应的k就是Otsu选取的阈值。
    在这里插入图片描述
    求解在第四步中的最大方差值,作为阈值。


Python实现

import numpy as np
import cv2
import math

image = cv2.imread(r"C:\Users\1\Pictures\test.jpg", 0)
rows, cols = image.shape[:2]
gray_hist = np.zeros([256], np.uint64)
for i in range(rows):
    for j in range(cols):
        gray_hist[image[i][j]] += 1
uniformGrayHist = gray_hist / float(rows * cols)
# 计算零阶累积距和一阶累积距
zeroCumuMomnet = np.zeros(256, np.float32)
oneCumuMomnet = np.zeros(256, np.float32)
for k in range(256):
    if k == 0:
        zeroCumuMomnet[k] = uniformGrayHist[0]
        oneCumuMomnet[k] = (k) * uniformGrayHist[0]
    else:
        zeroCumuMomnet[k] = zeroCumuMomnet[k - 1] + uniformGrayHist[k]
        oneCumuMomnet[k] = oneCumuMomnet[k - 1] + k * uniformGrayHist[k]
# 计算类间方差
variance = np.zeros(256, np.float32)
for k in range(255):
    if zeroCumuMomnet[k] == 0 or zeroCumuMomnet[k] == 1:
        variance[k] = 0
    else:
        variance[k] = math.pow(oneCumuMomnet[255] * zeroCumuMomnet[k] - oneCumuMomnet[k], 2) / (
                    zeroCumuMomnet[k] * (1.0 - zeroCumuMomnet[k]))
# 找到阈值
threshLoc = np.where(variance[0:255] == np.max(variance[0:255]))
thresh = threshLoc[0][0]
# 阈值处理
threshold = np.copy(image)
threshold[threshold > thresh] = 255
threshold[threshold <= thresh] = 0
cv2.imshow("test", threshold)
cv2.waitKey(0)


运行结果
原图
在这里插入图片描述

处理后的图像
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44116998/article/details/124645657