设计一个基于灰度阈值分割算法的图像处理程序,实现对输入图像的分割,输出分割后的图像。
基于灰度阈值的图像分割算法是将图像中的像素分为两类,一类是大于阈值的像素,另一类是小于等于阈值的像素。通常情况下,将大于阈值的像素视为前景像素(目标物体),而将小于等于阈值的像素视为背景像素。通过这种方式,实现将图像分成目标和背景两部分的目的。
为预防使用同一阈值对灰度分布不均匀或强度不易的图像,导致分割效果不佳甚至完全失败。因此本文选择使用自适应阈值算法,而自适应阈值分割算法则是在计算局部像素灰度均值和标准差的基础上,根据像素点与周围像素的差异性确定分割阈值,利用不同小区域内的阈值进行图像分割的一种方法。因此,基于自适应阈值分割算法可以根据图像不同区域的特性,自适应地确定分割阈值,使得分割效果更加准确。
在任务中,本文使用贝叶斯优化确定最优的块大小和偏移量,以进一步优化图像分割效果。贝叶斯优化算法是针对黑盒函数的优化技术,通过迭代采样寻找最优解。在该算法中,通过选取合适的初始采样点,确定后续样本点的取样位置和取样大小,从而得到使目标定值函数最小的参数。在我们的任务中,我们使用贝叶斯优化算法确定最优的块大小和偏移量,以最大化分割后的图像方差,进一步提高分割效果。
实现:
读入原始图像,使用中值滤波降噪,并将其转化为灰度图像。
使用贝叶斯优化来寻找最优的块大小和偏移量,确定适当的块大小和偏移量(offset)。
将图像划分为若干个小块,并对每个小块进行局部均值和方差的计算。
对图像进行自适应灰度分析,使用cv2.adaptiveThreshold函数进行阈值分割,并传入最优的块大小和偏移量。
保存分割后的图像。
自适应阈值算法是一种在图像处理和计算机视觉领域广泛使用的算法。它的主要目的是将图像中不同区域的亮度计算出来,然后根据亮度来对图像进行分割和处理。该算法被广泛应用于人脸检测、背景建模等视觉任务中。
具体来说,自适应阈值算法将图像分成若干个不同大小的块,然后计算每个块中像素值的平均值,并将这个平均值设为该块的阈值。如果一个像素的亮度值大于该块的阈值,则被认为是前景区域,否则被认为是背景区域。
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
参数说明:
贝叶斯优化(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值对于结果影响的具体表现,同时也需要注意算法的效率和运行速度,尤其是对于大尺寸图像可能存在性能瓶颈。
同时该代码仍存在一些缺点,还待解决:
程序运行速度有一些慢,这可能与自适应阈值化对于每个像素点都需要进行块计算有关。
目标函数的计算只考虑了图像周围块的方差,而没有考虑到图像的形状信息和纹理特征等,可能导致参数优化结果不够准确。
算法的收敛速度和结果精度依赖于随机采样点的选择和搜索范围的设置,这需要手动进行调整,可能需要更多的经验和理论知识。
代码对于大尺寸图像可能会出现性能瓶颈,同时需要占用较大的内存空间进行运算。
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)