OpenCV-Python入門教程6-Otsu閾值法


在說Otsu之前,先說幾個概念

灰度直方圖:將數字圖像中的所有像素,按照灰度值的大小,統計其出現的頻率。其實就是每個值(0~255)的像素點個數統計。

Otsu算法假設這副圖片由前景色和背景色組成,通過最大類間方差選取一個閾值,將前景和背景盡可能分開。

一、代碼展示

import cv2
from matplotlib import pyplot as plt
img = cv2.imread('noisy.jpg', 0)
# 固定閾值法
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)

# Otsu閾值法
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 先進行高斯濾波,再使用Otsu閾值法
blur = cv2.GaussianBlur(img, (5, 5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
images = [img, 0, th1, img, 0, th2, blur, 0, th3]
titles = ['Original', 'Histogram', 'Global(v=100)',
         'Original', 'Histogram', "Otsu's",
         'Gaussian filtered Image', 'Histogram', "Otsu's"]

for i in range(3):
    # 繪制原圖
    plt.subplot(3, 3, i * 3 + 1)
    plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3], fontsize=8)
    plt.xticks([]), plt.yticks([])
    
    # 繪制直方圖plt.hist, ravel函數將數組降成一維
    plt.subplot(3, 3, i * 3 + 2)
    plt.hist(images[i * 3].ravel(), 256)
    plt.title(titles[i * 3 + 1], fontsize=8)
    plt.xticks([]), plt.yticks([])
    
    # 繪制閾值圖
    plt.subplot(3, 3, i * 3 + 3)
    plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

可以看出Otsu閾值明顯優於固定閾值。

 

二、Otsu算法推導

Otsu閾值法將整幅圖分為前景(目標)和背景,以下是一些符號規定:

  • T: 分割閾值
  • N0:前景像素點數
  • N1:背景像素點數
  • ω0:前景的像素點數占整幅圖像的比例
  • ω1:背景的像素點數占整幅圖像的比例
  • μ0:前景的平均像素值
  • μ1:背景的平均像素值
  • μ:整幅圖的平均像素值
  • rows * cols:圖像的行數和列數

總的像素個數:

       N0+N1=rows×cols

ω0和ω1是前景、背景所占的比例,也就是:

 

整幅圖的平均像素值就是:

我們定義一個前景μ0與背景μ1的方差g:

聯立前面幾個公式得:

g就是前景與背景兩類之間的方差,這個值越大,說明前景和背景的差別也就越大,效果越好。Otsu算法便是遍歷閾值T,使得g最大。所以又稱為最大類間方差法。基本上雙峰圖片的閾值T在兩峰之間的谷底。

參考網址:https://tianchi.aliyun.com/course/courseConsole?courseId=40992&chapterIndex=1&sectionIndex=12

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM