Overview
二值化是常用的图像处理手段之一,通过二值化处理我们可以突出图像中感兴趣的部分,过滤掉多余的部分(比如噪音)。OpenCV 中二值化处理主要是调用这两个函数:
下面对不同的二值化方法进行详细说明。注意,下面的讨论都是对灰度图进行二值化处理,但这种方法可以很容易地移植到多通道图像上。
简单二值化
最直接的二值化是这个样子的:对每一个像素点采用相同的二值化阈值,当像素值小于这个阈值时,像素值设为0,相反,设为255。这时,我们调用
cv.threshold
这个方法,它总共接受4个输入:第一个是要处理的图像;第二个是二值化阈值;第三个是像素取值的最大值,一般是255;第四个是二值化的类型。第四个输入有下面五个选择。对于这五种选择的差别详见OpenCV文档。cv.THRESH_BINARY
cv.THRESH_BINARY_INV
cv.THRESH_TRUNC
cv.THRESH_TOZERO
cv.THRESH_TOZERO_INV
代码例子
import cv2 as cv import numpy as np from matplotlib import pyplot as plt img = cv.imread('gradient.png',0) ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY) ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV) ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC) ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO) ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV) titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV'] images = [img, thresh1, thresh2, thresh3, thresh4, thresh5] for i in xrange(6): plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
自适应二值化(Adaptive Threshold)
在简单二值化处理中,我们对整张图片采用了一样的阈值,但很多时候,我们会想对图片中不同的地方采用不同的阈值。比如一张图片不同区域的光照条件不一样,这时我们就会用到自适应二值化(
cv.adaptiveThreshold
)。在这种方法中,算法基于一个像素点周围的区域决定这个像素点的二值化阈值。除了简单二值化中提到的输入参数,cv.adaptiveThreshold
还有自己的三个参数:- adaptiveMethod 告诉函数该使用哪一种自适应方法:
cv.ADAPTIVE_THRESH_MEAN_C
阈值是周围区域的平均值减去一个常量 Ccv.ADAPTIVE_THRESH_GAUSSIAN_C
阈值是周围区域的高斯平均值减去一个常量
- block 周围区域的大小
- C 减去的常量
代码例子
import cv2 as cv import numpy as np from matplotlib import pyplot as plt img = cv.imread('sudoku.png',0) img = cv.medianBlur(img,5) ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY) th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\ cv.THRESH_BINARY,11,2) th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\ cv.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 xrange(4): plt.subplot(2,2,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
大津二值化(Otsu's Binarization)
别猜了,大津是一个日本名字。大津二值化是由大津展之发明的,所以就用他的名字命名了。和简单二值化相似,大津二值化也是一个全局二值化的方法,也就是对整张图片采用同一样的阈值。但和简单二值化不同的是,大津二值化不用人为地提供一个阈值,它根据整张图片的像素点的直方图分布计算合适的阈值。
这样说可能比较抽象,想象一张图片,它由两种不同的像素点组成,比如说0和128。相应的,它的像素点直方图只有两个峰值,分别位于0和128。一个好的阈值应该在0和128的中间,也就是64,这样就可以把这张图片上的像素点分开了。相似的,大津二值化先计算一个这样的合适的阈值,然后用这个阈值对整张照片进行二值化。
由于是全局二值化,我们还是使用
cv.threshold()
这个方法,同时我们需要在最后一个输入参数中添加cv.THRESH_OTSU
。输入的阈值参数将会被忽略,取而代之的是大津二值化计算出来的阈值。代码例子
import cv2 as cv import numpy as np from matplotlib import pyplot as plt img = cv.imread('noisy2.png',0) # global thresholding ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY) # Otsu's thresholding ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU) # Otsu's thresholding after Gaussian filtering blur = cv.GaussianBlur(img,(5,5),0) ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.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 xrange(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()