阈值处理是指剔除图像内像素高于阈值或者低于阈值的像素点。图像的阈值处理主要是设置一个阈值:大于这个数赋予一个值,小于一个数赋予另一个值,将图片的像素值变成两个灰度值数中间的一个,实现图像的分割。图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。
目录
1、图像阈值处理函数threshold()介绍
2、常见的5大阈值处理方法
3、自适应阈值与Otsu处理
自适应阈值处理
Otsu处理
进行阈值处理主要使用OpenCV库中的cv.threshold()函数
cv.threshold(src,thresh,maxval,type,dst=None)
src:输入的图片
thresh:阈值
maxval:最大阈值,只对THRESH_BINARY和THRESH_BINARY_INV有用
type:主要有以下几种类型:
对应的类型解释如下:(图片来自OpenCV threshold函数详解_Leenux0810的博客-CSDN博客_opencv threshold)
五大阈值处理方法主要是二值化阈值处理(cv.THRESH_BINARY)、反二值化处理(cv.THRESH_BINARY_INV)、截断阈值化处理(cv.THRESH_TRUNC)、超阈值化零处理(cv.THRESH_TOZERO_INV)、低阈值零处理(cv.THRESH_TOZERO)。五大阈值处理方法,都是通过每个点的像素值与阈值进行比较,然后赋予一个固定的像素值,实现图像的分割,具体意义见上表。废话不多说,先看代码:
import cv2 as cv
# 读取图片
img = cv.imread('zzf10.jpg')
img = cv.resize(img, None, fx=0.4, fy=0.4)
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('img', img)
# 图像的二值化阈值处理
t, img1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
cv.imshow('THRESH_BINARY', img1)
# 图像的反二值化阈值处理
t, img2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV)
cv.imshow('THRESH_BINARY_INV', img2)
# 图像的截断阈值化处理
t, img3 = cv.threshold(img, 127, 255, cv.THRESH_TRUNC)
cv.imshow('THRESH_TRUNC', img3)
# 图像的低阈值化零处理
t, img4 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO)
cv.imshow('THRESH_TOZERO', img4)
# 图像的超阈值化零处理
t, img5 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO_INV)
cv.imshow('THRESH_TOZERO_INV', img5)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果如下:
二值化阈值处理是比较每个点的阈值,大于thresh的赋予maxval,小于thresh的赋予0;反二值化阈值处理,大于thresh的赋予0,小于thresh的赋予thresh;截断阈值化处理,大于thresh的赋予阈值,小于thresh的保持原像素值;超阈值化零处理,大于thresh的赋予0,小于thresh的保持原像素值;低阈值化零处理,大于thresh的保持原像素值,小于thresh的赋予0。图像效果比较明显,各个操作的具体作用大家可以自己去了解一下。
那么问题来了,我们的阈值处理处理的是灰度图,那么能处理彩色图吗?处理的效果是什么呢?只需要将上面的图片灰度化注释掉即可,运行结果如下:
大家可以看出来,这好像和阈值处理的目的和特点不相符合。我查找了一些资料也不太明白为什么是这样。但是我有一些自己的想法,我认为,图片的阈值化处理,是和单个数据比较大小,那么就应该在一维的单通道图片进行比较;而彩色图是三通道,可能是在某一个通道处理,或者是多个通道处理。具体的阈值比较方法不清楚,所以和阈值处理所介绍的效果和目的大相径庭 。大家有什么想法可以在评论区进行讨论哦!
自适应阈值分割也叫做局部阈值化,它是根据像素的邻域块的像素值分布来确定该像素位置上的阈值。 这样做的好处在于每个像素位置处的阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。 亮度较高的图像区域的阈值通常会较高,而亮度较低的图像区域的阈值则会相适应地变小。当图像的色彩不均衡时,只用一个阈值不能有效清晰的分割图像,所以需要自适应阈值处理。
具体的操作需要使用cv.adaptiveThreshold()函数进行自适应阈值处理,具体参数介绍如下:
cv.adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C,dst=None)
src:输入的图像
maxValue:最大值
adaptiveMethod:自适应的方法有两种,一种是cv.ADAPTIVE_THRESH_MEAN_C,领域内的像素值的权值一样;另一种是cv.ADAPTIVE_THRESH_GAUSSIAN_C,领域内的像素值的权值不同,与到中心的距离有关系,呈现高斯分布,通过高斯方程得到各个点的权重。
thresholdType:代表阈值处理的方法,该值必须是cv.THRESH_BINARY或者cv.THRESH_BINARY_INV中的一个
blockSize:块的大小,计算阈值使用的尺寸,3,5,7等
C:常量对每个blockSize所指定的领域的加权平均值减去常量C
具体代码如下:
import cv2 as cv
img = cv.imread('zzf10.jpg')
img = cv.resize(img, None, fx=0.3, fy=0.3)
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('img_', img)
# 图像二值化阈值处理
t, img1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
# 采用领域像素点权重一致的方法自适应阈值
img2 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 5, 3)
# 采用领域像素点权重通过高斯方程计算权值的方法自适应阈值
img3 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 3)
cv.imshow('THRESH_BINARY', img1)
cv.imshow('ADAPTIVE_THRESH_MEAN_C', img2)
cv.imshow('ADAPTIVE_THRESH_GAUSSIAN_C', img3)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果如下图:
可以看的出来自适应阈值分割相对于二值化阈值分割来说,能分割出更多的细节和特征 。在图像中设置多个阈值,能更好的对图像的各个区域的像素值进行处理,分割效果更好。
当我们在对图像进行cv.threshold()阈值处理时,这个阈值往往是自己随机设置的,并不能很好的对图像进行分割。阈值的选取在阈值处理、图像分割中至关重要。Otsu处理可以再遍历所有的像素值找到最好的类间分割阈值,然后进行cv.threshold操作。具体代码如下:
import cv2 as cv
img = cv.imread('zzf10.jpg')
img = cv.resize(img, None, fx=0.3, fy=0.3)
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('img', img)
# 图像二值化阈值处理
t, img1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
# 采用Otsu处理的二值化阈值处理
t2, img2 = cv.threshold(img, 0, 255, cv.THRESH_BINARY+cv.THRESH_OTSU)
cv.imshow('THRESH_BINARY', img1)
cv.imshow('OTSU', img2)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果如下:
可以看得到Otsu处理得到的阈值是145,且分割效果要比普通的二值化处理要好,图片更加清晰,特征更加分明。
总结:本文讲述了图像阈值处理的五种基本方法,同时介绍了自适应阈值方法,针对基本图像阈值处理采用Otsu获取迭代出最佳类间分割阈值,得到最好的阈值处理效果,使得图像分割出的特征更加明显有效。