目录
简单阈值
自适应阈值
Otsu的二值化
所谓的图像阈值,就是图像二值化,什么是二值化,就是只有0和1,没有其他的。在OpenCV的图像里面,二值化表示图像的像素为0和255,并没有其他的值,它跟灰度化并不同。然而要想实现二值化,就最好先对图像进行灰度化处理,因为我们需要的图像不能具备GBR三元通道。
简单阈值
retval, dst = cv2.threshold (src, thresh, maxval, type)
src:源图像,8位或32位图像的numpy数组
thresh:阈值,0-255之间的数字,在进行处理时以阈值为边界来设不同的输出,阈值判断时,是以小于等于阈值和大于阈值作为分界条件
maxval:最大阈值,当使用固定阈值方法时为指定阈值,当叠加标记时为允许最大的阈值,算法必须在小于该值范围内计算合适的阈值
type:处理方式,具体取值及含义如下
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = 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()
自适应阈值
dst = cv2.adaptiveThreshold( src, maxValue,adaptiveMethod ,thresholdType,blockSize,C)
adaptiveMethod包含cv2.ADAPTIVE_THRESH_MEAN_C和cv2.ADAPTIVE_THRESH_GAUSSIAN_C两种不同的方法。
这两种方法都是逐个像素地计算自适应阈值,阈值等于每个像素由参数blockSize所指定邻域的加权平均值减去常量C。
cv2.ADAPTIVE_THRESH_MEAN_C:邻域所有像素点的权重值是一致的。
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:与邻域各个像素点到中心点的距离有关,通过高斯方程得到各个点的权重值。在去除背景提取前景方面,自适应阈值函数要有效很多。
import cv2img=cv2.imread ( "computer.png",0) #将图像调整为单通道的灰度图像t1,thd=cv2.threshold (img,127,255,cv2.THRESH_BINARY)athdMEAN=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,5,3) #采用方法ADAPTIVE_THRESH_MEAN_CathdGAUS=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,5,3)cv2.imshow ("img",img)cv2.imshow ("thd",thd)cv2.imshow ("athdMEAN",athdMEAN)cv2.imshow ("athdGAUS",athdGAUS)cv2.waitKey ()cv2.destroyAllWindows ()
Otsu的二值化
在全局阈值处理中,我们使用任意值作为阈值,那么,我们如何知道我们选择的值是好还是不好?
答案是,试错法。但如果是双峰图像(简单来说,双峰图像是直方图有两个峰值的图像)我们可以将这些峰值中间的值近似作为阈值,这就是Otsu二值化的作用。简单来说,它会根据双峰图像的图像直方图自动计算阈值。(对于非双峰图像,二值化不准确。)
为此,使用了我们的cv.threshold()函数,但是需要多传递一个参数cv.THRESH_OTSU。这时要吧阈值设为零。然后算法找到最佳阈值并返回第二个输出retVal。如果未使用Otsu二值化,则retVal与你设定的阈值相同。
请查看以下示例。输入图像是嘈杂的图像。在第一种情况下,我将全局阈值应用为值127。在第二种情况下,我直接应用了Otsu的二值化。在第三种情况下,我使用5x5高斯卷积核过滤图像以消除噪声,然后应用Otsu阈值处理。来看看噪声过滤如何改善结果。
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as plt img = cv.imread(r'picturesnoisy2.png')gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) #global thresholdingret1,binary1 = cv.threshold(gray,127,255,cv.THRESH_BINARY)#Otsu's thresholdingret2,binary2 = cv.threshold(gray,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)#Otsu's thresholding after Gaussian filteringblur = cv.GaussianBlur(gray,(5,5),0)ret3,binary3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# cv.imshow('binary1',binary1)# cv.imshow('binary2',binary2)# cv.imshow('blur',blur)# cv.imshow('binary3',binary3)#Plot all the images and their histogramsimages = [img,0,binary1, img,0,binary2, blur,0,binary3]titles = ['original noisy image','histogram','global threshold(val=127)', 'original noisy image','histogram',"Otsu's threshold", 'Gaussian filter image','histogram',"Otsu's threshold(Gaussian)"]"""使用pyplot中画直方图的方法plt.hist(),注意它的参数是一维数组故使用numpy的ravel()方法或者flatten()方法, 将多维数组转为一维数组#for循环每次打印出一行3幅图"""for i in range(3): plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray') #plt,imshow(img,'gray') 灰度图 plt.title(titles[i*3]),plt.xticks(()),plt.yticks(()) plt.subplot(3,3,i*3+2),plt.hist(images[i*3].flatten(),256) plt.title(titles[1]),plt.xticks(()),plt.yticks(()) plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray') plt.title(titles[2]),plt.xticks(()),plt.yticks(()) plt.show()