Otsu算法原理

目录

  • Otsu 算法
    • Opencv API
      • 先给出原图
      • 直接二值化
      • Otsu
    • 手动实现Otsu
  • 欢迎一起来参与leetcode刷题项目

Otsu 算法

该算法就是通过直方图的特性来自动选取阈值,尤其是有的图像的灰度直方图是双峰

Opencv API

先给出原图

Otsu算法原理_第1张图片
可以看到这不是灰度图像,所以记住,二值化必须是灰度图像。

cv.cvtColor(img_d1, cv.COLOR_BGR2GRAY)

直接二值化

# 我传入的是灰度图像
retval, dst = cv.threshold(BGR2GRAY(img_d1), 128, 255, cv.THRESH_BINARY)
plt.imshow(dst)

Otsu算法原理_第2张图片
效果并不是很好

Otsu

# 用高斯滤波是为了降噪,噪声有时候会影响直方图的结果
# 我传入的是灰度图像
blur = cv.GaussianBlur(BGR2GRAY(img_d1), (5,5), 0)
# 直接一个API调用就结束了。
ret_otsu, im_otsu = cv.threshold(blur, 0, 255, cv.THRESH_BINARY+cv.THRESH_OTSU)

plt.subplot(1,3,1), plt.imshow(BGR2GRAY(img_d1), 'gray')
plt.title('GRAY'),plt.xticks([]), plt.yticks([])

plt.subplot(1,3,2), plt.hist(BGR2GRAY(img_d1).ravel(), 256)
plt.title('Histogram'),plt.xticks([]), plt.yticks([])

plt.subplot(1,3,3), plt.imshow(im_otsu, 'gray')
plt.title('Otsu'),plt.xticks([]), plt.yticks([])

Otsu算法原理_第3张图片
党妹这张图像的直方图,分布是不特别好,但是能明显的看到有双峰

手动实现Otsu

要求你在0到255之间找一个灰度值tt将图像的直方图分成前后两部分,叫做前景和后景。
我们的目标 使得 前景和后景的方差最大,或者前景与后景各自内部的方差最小。这里用第一种 w 0 ∗ w 1 ∗ ( u 0 − u 1 ) 2 w0∗w1∗(u0−u1)^2 w0w1(u0u1)2
w0 是前景里所有像素占总像素的比例 ,u0 是前景里像素均值,w1 u1就是后景里对应的值了

def otsu_binarization(img: np.ndarray, th=128):
    max_sigma, max_t = 0, 0
    H, W = img.shape
    
    # determine threshold
    for _t in range(1, 255):
        v0 = img[np.where(img < _t)]
        u0 = np.mean(v0) if len(v0) else 0
        w0 = len(v0) / (H * W)
        v1 = img[np.where(img >= _t)]
        u1 = np.mean(v1) if len(v1) else 0
        w1 = len(v1) / (H * W)
        sigma = w0 * w1 * (u0 - u1)**2 
        if sigma > max_sigma:
            max_sigma = sigma
            max_t = _t
    
    # Binarization
    print('Threshold >>', max_t)
    th = max_t
    out = img.copy()
    out[out < th] = 0 
    out[out >= th] = 255

Otsu算法原理_第4张图片
​​

欢迎一起来参与leetcode刷题项目

刷题的GitHub: github链接.

你可能感兴趣的:(Opencv,python)