opencv入门11:图像阀值-thresholding

一个简单的阈值例子就是选择一个像素值p,然后将小于p的所有像素强度设置为零,并且将所有像素值大于p设置为255.以这种方式,我们能够创建图像的二进制表示。

一、阈值化的类型:

OpenCV中提供了阈值(threshold)函数: threshold 。这个函数有5种阈值化类型:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV

为了解释阈值分割的过程,我们来看一个简单有关像素灰度的图片,该图如下。该图中的蓝色水平线代表着具体的一个阈值。

阈值类型1:二进制阈值化 cv2.THRESH_BINARY

  • 该阈值化类型如下式所示:
  • 解释:在运用该阈值类型的时候,先要选定一个特定的阈值量,比如:125,这样,新的阈值产生规则可以解释为大于125的像素点的灰度值设定为最大值(如8位灰度值最大为255),灰度值小于125的像素点的灰度值设定为0。

阈值类型2:反二进制阈值化 cv2.THRESH_BINARY_INV

  • 该阈值化类型如下式所示:
  • 解释:该阈值化与二进制阈值化相似,先选定一个特定的灰度值作为阈值,不过最后的设定值相反。(在8位灰度图中,例如大于阈值的设定为0,而小于该阈值的设定为255)。

阈值类型3:截断阈值化 cv2.THRESH_TRUNC

  • 该阈值化类型如下式所示:
  • 解释:同样首先需要选定一个阈值,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变。(例如:阈值选取为125,那小于125的阈值不改变,大于125的灰度值(230)的像素点就设定为该阈值)。

阈值类型4:阈值化为0 cv2.THRESH_TOZERO

  • 该阈值化类型如下式所示:
  • 解释:先选定一个阈值,然后对图像做如下处理:1 像素点的灰度值大于该阈值的不进行任何改变;2 像素点的灰度值小于该阈值的,其灰度值全部变为0。

阈值类型5:反阈值化为0 cv2.THRESH_TOZERO_INV

  • 该阈值化类型如下式所示:
  • 解释:原理类似于0阈值,但是在对图像做处理的时候相反,即:像素点的灰度值小于该阈值的不进行任何改变,而大于该阈值的部分,其灰度值全部变为0。

二、simple thresholding 简单的阈值方法:

应用简单的阈值方法需要人为干预。
我们必须指定一个阈值T.低于T的所有像素强度都被设置为0.而所有大于T的像素强度被设置为255。

cv2.threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type )

  • src_gray: 输入的灰度图像的地址。
  • dst: 输出图像的地址。
  • threshold_value: 进行阈值操作时阈值的大小。
  • max_BINARY_value: 设定的最大灰度值(该参数运用在二进制与反二进制阈值操作中)。
  • threshold_type: 阈值的类型。从上面提到的5种中选择出的结果。

三、adaptive thresholding 自适应阀值

在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。

cv2.adaptiveThreshold(image,max_BINARY_value,Adaptive_Method,threshold_type,Block_Size,C)

  • max_BINARY_value: 设定的最大灰度值(该参数运用在二进制与反二进制阈值操作中)。
  • threshold_type: 阈值的类型。从上面提到的5种中选择出的结果。

这种方法需要我们指定三个参数,返回值只有一个。

  • Adaptive Method- 指定计算阈值的方法。
    • cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平
      均值
    • cv2.ADPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域
      的加权和,权重为一个高斯窗口。
  • Block Size - 邻域大小(用来计算阈值的区域大小)。表明我们要检查图像的11×11像素区域,而不是像在简单的阈值方法中那样尝试对图像进行全局阈值
  • C - 这就是是一个常数,阈值就等于的平均值或者加权平均值减去这个常数。我们提供一个简单的叫做C的参数。这个值是一个从平均值中减去的整数,使我们可以微调我们的阈值

一般来说,在平均自适应阈值和高斯自适应阈值之间进行选择需要在您的最后进行一些实验。要改变的最重要的参数是邻域大小和C,即从平均值中减去的值。通过试验这个值,你将能够显着地改变你的阈值的结果。

图像阀值-thresholdingadaptive_thresholding.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np 
import argparse
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-i","--image",required =True, help="Path to the image")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
blured = cv2.GaussianBlur(image,(5,5),0)
cv2.imshow("Image",image)

thresh =cv2.adaptiveThreshold(blured, 255 ,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY_INV,11,4)
cv2.imshow("mean thresh",thresh)

thresh =cv2.adaptiveThreshold(blured, 255 ,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,15,3)
cv2.imshow("GAUSSIAN thresh",thresh)
cv2.waitKey(0)

四、Otsu’s 二值化 和 Riddler-Calvard

在使用全局阈值时,我们就是随便给了一个数来做阈值,那我们怎么知道
我们选取的这个数的好坏呢?答案就是不停的尝试。如果是一副双峰图像(简
单来说双峰图像是指图像直方图中存在两个峰)呢?我们岂不是应该在两个峰
之间的峰谷选一个值作为阈值?这就是Otsu 二值化要做的。简单来说就是对
一副双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法
得到的结果可能会不理想)。

mahotas.thresholding.otsu() 和 mahotas.thresholding.rc()

otsu_and_riddlerotsu_and_riddler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from __future__ import print_function
import numpy as np
import argparse
import mahotas
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-i","--image",required =True, help="Path to the image")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(image,(5,5),0)
cv2.imshow("Image",image)

T = mahotas.thresholding.otsu(blurred)
#为了计算T的最优值,我们使用mahotas.thresholding包中的otsu函数
print("Otsu`s threshold:{}".format(T))
thresh = image.copy()
thresh[thresh>T] = 255
thresh[thresh<T] = 0
thresh = cv2.bitwise_not(thresh)
# 首先,我们制作灰度图像的副本,以便使图像达到阈值。
# 第20行然后使任何值大于T white,
# 而第21行将所有剩余的不是白色的像素变成黑色像素。
# 然后我们通过使用cv2.bitwise_not来反转我们的阈值。
# 这相当于在本章前面的例子中应用cv2.THRESH_BINARY_INV阈值类型。
cv2.imshow("Ostu",thresh)

T = mahotas.thresholding.rc(blurred)
# 另一种方法找到最优值T 时要牢记Riddler-Calvard方法。
# 使用mahotas.thresholding中的rc函数
print("Riddler-Calvard:{}".format(T))
thresh = image.copy()
thresh[thresh>T] = 255
thresh[thresh<255] = 0
thresh = cv2.bitwise_not(thresh)
cv2.imshow("Riddler-Calvard",thresh)
cv2.waitKey(0)
努力常态化。
坚持原创技术分享,您的支持将鼓励我继续创作!