阈值分割算法效果测试

 

直方图阈值分割

 

一般图像都有双峰性,一个峰是前景一个是后景。

 

一般取这两个峰值之间的最小值为图片的二值化的阈值

 

从而二值化图片

 

值得一提的是,对于任何一张图像,它的直方图中如果存在较为明显的双峰,用直方图分割技术法可以达到很好的效果,否则,达到的效果会很不理想。

 

所以建议先绘制直方图看看。

 

import numpy as np
import cv2
import os


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,image_name):
    # 计算灰度直方图
    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()
    print(type(img))
    img[img > thresh] = 255.0
    img[img <= thresh] = 0.0
    cv2.imshow('deal_image', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    print(type(img))
    cv2.imwrite(image_name,img)


if __name__ == '__main__':
    for img_name in os.listdir("rect"):
        image = cv2.imread("rect/"+img_name, cv2.IMREAD_GRAYSCALE)
        threshTwoPeaks(image,"result/"+img_name)

 

如果直方图无明显双峰则分割效果明显不行

 

 

 

 

有双峰分割效果才勉强能看

 

 

 

 

自适应阈值算法

 

自适应二值化就是在单个阈值不够分割整个图片时,把整张图片分为多个小块,每块采用各自的阈值进行分割。

 

import os
import matplotlib.pyplot as plt

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__':
    for img_name in os.listdir("rect"):
        image = cv2.imread("rect/"+img_name, cv2.IMREAD_GRAYSCALE)
        img = adaptiveThresh(image, (10, 10))
        # cv2.imshow('origin', image)
        # cv2.imshow('deal_image', img)
        cv2.imwrite("result/"+img_name,img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

 

在虾分割的测试中效果明显不佳,因为虾和周围环境颜色还是较为相似的

 

滑窗大小为10x10

 

 

滑窗大小为50x50

 

 

熵算法

 

熵是用来衡量信息量多少的标准

 

熵算法取得是让前景与背景熵的和最大的阈值,因此相对而言获取到的信息也是最多的。

 

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__':
    for img_name in os.listdir("rect"):
        image = cv2.imread("rect/"+img_name, cv2.IMREAD_GRAYSCALE)
        img = threshEntroy(image)
        cv2.imshow("img",img)
        cv2.imwrite("result/"+img_name,img)

 

 

 

最终实验版本:熵算法加骨架算法

 

import os
import math
import cv2
import numpy as np

from skimage import morphology, data, color
import matplotlib.pyplot as plt

def get_skeleton(image,original_img,img_name):
    image = color.rgb2gray(image)
    print(image)
    image = 1 - image  # 反相
    # 实施骨架算法
    skeleton = morphology.skeletonize(image)

    # 显示结果
    fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))

    ax1.imshow(original_img, cmap=plt.cm.gray)
    ax1.axis('off')
    ax1.set_title('original', fontsize=20)

    ax2.imshow(skeleton, cmap=plt.cm.gray)
    ax2.axis('off')
    ax2.set_title('skeleton', fontsize=20)

    fig.tight_layout()
    plt.savefig(img_name)
    plt.show()






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] = 1
    threshold[threshold <= thresh] = 0
    return threshold


if __name__ == '__main__':
    for img_name in os.listdir("rect"):
        image = cv2.imread("rect/"+img_name, cv2.IMREAD_GRAYSCALE)
        img = threshEntroy(image)

        get_skeleton(img,image,"result/"+img_name)

 

 

 

 

效果很一般,果然还是得深度学习

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值