浅谈图像分割基于阈值处理的基本方法

机器视觉

14人已加入

描述

本文主要介绍图像分割基于阈值处理的一些基本方法。

一、基于阈值的分割方法

1.1 固定阈值法——直方图双峰法

该方法基于图像直方图上出现的双峰现象。当一个图像有双峰现象时,其直方图会出现两个峰,分别对应图像中两种不同的颜色或亮度区域。这时我们可以使用直方图双峰法来自动确定合适的阈值。

其基本思路如下:

1. 计算图像的灰度直方图。

2. 根据直方图的两个峰的位置,计算出两个峰之间的阈值,作为图像的阈值。

3. 根据计算出的阈值对图像进行二值化处理,将图像分成目标和背景两个部分。

注意:该方法只适用于存在双峰现象的图像,对于单峰或峰不明显的图像,则需要使用其他的阈值分割方法。

使用cv2.threshold(src, thresh, maxval, type)函数

像素

常用的阈值处理方法有:

1.THRESH_BINARY 二值阈值化该方法将像素值与设定的阈值进行比较,若像素值大于等于阈值,则将该像素值设为最大值,否则设为0。可以用于处理灰度图像与彩色图像。

2.THRESH_BINARY_INV 反二值阈值化该方法将像素值与设定的阈值进行比较,若像素值小于阈值,则将该像素值设为最大值,否则设为0。可以用于处理灰度图像与彩色图像。

3.THRESH_TRUNC 截断阈值化该方法将像素值与设定的阈值进行比较,若像素值大于等于阈值,则将该像素值设为阈值,否则不更改。可以用于处理灰度图像。

4.THRESH_TOZERO 零阈值化该方法将像素值与设定的阈值进行比较,若像素值大于等于阈值,则不更改,否则设为0。可以用于处理灰度图像。

5.THRESH_TOZERO_INV 反零阈值化该方法将像素值与设定的阈值进行比较,若像素值小于等于阈值,则不更改,否则设为0。可以用于处理灰度图像

代码:

# 直方图双峰法import cv2import numpy as npfrom matplotlib import pyplot as plt

# 读取图像(阈值处理方法不同)img = cv2.imread('house.tif',0)x,img1 = cv2.threshold(img,150,255,cv2.THRESH_BINARY)x,img2 = cv2.threshold(img,150,255,cv2.THRESH_TRUNC)x,img3 = cv2.threshold(img,150,255,cv2.THRESH_TOZERO)

# 显示原始图像和恢复后的图像plt.figure(figsize=(20, 20))plt.subplot(221), plt.imshow(img, cmap='gray')plt.title('Input Image'), plt.xticks([]), plt.yticks([])plt.subplot(222), plt.imshow(img1, cmap='gray')plt.title('seg img THRESH_BINARY'), plt.xticks([]), plt.yticks([])plt.subplot(223), plt.imshow(img2, cmap='gray')plt.title('seg img THRESH_TRUNC'), plt.xticks([]), plt.yticks([])plt.subplot(224), plt.imshow(img3, cmap='gray')plt.title('seg img THRESH_TOZERO'), plt.xticks([]), plt.yticks([])plt.show()

像素

这种全局阈值处理方法缺点是对噪声的处理的效果并不好,需要进行平滑处理。

import cv2import randomimport numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('house.tif',0)

# 加上高斯噪声noise = np.random.normal(0,100,size=img.size).reshape(img.shape[0],img.shape[1])img1 = img + noiseimg1 = np.clip(img1,0,255)

# 平滑处理img2 = cv2.GaussianBlur(img1,(5,5),0)

# 直方图双峰法x,img3 = cv2.threshold(img,150,255,cv2.THRESH_BINARY)x,img4 = cv2.threshold(img1,150,255,cv2.THRESH_BINARY)x,img5 = cv2.threshold(img2,150,255,cv2.THRESH_BINARY)

# 显示原始图像和恢复后的图像plt.figure(figsize=(20, 20))plt.subplot(221), plt.imshow(img, cmap='gray')plt.title('Input Image'), plt.xticks([]), plt.yticks([])plt.subplot(222), plt.imshow(img1, cmap='gray')plt.title('noise img'), plt.xticks([]), plt.yticks([])plt.subplot(223), plt.imshow(img4, cmap='gray')plt.title('seg noise img '), plt.xticks([]), plt.yticks([])plt.subplot(224), plt.imshow(img5, cmap='gray')plt.title('seg blur img '), plt.xticks([]), plt.yticks([])plt.show()

像素

1.2 迭代阈值图像分割

这一种自适应的图像分割方法,其主要思想是通过对图像的灰度值进行迭代,不断调整阈值使得分割更加准确。

分割步骤如下:

1. 随机选取一个初始阈值(可以是图像的平均灰度值)

2. 根据该阈值将图像分割成两部分:小于等于阈值的部分为前景,大于阈值的部分为背景

3. 计算前景和背景的平均灰度值

4. 将前景和背景的平均灰度值的平均值作为新的阈值

5. 如果新的阈值和原来的阈值相同,则分割结束。否则,回到第2步,重复迭代直到收敛

代码:

#  迭代阈值图像分割法import numpy as npfrom PIL import Image

# 读取图像img = Image.open('house.tif').convert('L')width, height = img.sizepixels = img.load()

# 初始化阈值threshold = 150delta = 1while delta > 0:    # 根据阈值将图像分割    foreground = []    background = []    for y in range(height):        for x in range(width):            if pixels[x, y] > threshold:                background.append(pixels[x, y]) #大于阈值的部分为背景            else:                foreground.append(pixels[x, y]) #小于等于阈值的部分为前景    avr_foreground = sum(foreground) // len(foreground)    avr_background = sum(background) // len(background)    # 更新阈值    new_threshold = (avr_foreground + avr_background) // 2    delta = abs(new_threshold - threshold)    threshold = new_threshold

# 重新分割图像for y in range(height):    for x in range(width):        if pixels[x, y] > threshold:            pixels[x, y] = 255        else:            pixels[x, y] = 0

# 显示分割后的图像img.show('result.jpg')

像素

优点:  1.迭代阈值图像分割相对于静态阈值分割而言,具有更高的实用性和鲁棒性。  2.该方法能够有效地应对光照变化、背景复杂多样等情况下的图像分割问题。缺点:  对于大尺寸图像,迭代阈值图像分割的计算速度可能成为其一个缺点。

1.3 自适应阈值图像分割

1.3.1 常规方法

分割步骤如下:

1. 针对输入的灰度图像,定义一个大小为 N × N N×NN×N 的窗口,在窗口中央选择一个像素点作为处理的核心像素点。

2. 根据窗口内的像素信息计算局部阈值,作为当前像素的阈值,这个阈值可以是均值、中值、模式等统计量。

3. 将处理完的像素点和当前像素点的局部阈值进行比较,大于等于阈值的像素点设置为白色,小于阈值的像素点设置为黑色,分割出新的二值化图像。

4. 将窗口向图像的其他区域移动,继续对各个区域进行高斯自适应阈值分割,直到图像的所有区域都被分割为二值化图像。

代码:

# 自适应阈值图像分割import numpy as npfrom PIL import Image
# 图像预处理img = Image.open('house.tif').convert('L')width, height = img.sizepixels = img.load()block_size = 11  # 设置块大小

# 分割图像并计算局部阈值for y in range(0, height, block_size):    for x in range(0, width, block_size):        # 获取局部区域        region = []        for j in range(y, y+block_size):            for i in range(x, x+block_size):                if i < width and j < height:                    region.append(pixels[i, j])        # 计算局部区域平均值作为阈值        threshold = sum(region) // len(region)        # 对区域进行二值化处理        for j in range(y, y+block_size):            for i in range(x, x+block_size):                if i < width and j < height:                    if pixels[i, j] > threshold:                        pixels[i, j] = 255                    else:                        pixels[i, j] = 0

#显示分割后的图像img.show('result.jpg')

像素

也可以直接调用cv2.adaptiveThreshold()函数实现。

import cv2# 读取原始图像img = cv2.imread('house.tif', 0)# 自适应阈值分割img_thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)# 显示结果cv2.imshow('Original Image', img)cv2.imshow('Adaptive Thresholding', img_thresh)cv2.waitKey(0)cv2.destroyAllWindows()

像素

1.3.2 大津法(OTSU)

大津法基于以下观察结果:当图像被分为多个区域时,如果区域内的像素值差异较小,区域的均值方差就会较小。而当区域内像素值差异较大时,区域的均值方差就会较大。因此,局部图像的全局最佳阈值是能使类间方差最大的那个灰度级。

步骤:

像素

代码:

import cv2
# 读取图片img = cv2.imread('house.tif', 0)
# 大津法阈值分割ret, img_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 显示结果cv2.imshow('Original Image', img)cv2.imshow('OTSU Thresholding', img_thresh)cv2.waitKey(0)cv2.destroyAllWindows()

像素

优点:  多种检测任务效果较好。缺点:  计算量比较大,适用于数据量较小的图像分割场合。

参考文献:

[1] 阮秋琦,阮宇智译;(美)拉斐尔·C.冈萨雷斯,理查德·E.伍兹.国外电子书与通信教材系列 数字图像处理 第4版[M].北京:电子工业出版社,2020

审核编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分