阈值处理
1、阈值处理
阈值处理就是设定某个阈值,然后对大于阈值的像素或者小于阈值的像素统一处理的过程。比如下面这个简单的图像:
每个格子表示一个像素,格子中的数字表示图片的像素值。如果设定阈值为8,那我们可以把图片分成两个区域,如下图:
然后我们统一对绿色区域或者蓝色区域进行操作,这就是阈值处理了。
我们通常的操作是将高于某一阈值的像素值处理为255,或者低于某一阈值的像素值处理为0。或者两者同时进行。当我们两者同时进行时,我们可以把这个操作成为二值化,因为处理后的图片只有纯黑和纯白两个颜色。
2、用numpy实现阈值处理
在numpy
的ndarray
数组中,提供了布尔索引的操作。通过布尔索引我们可以方便快速实现阈值处理,而不需要写大量的for循环。
布尔索引的操作是基于布尔矩阵的,因此我们需要了解一下布尔矩阵。
(1)布尔矩阵
布尔矩阵其实就是一个元素类型为布尔的矩阵,使用布尔矩阵我们可以对实数矩阵进行布尔索引操作。
我们使用下面代码生成一个布尔矩阵:
import numpy as np m = np.array([False, True, False, False], dtype=np.bool_) print(m) 复制代码
输出结果如下:
[False True False False] 复制代码
不过这个矩阵好像没有什么作用。写出上面的代码只是为了让你知道,布尔矩阵就是一个布尔类型的ndarray
数组。
除了自己手动创建布尔矩阵,我们还可以通过比较运算符生成某个数组的布尔矩阵。如:
import numpy as np # 生成一个二维矩阵 x = np.array([ [10, 13, 90], [80, 21, 34], [1, 4, 6]], dtype=np.uint8 ) # 通过比较生成布尔矩阵 bool_x = x > 8 print(bool_x) 复制代码
在代码中,我们创建了一个二维矩阵。然后通过x > 8
来生成一个布尔矩阵,下面是输出结果:
[[ True True True] [ True True True] [False False False]] 复制代码
可以看到bool_x
和x
的形状是一样的,布尔矩阵和二维矩阵元素之间一一对应。当元素值大于8,在布尔矩阵中表现为True
否则表现为False
。图示如下:
(2)布尔索引
有了布尔矩阵,我们就可以进行布尔索引了。布尔索引只会对矩阵中为True
的部分进行操作。比如下面的代码:
import numpy as np x = np.array([ [10, 13, 90], [80, 21, 34], [1, 4, 6]], dtype=np.uint8 ) bool_x = x > 8 # 将元素值大于8的元素赋值为255 x[bool_x] = 255 print(x) 复制代码
输出结果如下:
[[255 255 255] [255 255 255] [ 1 4 6]] 复制代码
这里需要明确,我们操作的是实数矩阵。布尔矩阵只是用来指引,告诉程序我们需要操作的元素。
从结果可以看到,大于8的元素都被赋值为了255,其它元素没有改变。
3、opencv实现阈值处理
(1)阈值处理函数
在opencv
中提供了阈值处理的函数,其函数定义为:
thresh, dst = cv2.threshold(src, thresh, maxval, type) 复制代码
参数含义如下:
返回的两个值分别是阈值和处理后的结果图像。
下面是阈处理类型可选的几个参数:
当我们阈值处理类型为二值处理时,maxval
参数才起作用。
(3)阈值处理的区别
下面我们来说说各种阈值处理的区别。具体如下表:
我们用代码来实战一下:
import cv2 # 读取图片 img = cv2.imread('beautiful.JPG', 0) # 进行二值化阈值处理 _, result = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # 显示图片 cv2.imshow('result', result) cv2.waitKey() cv2.destroyAllWindows() 复制代码
下面是效果图和原图的对比:
可以看到,原图本事要偏暗。而我们的阈值设置为了127,导致得到的二值图像效果要差一些,这个我们后面会提到解决办法。
我们再来尝试一下截断式阈值处理:
import cv2 img = cv2.imread('beautiful.JPG') _, result = cv2.threshold(img, 100, 255, cv2.THRESH_TRUNC) cv2.imshow('result', result) cv2.waitKey() cv2.destroyAllWindows() 复制代码
这次我们没有以灰度图的方式读取图片,因此最后的结果也是彩色图片,下面是效果图:
因为一些像素值高的点被抑制了,所以效果图偏暗,而且对比度也明显降低了。
其余的大家可以自己尝试一下。
4、Otsu处理
在上面的例子中,我们都需要手动设置阈值。而且不同图像设置不同的阈值效果上会有很大区别,而Otsu
算法就是一种自动确定阈值的算法。我们可以用cv2.threshold
函数直接实现,使用如下:
import cv2 import numpy as np img = cv2.imread('beautiful.JPG', 0) _, result1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # 使用Otsu算法 thresh, result2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) # 将两张图片横向拼接 result = np.hstack((result1, result2)) # 输出Ostu算法得到的阈值 print(thresh) cv2.imshow('result', result) cv2.waitKey() cv2.destroyAllWindows() 复制代码
我们分别使用了普通的二值化和Otsu
算法,下面是效果图:
这次效果上背景看的更加清晰了。
输出的阈值如下:
99.0 复制代码
大家可以多尝试处理一些不同的图片。
作者:ZackSock
链接:https://juejin.cn/post/6992763193382666277
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。