基于灰度阈值的图像分割

一、设计题目

        设计一个基于灰度阈值分割算法的图像处理程序,实现对输入图像的分割,输出分割后的图像。

二、分析

        基于灰度阈值的图像分割算法是将图像中的像素分为两类,一类是大于阈值的像素,另一类是小于等于阈值的像素。通常情况下,将大于阈值的像素视为前景像素(目标物体),而将小于等于阈值的像素视为背景像素。通过这种方式,实现将图像分成目标和背景两部分的目的。

三、设计实现

        为预防使用同一阈值对灰度分布不均匀或强度不易的图像,导致分割效果不佳甚至完全失败。因此本文选择使用自适应阈值算法,而自适应阈值分割算法则是在计算局部像素灰度均值和标准差的基础上,根据像素点与周围像素的差异性确定分割阈值,利用不同小区域内的阈值进行图像分割的一种方法。因此,基于自适应阈值分割算法可以根据图像不同区域的特性,自适应地确定分割阈值,使得分割效果更加准确。

        在任务中,本文使用贝叶斯优化确定最优的块大小和偏移量,以进一步优化图像分割效果。贝叶斯优化算法是针对黑盒函数的优化技术,通过迭代采样寻找最优解。在该算法中,通过选取合适的初始采样点,确定后续样本点的取样位置和取样大小,从而得到使目标定值函数最小的参数。在我们的任务中,我们使用贝叶斯优化算法确定最优的块大小和偏移量,以最大化分割后的图像方差,进一步提高分割效果。

实现:

  1. 读入原始图像,使用中值滤波降噪,并将其转化为灰度图像。

  2. 使用贝叶斯优化来寻找最优的块大小和偏移量,确定适当的块大小和偏移量(offset)。

  3. 将图像划分为若干个小块,并对每个小块进行局部均值和方差的计算。

  4. 对图像进行自适应灰度分析,使用cv2.adaptiveThreshold函数进行阈值分割,并传入最优的块大小和偏移量。

  5. 保存分割后的图像。

四、预备知识

自适应阈值分割算法

        自适应阈值算法是一种在图像处理和计算机视觉领域广泛使用的算法。它的主要目的是将图像中不同区域的亮度计算出来,然后根据亮度来对图像进行分割和处理。该算法被广泛应用于人脸检测、背景建模等视觉任务中。

        具体来说,自适应阈值算法将图像分成若干个不同大小的块,然后计算每个块中像素值的平均值,并将这个平均值设为该块的阈值。如果一个像素的亮度值大于该块的阈值,则被认为是前景区域,否则被认为是背景区域。

cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)

 参数说明:

  • src:输入的灰度图像
  • maxValue:阈值的最大值,如果adaptiveMethod为cv2.ADAPTIVE_THRESH_MEAN_C,则指定为255,如果为cv2.ADAPTIVE_THRESH_GAUSSIAN_C,则指定为任何大于0的值即可。
  • adaptiveMethod:自适应阈值算法类型,可以为cv2.ADAPTIVE_THRESH_MEAN_C或者cv2.ADAPTIVE_THRESH_GAUSSIAN_C。
  • thresholdType:阈值类型,可以为cv2.THRESH_BINARY或者cv2.THRESH_BINARY_INV。
  • blockSize:块大小,这个值越大,图像越分块越粗略,计算速度也会相应变快。通常情况下,块大小应该为奇数。
  • C:从均值或高斯加权与T值相差C的情况下,是向高于T的方向移动还是向低于T的方向移动的参数,常见使用0。

贝叶斯优化

        贝叶斯优化(Bayesian Optimization)是一种黑盒优化技术,它是基于贝叶斯定理及高斯过程的概率模型优化方法。它可以在有限次数的函数值查询中,高效地寻找出全局最大值或最小值,因此被广泛应用于机器学习模型优化的领域中。

        贝叶斯优化的基本思想是在搜寻参数空间时,根据先前的观测结果建立响应函数模型,然后使用响应函数模型指导搜索。具体来说,它首先根据已知的参数-函数值数据点,构建高斯过程回归模型(Gaussian Process Regression Model),使用这个模型计算期望收益和方差,期望收益最大的点作为优化的下一步。在这个过程中,高斯过程回归模型不断进行迭代,以更新响应函数模型。

数据集介绍

CBSD68:数字图像常用数据集,68张彩色图,大小不一

部分数据截图:

论文出处:

Authors: D. Martin and C. Fowlkes and D. Tal and J. Malik

Title: A Database of Human Segmented Natural Images and its Application to Evaluating Segmentation Algorithms and Measuring Ecological Statistics

Book Title: Proc. 8th Int'l Conf. Computer Vision Year: 2001 Month: July Volume: 2 Pages: 416--423

五、调试优化

对自适应阈值分割算法

        对于自适应阈值化算法,块大小(blockSize)和C值的组合可以影响到算法所得到的二值图像的质量。对于自适应阈值化算法,块大小(blockSize)和C值的组合可以影响到算法所得到的二值图像的质量。如果调整不当或使用不合理的超参数,将会导致图像被不正确地分割,即存在过剩或遗漏的噪音,这将对下游的图像处理和计算产生负面影响,从而影响最终结果的准确性。

        本文使用了贝叶斯优化方法,通过最大化目标函数,求解出块大小(block_size)和C值,从而得到更好的图像分割效果。代码中的目标函数threshold_func(),通过计算每个像素的周围块的方差,表示自适应阈值化所得到的二值图像的质量。优化过程中,通过不断地采样、计算和评估,来寻找目标函数的极值点,最终得到最佳的块大小和C值,使分割效果更加准确。

# 定义目标函数
def threshold_func(img, block_size, C):
    if block_size % 2 == 0:
        return 0.0
    if block_size < img.shape[0] and block_size < img.shape[1]:
        # 中值滤波
        img = cv2.medianBlur(img,5)
        adaptive_threshold = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, block_size, C)
        pix_var = np.var(adaptive_threshold)
        return pix_var
    else:
        return 0.0

# 将贝叶斯优化器封装为一个函数
def bayesian_optimization(img):
    # 定义参数搜索范围
    pbounds = {'block_size': (5, 100), 'C': (-20, 20)}

    # 定义贝叶斯优化器
    optimizer = BayesianOptimization(
        f=lambda block_size, C: threshold_func(img=img, block_size=int(block_size), C=int(C)),
        pbounds=pbounds,
        random_state=1,
    )

    # 进行优化
    optimizer.maximize(
        init_points=10, # 初始采样点数量
        n_iter=30, # 迭代次数
    )

    # 获取最佳参数
    best_params = optimizer.max['params']
    max_var_block_size = int(best_params['block_size'])
    max_var_c = int(best_params['C'])
    max_var = optimizer.max['target']

    return max_var_block_size, max_var_c,max_var

每张图片对应的最优块大小与偏移量(部分)

item 最优块大小 最优偏移量 方差
101085.png 71 2 16228.5198
101087.png 51 0 16240.8711
102061.png 71 1 16251.2531
103070.png 71 2 16244.9821
105025.png 51 0 16197.9176
106024.png 73 -3 16250.1578
…… …… …… ……
33039.png 51 -1 16063.9053
351093.png 73 -3 15648.1331

六、运行结果

        将获取的最佳块大小和C值,用于进行自适应阈值分割,即调用cv2.adaptiveThreshold()函数进行图像分割,得到分割图片保存在本地文件夹下。

代码如下:

input_folder = '路径'
output_folder = '路径'

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# 遍历文件夹

for root, dirs, files in os.walk(input_folder):
    saved_images = []
    for file in files:
        if file.endswith('.png'):
            # 读取图像
            img_path = os.path.join(root, file)
            img = cv2.imread(img_path, 0)

            # 进行贝叶斯优化
            best_block_size, best_c, best_var = bayesian_optimization(img)
            print(f"图片文件名:{file} 最优块大小:{best_block_size} 最优偏移量:{best_c} 方差:{best_var}")

            # 判断当前灰度图像是否已经保存过,如果保存过则跳过当前循环
            if best_var in saved_images:
                continue

            # 对图像进行自适应灰度分析
            adaptive_threshold_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, best_block_size, best_c)

            # 保存结果
            save_path = os.path.join(output_folder, f'{file[:-4]}_{best_block_size}_{best_c}.png')
            cv2.imwrite(save_path, adaptive_threshold_img)

            # 将当前灰度图像保存到已保存的列表中
            saved_images.append(best_var)

部分灰度图:

七、设计心得与体会

        自适应阈值分割算法可以有效的去除图像中的噪声和背景干扰,对于图像分析和处理都具有非常重要的作用。这个算法的优点是简单易懂,易于实现,原理比较直观,代码实现也相对易于掌握和理解。在实现过程中,需要考虑块大小和C值对于结果影响的具体表现,同时也需要注意算法的效率和运行速度,尤其是对于大尺寸图像可能存在性能瓶颈。

同时该代码仍存在一些缺点,还待解决:

  1. 程序运行速度有一些慢,这可能与自适应阈值化对于每个像素点都需要进行块计算有关。

  2. 目标函数的计算只考虑了图像周围块的方差,而没有考虑到图像的形状信息和纹理特征等,可能导致参数优化结果不够准确。

  3. 算法的收敛速度和结果精度依赖于随机采样点的选择和搜索范围的设置,这需要手动进行调整,可能需要更多的经验和理论知识。

  4. 代码对于大尺寸图像可能会出现性能瓶颈,同时需要占用较大的内存空间进行运算。

八、完整代码

import os
import cv2
import numpy as np
from bayes_opt import BayesianOptimization
# 
# 定义目标函数
def threshold_func(img, block_size, C):
    if block_size % 2 == 0:
        return 0.0
    if block_size < img.shape[0] and block_size < img.shape[1]:
        # 中值滤波
        img = cv2.medianBlur(img,5)
        adaptive_threshold = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, block_size, C)
        pix_var = np.var(adaptive_threshold)
        return pix_var
    else:
        return 0.0

# 将贝叶斯优化器封装为一个函数
def bayesian_optimization(img):
    # 定义参数搜索范围
    pbounds = {'block_size': (5, 100), 'C': (-20, 20)}

    # 定义贝叶斯优化器
    optimizer = BayesianOptimization(
        f=lambda block_size, C: threshold_func(img=img, block_size=int(block_size), C=int(C)),
        pbounds=pbounds,
        random_state=1,
    )

    # 进行优化
    optimizer.maximize(
        init_points=10, # 初始采样点数量
        n_iter=30, # 迭代次数
    )

    # 获取最佳参数
    best_params = optimizer.max['params']
    max_var_block_size = int(best_params['block_size'])
    max_var_c = int(best_params['C'])
    max_var = optimizer.max['target']

    return max_var_block_size, max_var_c,max_var

input_folder = ''
output_folder = ''

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# 遍历文件夹

for root, dirs, files in os.walk(input_folder):
    saved_images = []
    for file in files:
        if file.endswith('.png'):
            # 读取图像
            img_path = os.path.join(root, file)
            img = cv2.imread(img_path, 0)

            # 进行贝叶斯优化
            best_block_size, best_c, best_var = bayesian_optimization(img)
            print(f"图片文件名:{file} 最优块大小:{best_block_size} 最优偏移量:{best_c} 方差:{best_var}")

            # 判断当前灰度图像是否已经保存过,如果保存过则跳过当前循环
            if best_var in saved_images:
                print('当前灰度图像已经保存过,跳过当前循环')
                continue

            # 对图像进行自适应灰度分析
            adaptive_threshold_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, best_block_size, best_c)

            # 保存结果
            save_path = os.path.join(output_folder, f'{file[:-4]}_{best_block_size}_{best_c}.png')
            cv2.imwrite(save_path, adaptive_threshold_img)

            # 将当前灰度图像保存到已保存的列表中
            saved_images.append(best_var)

你可能感兴趣的:(计算机视觉,图像处理,python)