Python OpenCV入门到精通学习日记:图像的阈值处理
前言
阈值是图像处理中很重要的一个概念,类似于一个标准线。所有像素值都去和这条“标准线”进行比较,会得到大于,小于,等于三种不同的结果,程序对这三种结果进行分组,然后分别对不同组的像素进行“加深”或“变淡”的操作,让整个图像的轮廓变得更加鲜明,从而更容易让计算机或人眼识别。
其中阈值处理函数和自适应处理是重点内容
图像的阈值处理
1 阈值处理函数
在图像处理中,阈值的使用可以使得图像的像素值变得更加单一让图像的效果更加简单。具体流程就是先把彩色图像变成灰度图像,这样图像的像素值都被控制在了0到255,然后通过阈值处理,可以让灰度图像只呈现纯黑色和纯白色的视觉效果。举个例子,假设阈值为127,阈值处理就是把小于127的像素值都转化为0(纯黑色),把大于127的像素值都转化为255(纯白色)。虽然这样会丢失一些灰度细节,但是会更加明显地保留灰度图像的主体轮廓。
Opencv提供了函数threshold()
方法用于对图像进行阈值处理:
retval, dst = cv2.threshold(src, thresh, maxval, type)
参数说明:
src:被处理的图像,可以是多通道图像。
thresh:阈值,阈值在125~150取值的效果最好。
maxval:阈值处理采用的最大值。
type:阈值处理类型。常用类型和含义如表所示。
retval:处理时采用的阈值。
dst:经过阈值处理后的图像。
类型 | 含义 |
---|---|
CV2.THRESH_BINARY | 二值化阈值处理 |
CV2.THRESH_BINARY_INV | 反二值化阈值处理 |
CV2.THRESH_TOZERO | 低于阈值零处理 |
CV2.THRESH_TOZERO_INV | 超出阈值零处理 |
CV2.THRESH_TRUNC | 截断阈值处理 |
2 非黑即白的图像
二值化处理和反二值化处理使得灰度图像的像素值两极分化,灰度图像呈现出只有纯黑色和纯白色的视觉效果。非黑即白的图像由此而来。
2.1 二值化处理
二值化处理也叫二值化阈值处理,该处理让图像仅保留两种像素值,即0或255(最大值通常为255)。
进行二值化处理时,每一个像素值都会与阈值进行比较,将大于阈值的像素值变为最大值,将小于或等于阈值的像素值变为0。
if 像素值 <= 阈值:像素值 = 0
if 像素值 > 阈值:像素值 = 最大值
示例:将图img_1进行二值化处理,取0~255的中间值127作为阈值,将255作为最大值。
import cv2
img = cv2.imread("img_1.png",0)
t1,dst1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
print(t1)
cv2.imshow("img",img)
cv2.imshow("dst1",dst1)
cv2.waitKey()
cv2.destroyAllWindows()
运行结果如下:
当把阈值调高时,白色会变少,黑色会变多,因为原先大于127是白色的部分也会因为阈值变高而变成黑色,反之同理
当然,当调整了maxval参数后,例如原先maxval参数为255时,大于阈值部分呈现纯白色,如果将maxval参数调整为150,大于阈值部分会呈现灰色,因为最大值变成了150,图像将呈现非灰即黑的情况。
当然,彩色图像也可以进行二值化处理,处理后会将颜色夸张化。大家可以去试试,记得要先将彩色图像灰度处理。
2.2 反二值化处理
反二值化处理也叫反二值化阈值处理,其结果为二值化处理的相反结果。将大于阈值的像素值变为0,将小于或等于阈值的像素值变为最大值。
if 像素值 <= 阈值:像素值 = 最大值
if 像素值 > 阈值:像素值 = 0
处理方法和二值化处理相似,只是用到了不同的type参数,就不再这赘述了。
3 零处理
零处理会将某一个范围内的像素值变为0,并允许范围之外的像素保留原值。零处理包括低于阈值零处理和超出阈值零处理。
3.1 低于阈值零处理
低于阈值零处理也叫作低阈值零处理,该处理将低于或等于阈值的像素值变为0,大于阈值的保持不变。
if 像素值 <= 阈值:像素值 = 0
if 像素值 > 阈值:像素值 = 原值
还是使用threshold()
方法,只需要修改type参数为CV2.THRESH_TOZERO。
彩色图像经过低阈值零处理后,颜色浅的不会受到影响,颜色深的会变黑。
3.2 超出阈值零处理
超出阈值零处理也叫超阈值零处理,该处理将大于阈值的像素值变为0,小于或等于阈值的像素值保持原值,和低于阈值零处理正好相反。
if 像素值 <= 阈值:像素值 = 原值
if 像素值 > 阈值:像素值 = 0
这个给我的感觉没啥用,用了后图像变得更加混乱了,都黑黑的。
4 截断处理
截断处理也叫截断阈值处理,该处理将图像中大于阈值的像素值变为和阈值一样的值,小于或等于阈值的像素保持原值。
if 像素值 <= 阈值:像素值 = 原值
if 像素值 > 阈值:像素值 = 阈值
老规矩还是用threshold()
函数,type参数修改为CV2.THRESH_TRUNC。
图像经过截断处理后,整体颜色都会变暗。彩色图像经过截断处理后,在降低亮度的同时还会让浅颜色区域的颜色变得更浅。
5 自适应处理
我们在前面已经学习了5种阈值处理方法,但有时处理图像只用一种方法处理,是无法得到清晰有效的结果的。对于色彩不均衡的图像,虽然使用阶段效果是比较好的,但是有些轮廓还是模糊不清,不过还好,Opencv提供了一种改进的阈值处理技术:图像中的不同区域使用不同的阈值。我们把这种技术称作自适应阈值处理。
自适应阈值是根据图像中某个正方形区域内的所有像素值按照指定的算法计算得到的。
自适应处理能更好地处理明暗分布不均的图像,获得更好的效果。
Opencv提供了adaptiveThresHold()
方法对图像进行自适应处理:
dst = cv2.adaptiveThreshold(src, maxValue,adaptiveMethod, thresholdType, blockSize, C)
参数说明:
src:被处理的图像。需要注意的是,该图像需是灰度图像。
maxValue:阈值处理采用的最大值。
adaptiveMethod:自适应阈值的计算方法。自适应阈值的计算方法及其含义如表所示。
thresholdType:阈值处理类型;需要注意的是,阈值处理类型需是 cv2.THRESH_BINARY 或cv2.THRESH_BINARY_INV中的一个。
blockSize:一个正方形区域的大小。例如,5指的是5×5的区域。
C:常量。阈值等于均值或者加权值减去这个常量。
dst:经过阈值处理后的图像。
计算方法 | 含义 |
---|---|
CV2.ADAPTIVE_THRESH_MEAN_C | 对一个正方形区域内的所有像素平均加权 |
CV2.ADAPTIVE_THRESH_GAUSSIAN_C | 根据高斯函数按照像素与中心点的距离对一个正方形区域内的所有像素进行加权计算 |
光看这些定义真的看不懂,我们来运行试试看。
import cv2
img = cv2.imread("liuhui.png")
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
mean_c = cv2.adaptiveThreshold(img_gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,5,3)
gaussian_c = cv2.adaptiveThreshold(img_gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,5,3)
cv2.imshow("img",img)
cv2.imshow("img_gray",img_gray)
cv2.imshow("mean",mean_c)
cv2.imshow("gaussian",gaussian_c)
cv2.waitKey()
cv2.destroyAllWindows()
运行结果如下:
图片网上找的,侵权删。
这张图片其实很难做处理,特别是手和脸重合的部分,很明显,自适应处理保留了图像中更多的细节信息,更明显地保留了灰度图像主体的轮廓,而CV2.ADAPTIVE_THRESH_MEAN_C描绘出的轮廓似乎会更粗一些。
自适应阈值处理时如果是彩色图像一定要使用cv2.cvtColor()
函数将彩色图像转换为灰度图像,否则会报错。
6 Otsu方法
在前面进行阈值处理时,我们都将阈值设置为127,这个其实是人为控制,并不是通过算法得到的,对于有些图像,阈值设置为127的效果并不是很好,这时就需要一个个去尝试,找到最好的阈值。人为去寻找肯定是不好的,还好,Opencv提供了Otsu方法,他可以遍历所有可能的阈值,从中找到最合适的阈值。
Otsu的语法和threshold的语法差不多,只是在type传递参数时要多传递一个参数,即cv2.THRESH_OTSU。
retval, dst = cv2.threshold(src, thresh, maxval, type)
参数说明:
src:被处理的图像。需要注意的是,该图像需是灰度图像。
thresh:阈值,且要把阈值设置为0。
maxval:阈值处理采用的最大值,即255。
type:阈值处理类型。除在表中选择一种阈值处理类型外,还要多传递一个参数,即cv2.THRESH_OTSU。例如,cv2.THRESH_BINARY+cv2.THRESH_OTSU。
retval:由Otsu方法计算得到并使用的最合适的阈值。
dst:经过阈值处理后的图像。
import cv2
img = cv2.imread("liuhui.png")
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
t1,dst1 = cv2.threshold(img_gray,123,255,cv2.THRESH_BINARY)
t2,dst2 = cv2.threshold(img_gray,0,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.putText(dst2,"best threshold:"+str(t2),(0,30),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)
cv2.imshow("binary",dst1)
cv2.imshow("otsu",dst2)
cv2.waitKey()
cv2.destroyAllWindows()
运行结果如下:
运行到这里我蒙了,为什么让Opencv找的阈值直接让图像的手没了,后来一想,图中人物的眼睛变得更清楚了,不管怎么说,otsu方法还是有用的。
小结
其实学到这里,我觉得真的会用到的只有自适应,因为他结合了前面五种方法,重点掌握!!!
明天继续图像的运算!
标签:阈值,处理,cv2,像素,Opencv,THRESH,苦学,图像,第七天 From: https://blog.csdn.net/qq_71745595/article/details/140524961