OpenCV学习笔记04--图像阈值处理、threshold函数、adaptiveThreshold函数、Otsu方法处理

目录

(一)、threshold()函数

(二)、adaptiveThreshold()--自适应阈值处理

 (三)Otsu处理


引言:阈值处理在图像中的用处可以用一句话概括:我们设定一个阈值x,当图像中的像素值大于x时,我们想要怎么处理这些像素值;当小于x时我们又想要怎么处理这些像素值。阈值处理中的threshold()函数给出了很好的解决办法。通过阈值处理我们可以得到一个二值图像。下面我们来学一下。这里我们用到的图像都是8位灰度图像。

(一)、threshold()函数

在opencv中可以使用cv2.threshold()函数进行阈值处理。

reval, newimg = cv2.threshold (img, x, maxval, type)

参数解释:

reval : 是一个返回值,这个值是我们在threshhold参数里设置的x的值。

newimg : 是我们经过阈值处理之后的图像。

img:是我们要进行阈值处理的图像,即我们操作的对象。
x:是我们设置的一个阈值,也就是我们对图像img中的像素点的值进行操作时,是以这个阈值x为标准进行阈值处理的。

maxval:当我们对图像img中的像素点的值和阈值x进行比较时,如果img中的像素点的值大于或者是小于x的值,我们就把图像的像素点的值设置为maxval,maxval最大值是255。其他的设置为0。这个参数只有在type为THRESH_BINARY或者是THRESH_BINARY_INV类型时起作用。

type:这个参数我们好好将分析一下,因为这个参数在阈值处理中对结果有主导作用。

type的类型主要有以下几个:

THRESH_BINARY:也叫做二值化阈值处理,当type为该类型时,表示我们当前对图像img中的像素值与阈值x进行比较时,当图像img中的像素值大于阈值x时,将图像的当前像素点的值设置为maxval,如果不大于,则设置为0。即经过阈值处理之后的图像是一个二值图像,由最大值maxval和0组成。

THRESH_BINARY_INV:也叫做反二值化阈值处理,当type为该类型时,表示我们当前对图像img中的像素值与阈值x进行比较时,当图像img中的像素值大于阈值x时,将图像的当前像素点的值设置为0,如果不大于,则设置为maxval。

THRESH_TRUNC:也叫做截断阈值处理。当type为该类型时,表示我们当前对图像img中的像素值与阈值x进行比较时,当图像img中的像素值大于阈值x时,那就把大于x的像素点的值均设定为x,不大于x的值则我们不做处理。

THRESH_TOZERO_INV:也叫做超阈值0处理。从字面意思我们就可以理解,当type为该类型时,表示我们当前对图像img中的像素值与阈值x进行比较时,当图像img中的像素值大于阈值x时,那就把大于x的像素点的值均设定为0,不大于x的值则我们不做处理。

THRESH_TOZERO:也叫做阈值0处理。和上面的这个类型刚好相反。当type为该类型时,表示我们当前对图像img中的像素值与阈值x进行比较时,当图像img中的像素值不大于阈值x时,那就把大于x的像素点的值均设定为0,大于x的值则我们不做处理。

文字看着很难受,可视化能够让我们清楚的了解它们之间的区别。接下来我们通过实践来练习一下这个函数,当type取不同的类型时的区别通过程序一眼就能明白。我们通过简单的数组进行举例,然后再用图像看区别。

通过数组来练习函数的使用。示例代码如下:

import numpy as np
import cv2
# 声明一个数组,用生成随机数的函数np.random.randint生成一个数组。
data = np.random.randint(0, 256, size=[4, 4], dtype=np.uint8)
print('data=\n', data)
# 使用cv2.threshold()函数
# 设定阈值x为127,这个阈值是自己定义的哈, maxval=255,type = cv2.THRESH_BINARY
reval1, data_THRESH_BINARY = cv2.threshold(data, 127, 255, type=cv2.THRESH_BINARY)
print('data_THRESH_BINARY=\n', data_THRESH_BINARY)

# 设定阈值x为120, maxval=255,type = cv2.THRESH_BINARY_INV
reval2, data_THRESH_BINARY_INV = cv2.threshold(data, 120, 255, type=cv2.THRESH_BINARY_INV)
print('data_THRESH_BINARY_INV=\n', data_THRESH_BINARY_INV)

# 设定阈值x为200,maxval=255,type = cv2.THRESH_TRUNC
reval3, data_THRESH_TRUNC = cv2.threshold(data, 200, 255, type=cv2.THRESH_TRUNC)
print('data_THRESH_TRUNC=\n', data_THRESH_TRUNC)

# 设定阈值x为200,maxval=255,type = cv2.THRESH_TOZERO_INV
reval4, data_THRESH_TOZERO_INV = cv2.threshold(data, 200, 255, type=cv2.THRESH_TOZERO_INV)
print('data_THRESH_TOZERO_INV=\n', data_THRESH_TOZERO_INV)

# 设定阈值x为100,maxval=255,type = cv2.THRESH_TOZERO
reval5, data_THRESH_TOZERO = cv2.threshold(data, 100, 255, type=cv2.THRESH_TOZERO)
print('data_THRESH_TOZERO=\n', data_THRESH_TOZERO)



结果:

随机生成的数组:

二值化阈值处理和反二值化阈值处理的结果如下:

 截断阈值处理结果如下,大于200的都改为了200:

 超阈值零处理和低阈值零处理结果如下:

 可以结合着我们上面说明的类型不同时处理方式也不同,再去理解上面的结果,将会清楚明了了。

通过应用图像来说明函数的使用。这里我们是把上面的代码做了稍微的调整,把数组换成图像的数组,然后进行阈值处理,直接观察图像就可看出效果。代码如下:

import numpy as np
import cv2
# 读取图像位置
filename = r'C:\Users\LBS\Desktop\lena01.png'
# 读取图像,0的意思是读取灰度图像。
data = cv2.imread(filename, 0)
# 打印图像的矩阵
print('图像矩阵data=\n', data)
# 显示原图像
cv2.imshow('01', data)
# 使用cv2.threshold()函数
# 设定阈值x为127,这个阈值是自己定义的哈, maxval=255,type = cv2.THRESH_BINARY
reval1, data_THRESH_BINARY = cv2.threshold(data, 127, 255, type=cv2.THRESH_BINARY)
print('data_THRESH_BINARY=\n', data_THRESH_BINARY)
cv2.imshow('02', data_THRESH_BINARY)
# 设定阈值x为120, maxval=255,type = cv2.THRESH_BINARY_INV
reval2, data_THRESH_BINARY_INV = cv2.threshold(data, 120, 255, type=cv2.THRESH_BINARY_INV)
print('data_THRESH_BINARY_INV=\n', data_THRESH_BINARY_INV)
cv2.imshow('03', data_THRESH_BINARY_INV)
# 设定阈值x为200,maxval=255,type = cv2.THRESH_TRUNC
reval3, data_THRESH_TRUNC = cv2.threshold(data, 200, 255, type=cv2.THRESH_TRUNC)
print('data_THRESH_TRUNC=\n', data_THRESH_TRUNC)
cv2.imshow('04', data_THRESH_TRUNC)
# 设定阈值x为200,maxval=255,type = cv2.THRESH_TOZERO_INV
reval4, data_THRESH_TOZERO_INV = cv2.threshold(data, 200, 255, type=cv2.THRESH_TOZERO_INV)
print('data_THRESH_TOZERO_INV=\n', data_THRESH_TOZERO_INV)
cv2.imshow('05', data_THRESH_TOZERO_INV)
# 设定阈值x为100,maxval=255,type = cv2.THRESH_TOZERO
reval5, data_THRESH_TOZERO = cv2.threshold(data, 100, 255, type=cv2.THRESH_TOZERO)
print('data_THRESH_TOZERO=\n', data_THRESH_TOZERO)
cv2.imshow('06', data_THRESH_TOZERO)
cv2.waitKey()
cv2.destroyAllWindows()

结果:

原图像对应的图像和数组如下图所示。

 二值化阈值处理之后对应的图像和数组如下图所示。

 反二值化阈值处理之后对应的图像和数组如下图所示。

 截断阈值处理之后对应的图像和数组如下图所示。

 

超阈值零处理之后对应的图像和数组如下图所示。

  低阈值零处理之后对应的图像和数组如下图所示。

 以上就是函数threshold()的使用,大家可以通过更改阈值x的大小进行实践,观察结果图像的效果。

(二)、adaptiveThreshold()--自适应阈值处理

 我们在进行阈值处理时,如果说我们的图像色彩不均衡的话,我们通过一个阈值x,无法进行有效的分割,这时我们就可以使用自适应阈值处理,它就像一个掩膜,关于掩膜概念不懂得话,可以看一下我的图像处理笔记03,这种阈值的处理是根据当前像素点的周围邻域内的像素值的加权平均,获得一个阈值,获得阈值之后的操作就和前面的一样了。

该函数的语法格式如下:

reval, newimg = cv2.threshold (img,  maxval, adaptiveMethod, type,blocksize,C)

参数说明:与threshhold函数相同的参数这里不再说明,可以看文章开头,我们这里说一下添加的新的参数的意思。

adaptiveMethod:这个参数有表示的是我们获取阈值的方法,有两种,分别是cv2.ADAPTIVE_THRESH_MEAN_C和cv2.ADAPTIVE_THRESH_GAUSSIAN_C,即均值掩膜和高斯掩膜,均值掩膜的权值是一样的,高斯掩膜则是通过高斯函数分配权值,只是权值不同,对图像的像素点操作都是加权取平均。然后减去常数C,就得到了当前图像像素点的阈值x,对图像的像素逐个计算出这个阈值。就完成了对一幅图像的阈值处理操作。

type:只能是THRESH_BINARY_INVTHRESH_BINARY

blocksize:指定掩膜的大小,通常为奇数3,5,7...

C:是一个常数

我们通过该函数来处理图像,与thresh函数做一个对比。

代码如下:

import numpy as np
import cv2
# 读取图像位置
filename = r'C:\Users\LBS\Desktop\lena01.png'
# 读取图像,0的意思是读取灰度图像。
data = cv2.imread(filename, 0)
# 打印图像的矩阵
print('图像矩阵data=\n', data)
# 显示原图像
cv2.imshow('01', data)
# 使用cv2.threshold()函数
# 设定阈值x为127,这个阈值是自己定义的哈, maxval=255,type = cv2.THRESH_BINARY
reval1, data_THRESH_BINARY = cv2.threshold(data, 127, 255, type=cv2.THRESH_BINARY)
print('data_THRESH_BINARY=\n', data_THRESH_BINARY)
cv2.imshow('02', data_THRESH_BINARY)
# 使用cv2.adaptiveThreshold()函数,adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C
data_Mean = cv2.adaptiveThreshold(data, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize=5, C=3)
print('data_Mean=\n', data_Mean)
cv2.imshow('03', data_Mean)
# 使用cv2.adaptiveThreshold()函数,adaptiveMethod=cv2.ADAPTIVE_THRESH_GAUSSIAN_C
data_GAUSS = cv2.adaptiveThreshold(data, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blockSize=5, C=3)
print('data_Mean=\n', data_GAUSS)
cv2.imshow('04', data_GAUSS)
cv2.waitKey()
cv2.destroyAllWindows()

结果:

原图像为:

threshold函数处理、adaptiveThreshold函数处理的MEAN方法、GAUSSIAN方法结果图如下:

 (三)Otsu处理

       这个处理是为了克服我们手动设置的阈值x对当前图像来说不合理的情况。比如当前图像的像素值都大于125,然后我们设置一个阈值为125,用二值化处理,则图像的像素值都会变为255,其图像是一个白板,这样进行阈值处理是不可取的,那么我们可以通过Otsu进行处理,可以根据当前图像中的所有像素值,设定一个最优的阈值,它会综合考虑所有可能的阈值。

       在opencv中,我们只需要在函数threshold()中对参数type多添加一个参数cv2.THRESH_OTSU即可。

其声明方式如下:

reval, newimg = cv2.threshold (img, x, maxval, type+THRESH_OTSU)

需要注意的是,在使用Otsu方法是,阈值需设为0,函数threshhold会自动寻找最优阈值。

例如:reval, newimg = cv2.threshold (img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

 通过实践来看一下。代码如下:

import numpy as np
import cv2
# 读取图像位置
filename = r'C:\Users\LBS\Desktop\02.png'
# 读取图像,0的意思是读取灰度图像。
data = cv2.imread(filename, 0)
# 打印图像的矩阵
print('图像矩阵data=\n', data)
# 显示原图像
cv2.imshow('01', data)
# 使用cv2.threshold()函数加上Otsu方法
# 设定阈值x为0,这个阈值需为0, maxval=255,type = cv2.THRESH_BINARY+cv2.THRESH_OTSU
reval1, otsu = cv2.threshold(data, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print('otsu=\n', otsu)
cv2.imshow('02', otsu)
cv2.waitKey()
cv2.destroyAllWindows()

 结果如下:

原图,处理之后的图,这里我们没有指定阈值。

 大家可以找一个整体亮度比较高的图像素材,然后通过使用Otsu方法和不使用Otsu方法得到的图像进行比较,你就会知道这个方法的优点所在。

创作不易,转载请注明出处。

猜你喜欢

转载自blog.csdn.net/BaoITcore/article/details/124066618