目录
图像的二值化或阈值化 (Binarization) 旨在提取图像中的目标物体,将背景以及噪声区分开来。通常会设定一个阈值T,通过阈值将图像的像素划分为两类:大于阈值的像素群和小于阈值的像素群。 灰度转换处理后的图像中,每个像素都只有一个灰度值,其大小表示明暗程度。二值化处理可以将图像中的像素划分为两类颜色
1、简单阈值处理
(1)函数介绍
ret, dst = cv2.threshold(src, thresh, maxval, type)
src: 输入图,只能输入单通道图像,通常来说为灰度图
dst: 输出图
thresh: 阈值
maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO; cv2.THRESH_TOZERO_INV
cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
cv2.THRESH_BINARY_INV THRESH_BINARY的反转
cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
(2)代码实现
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
def img_show(name, img): # 展示图像函数
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
x = np.zeros([255,255])
for i in np.arange(0,255):
x[:,i] = i
img_x = np.array(x,dtype='uint8')
img_show('img_x',img_x)
ret, thresh1 = cv2.threshold(img_x, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_x, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_x, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_x, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_x, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img_x, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
下面我们用彩色RGB图像进行演示:
其中原始RGB三通道图如下图所示:
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
def img_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img=cv2.imread('chess.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_gray
img_show('chess',img_gray)
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img_gray, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
2、 自适应阈值
(1)函数介绍
th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY,11,2)
- 第一个参数(img):源图像
- th2:输出图像,与源图像大小一致
- 第三个参数(255):超过阈值的部分取值是多少(对于cv.THRESH_BINARY而言)
- 第四个参数(cv.ADAPTIVE_THRESH_MEAN_C):
- (1)在一个邻域内计算阈值所采用的算法,有两个取值,分别为 ADAPTIVE_THRESH_MEAN_C 和 ADAPTIVE_THRESH_GAUSSIAN_C
- (2)ADAPTIVE_THRESH_MEAN_C的计算方法是计算出领域的平均值再减去第七个参数2的值。
- (3)ADAPTIVE_THRESH_GAUSSIAN_C的计算方法是计算出领域的高斯均值再减去第七个参数2的值
- 第五个参数(cv.THRESH_BINARY):这是阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV
- 第六个参数(11):adaptiveThreshold的计算单位是像素的邻域块大小选择,这是局部邻域大小,3、5、7等
- 第七个参数(2):这个参数实际上是一个偏移值调整量,用均值和高斯计算阈值后,再减或加这个值就是最终阈值。
(2)代码实现
img = cv2.imread('chess.jpg',0)
img = cv2.medianBlur(img,5) # 中值滤波
img_show('1',img)
ret,th1 = cv2.threshold(img,127,255,cv.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in np.arange(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
3、Outs二值化处理
(1)基础介绍
在第一部分中,第二个参数retVal(ret)。当我们进行Otsu的二值化时,就会用到它。那是什么?
在全局阈值处理中,我们使用任意值作为阈值,那么,我们如何知道我们选择的值是好还是坏?答案是,试错法。但是考虑一个双峰图像(简单来说,双峰图像是直方图有两个峰值的图像)。对于该图像,我们可以近似地将这些峰值中间的一个值作为阈值,这就是Otus二值化所做的。所以简单来说,它会自动从图像直方图中计算出双峰图像的阈值。(对于非双峰图像,二值化将不准确)
为此,使用了我们的 cv2.threshold() 函数,但传递了一个额外的标志cv2.THRESH_ OTSU。对于阈值,只需传递 zero。然后算法找到最佳阈值并将您作为第二个输出retVal返回。如果不使用Otsu阈值,则 retVal 与您使用的阈值相同。
看看下面的例子。输入图像是噪声图像。在第一种情况下,我为 127 应用了全局阈值。在第二种情况下,我直接应用了Otsu的阈值。在第三种情况下,我使用 5×5 高斯核过滤图像以去除噪声,然后应用 Otsu 阈值。了解噪声过滤如何改善结果。
(2)代码实现
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('noisy.jpg',0)
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in np.arange(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()
文章出处登录后可见!