正常一个图像分为 R、G、B、三个通道,彩色照片中的每个像素值(生活中的某一中颜色)都是由不同R、G、B的值组合在一起的,比如下面这种:
而 图片去色之后变成灰度图,也就是我们所常见的黑白照片,其实生活中所谓的 "黑白照片"有一定的歧义,仔细观察会发现里面会参杂着不同程度的灰色:
真正意义上的 黑白照片 中只有黑色跟白色,要么是白色,要么是黑色;把一张灰度图变成这样的 黑白照片 也称之为 图像的 二值化:
图像的二值化一般经过下面几个步骤:
图像灰度图转化,多通道变单通道;
设置阈值,在设置一个新值(介于黑—白之间的颜色),高于这个颜色设为新值,否则设为另外一个颜色;
选择调节方法阈值;
OpenCv 中有分为几类阈值:简单阈值、自适应阈值和 Otsu’s 二值化,其实这几种方法都是关于图像二值化处理:
简单阈值
简单阈值原理,设置一个阈值,高于这个阈值的图像赋予一个新值,低于这个阈值赋予另一种颜色,用到的函数主要是 cv2.threshhold();里面需要用到4个参数:第一个是需要处理的原图像;第二个是 设置的阈值,第三个是需要赋予的新的像素值;第四个参数是 不同的阈值方法:
cv2.THRESH_BINARY;
cv2.THRESH_BINARY_INV;
cv2.THRESH_TRUNC;
cv2.THRESH_TOZERO;
cv2.THRESH_TOZERO_INV;
五种阈值方法区别如下:
import cv2 import numpy as np from matplotlib import pyplot as plt img_path = 'D:/ceshi.jpg' img = cv2.imread(img_path) #灰度图转化;;; img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,th1 = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY) ret,th2 = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY_INV) ret,th3 = cv2.threshold(img_gray,127,255,cv2.THRESH_TRUNC) ret,th4 = cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO) ret,th5 = cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO_INV) titles = ['oringnal','gray_img','BINGARY','BINGARY_INV','TRUNC','TOZERO','TOZERO_INV'] images = [img,img_gray,th1,th2,th3,th4,th5] i = 0 for i in range(7): plt.subplot(3,3,i+1) plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
阈值展示效果如下:
可以从图像中可以很清楚地看到 不同阈值之间的区别与联系;Threshold()函数返回的有两个值,第二个才是我们要的图像
自适应阈值
这一部分选取处理图像如下:
简单阈值又称之为全句阈值,就是整个图像发生改变,图像中的像素值分布只有两种,一种是大于初设的阈值区域,另外一种就是小于初设的阈值,对于图像阈值处理方面具有一定的局限性,OpenCv 中又引入了一种 自适应阈值 方法,使得图像中不同亮度部分最终显示不同效果,
**自适应阈值 ** 是根据图像上 每一小区域来进行计算 其对应阈值,也就是不同区域会设置不同的阈值效果,
OpenCv 中 自适应阈值函数用到的函数为: adaptiveThreshold(),里面包含有6个参数:
第一个跟简单阈值一样,是源图像 img;
第二个就是赋予的新像素值;
第三个为 Adaptive Method 指定计算阈值的方法,有两种:
cv2.ADPTIVE_THRESH_MENA_C:阈值取子相邻区域的平均值;
cv2.ADPTOVE_THRESH_GAUSSIAN_C:阈值取值相邻区域的加权和,权重为一个高斯窗口。
第四个就是需要选用的阈值方法,简单阈值中用到过的,例如:cv2.THRESH_BINARY;
第五个参数为 Block Size —邻域大小(用来计算阈值的区域大小)。
第六个参数 C 是一个常数,阈值就等于的平均值或者加权平均值减去这个常数值;
提醒一下,在做 自适应阈值 之前,需要对图片进行 一下 中值滤波处理 ;计算指定大小区域的平均像素值并把这一区域的像素值统一赋值;
下来可以看一下 自适应阈值 与 简单阈值 之间的区别,以及 自适应阈值 不同计算方法之间的差别:
import cv2 import numpy as np from matplotlib import pyplot as plt #图片读入灰度图 img1 =cv2.imread('E:/7.jpg',0) #中值滤波 img = cv2.medianBlur(img1,5) #简单阈值 ret, th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,11,2) th3 =cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,11,5) th4 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2) th5 =cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,5) titles = [ 'origianl_ images','means-image','gloabal(v = 127)','Mean(C =2)', 'Mean(C =5)','Gayssian(C = 2)', 'Gayssian(C = 5)' ] images =[img1,img,th1,th2,th3,th4,th5] num = 1 for i in range(2,6): plt.subplot(2,2,num),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) num += 1 plt.show()
展示效果:
这里我用到的图片比较模糊,所以展示的效果很差,下面我贴一下官网上的效果图:
Otsu’s 二值化
无论是 简单阈值 ,还是 自适应阈值 ,我们在处理之前都不可避免地需要考虑 阈值 设置问题,设置的好坏对于最后成像起到很大的影响,但是怎样设置一最适合的阈值呢?不断尝试?
而这个就是 Ostu 二值化要做的,通过根据图像的直方图分布计算出一个阈值 ,但是对于 非双峰图像来说,这种方法得到的结果可能不太理想,Ostu 二值化 用到的函数同样是 cv2.threshold(),
在之前的 简单阈值 部分中,cv2.threshold() 函数返回了两个值,第二个参数是我们最后要的图像,而第一个 rerval ,其实就是这里我们要计算的的最佳阈值,Ostu二值化 与 **简单阈值 **之间 一个重要的区别,就是需要多传入一个参数:cv2.THRESH_OSTU ,同时把 threshold() 函数中设定的阈值一定要设为 0;
import cv2 import numpy as np from matplotlib import pyplot as plt #图片读入灰度图 img1 =cv2.imread('E:/9.jpg',0) #简单阈值处理 ret1,th1 = cv2.threshold(img1,127,255,cv2.THRESH_BINARY) #Ostu thresholding ret2,th2 = cv2.threshold(img1,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) # Ostu ‘ s thresholding after Gaussian FILTERING #5,5为高斯核的大小,0为标准差; blur =cv2.GaussianBlur(img1,(5,5),0) ret3,th3 =cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) ## plot all the images and their histogram images =[img1,0,th1, img1,0,th2, blur,0,th3] titles =[ 'Ori','Hist','Glo(v =127)', 'Ori', 'Hist', 'Ostu', 'Gass', 'Hist', 'Ostu', ] #治理使用 pyplot绘制直方图,参数为一维数组,用到了numpy.ravel()函数; for i in range(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()
这里选取一个带有噪点的图像,对于第一、二排是分别对图像做了 简单阈值 和 Ostu二值化 ,而对于第三副图,先对带噪点的图像做了一个高斯核出去噪音,然后再进行 二值化;
下面利用 pyplot 函数展示每一排分别代表为:处理之前的图像、未处理的直方图、处理之后的图像;
因为这里处理的元图像很模糊,所以处理之后的效果并不明显,这里贴一张官方的图片:
怎么样是不是很赞,而我处理的原图像就下面这样子。。。。。
: