第六节:阈值分割

一: 全阈值分割

 实例代码:

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()

结果展示:
 

 

      未完待续。。。。。。

                                      下节你将能够学到一些形态学处理(腐蚀,膨胀等等)