opencv 大津算法讲解与实现

大津算法原理

在 opencv 中对图像进行二值化的过程中我们可能会使用大津算法,大津算法的主要作用是分割前景与背景部分区域,先将图像灰度化,假设图像有 [0,255] 个灰度等级,在数学中有方差这个概念,如果两个事物之间的方差越大,则他们的关联性则越小,在图像中计算前景与背景间的类间方差,方差越大,越能认为两部分关联性越小,即前景与背景区域,所以大津算法即寻找使背景与前景方差最大的阈值

有如下假设:

W0:背景像素点占整幅图像的比例
U0: 背景像素点的平均灰度
W1:前景像素点占整幅图像的比例
U1: 前景像素点的平均灰度
U: 整幅图像的平均灰度
g: 类间方差

有如下关系:

U = W0U0 + W1U1 --------------------------------- (1)
g = W1 ( U - U1)2 + W0 ( U - U0 )2-------------- (2)

将(2) 代入 (1) 有:

g=W0 W1 ( U0 - U1 )2

实现过程

循环遍历阈值 [0,255] 获取最大类间方差

import numpy as np
import cv2
import matplotlib.pyplot  as plt

def otsuCompute(grayImg):
    # 类间方差
    g = 0
    # 遍历矩阵
    for i in range(0,256):
        # 背景像素点占整幅图像的比例

        W0 = 0.0
        w0 = 0
        # 背景图像平均灰度
        U0 = 0
        u0 = 0.0
        # 前景图像占整幅图像的比例
        W1 = 0.0
        w1 = 0
        # 前景图像的平均灰度
        U1 = 0
        u1 = 0.0


        for element in grayImg.flat:

            # 大于i为前景
            if element>i:
                w1+=1
                u1+=element
            else:
                w0+=1
                u0+=element
        try:
            W0 = w0/(w0+w1)
            W1 = 1 - W0
            U0 = u0/w0
            U1 = u1/w1

            if W1*W0*((U0 - U1)**2) > g:
                g=W1*W0*((U0 - U1)**2)
                thres=i
        except:
            pass
    return  thres

img=cv2.imread('img/water_coins.jpg',cv2.IMREAD_UNCHANGED)
grayImg=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# cv2.medianBlur(grayImg,5,grayImg)
# 大津算法二值化分割前景和背景
ret,thresOtsu=cv2.threshold(grayImg,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)
ret1,thresMyOtsu=cv2.threshold(grayImg,otsuCompute(grayImg),255,cv2.THRESH_BINARY_INV)



print('Otsu threshold is {0}'.format(ret))
print('my Otsu threshold is {0}'.format(ret1))
cv2.imshow('src',img)
cv2.imshow('Otsu',thresOtsu)
cv2.imshow('my Otsu',thresMyOtsu)
cv2.waitKey()
cv2.destroyAllWindows()

结果如下:
opencv 大津算法讲解与实现_第1张图片
在这里插入图片描述
可以看到与原生大津算法效果是相同的

你可能感兴趣的:(机器视觉)