opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得

opencv4学习笔记(1)-阈值分割3种方法 文章结构:

1.三种分割方法:直接分割、自适应分割(平均值、高斯均值) 2.函数使用 3.程序例程 (C++) 4.效果展示 5.参数设置心得

三种分割方法 1.直接分割
直接分割即最简单的分割方法,将图片转换为灰度图,设置一个灰度值界限,在界限内的像素点,我们就让他变为白色,否则就变成黑色。
直接分割简单粗暴,但是缺点也很明显。如果一个图片某些地方暗,某些地方亮,这样的话分割统一用一个标准的话的,分割效果就不好了。
这里借用博主陨落星云的一张图,让大家看看直接分割的缺陷:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

可以看到由于图片明暗不一致,导致分割的不理想。
2.自适应分割(平均值)
自适应分割就和前面的直接分割不同了。自适应分割会对图像的每一个小区域单独处理,这样的话就达到了因地制宜的效果了。
相比于前面的直接分割需要直接设定阈值(即灰度值界限),我们的自适应分割就不需要了。
自适应分割是如何判断图片中的某一个像素点应该是黑色还是白色呢?这里,自适应分割是通过将像素点和周围特定范围内像素点的灰度值的平均值做比较得出来的。
【opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得】这里大家可能会有一点听不懂,那我们换一种说法。如果一个像素点,他比他周围的像素点灰度的平均值大,那么我们就把他变成白色。相反,我们就把他变成黑色。就像如果你的分数(灰度值)大于你们班级(指定的小范围)的平均值,那么你就是优等生(白色),否则你就是差等生(黑色)。
我么用博主Kyda的一张图做例子:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

如果我们要判断中心点6的颜色应该是黑色还是白色,我么以他为中心,取3x3的矩阵范围(即深蓝色范围),计算矩阵的均值,得出来是5.4。然后我们看他原来值时6。比我们算出来的平均值大,所以他就会变成白色的像素点。类似其他点我们也可以同理算出来。
这里我们通过平均值算出来该点为白色,我们有没有别的办法让该点变成黑色呢。这里我们还可以设置一个偏移量C,这样的话,我们在将像素点的灰度值和平均值(mean)做比较的时候,平均值就会实现减去一个偏移量C,即mean = mean - C。这里偏移量可以为正也可以为负。
这里值得注意的是,以像素点为中心,他左边的距离和右边的距离必须相等,所以可以计算出矩形的长和宽必须是奇数,之后opencv提供的函数里面就有这样一个参数,如果设置为偶数,就会报错。
还有一个问题是,如果大家仔细分析可以得出,如果矩形为3x3,那个图像边界上的那一圈像素点没有办法计算他的均值,这里我们先放一放,不做深究,opencv的函数已经提前做好了边界像素点的处理。
这里总结一下,如果是自适应算法,需要我们用户自己设置两个参数,一个是我们范围矩阵的大小,还有一个就是我们的偏移量C。
3.自适应分割(高斯均值)
高斯均值和我们前面的平均值大体原理来说是一样的。不一样的是,前面的平均值是计算范围矩阵内所有像素点灰度的平均值。而我们的高斯均值并不是计算的平均值。而是引入了高斯分布函数,如果范围矩阵内的像素点,离中心像素点越远,那么他的权重值就会越小。简而言之,就是离中心像素点越的像素点,对我们的均值计算影响越小。
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

我们自适应分割的优势很明显,能够针对图形不同的区域进行处理,降低了图片的明暗不均对分割产生的影响。
函数使用
◆ threshold()//直接分割 double cv::threshold ( InputArraysrc,//输入图片 OutputArraydst, //输入图像 doublethresh,//阈值 doublemaxval,//最大值,一般255 inttype//阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV,不同的取值会导致图形黑白的反转 ) Python: retval, dst = cv.threshold( src, thresh, maxval, type[, dst] ) #include ◆ adaptiveThreshold()//自适应分割 void cv::adaptiveThreshold ( InputArraysrc,//输入图片 OutputArraydst,//输出图片 doublemaxValue,//灰度值最大值,一般取255 intadaptiveMethod,//自适应的方法,ADAPTIVE_THRESH_MEAN_C 和 ADAPTIVE_THRESH_GAUSSIAN_C intthresholdType,//阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV,不同的取值会导致图形黑白的反转 intblockSize,//范围矩阵的大小,注意取奇数 doubleC//偏移量 ) Python: dst = cv.adaptiveThreshold( src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst] ) #include //记得引入头文件

程序例程(C++)
#include #include #include void Demo::threshold_demo() { namedWindow("src", WINDOW_NORMAL); //WINDOW_NORMAL 用户可以改变src窗口大小 namedWindow("src_gray", WINDOW_NORMAL); namedWindow("src_gray_median", WINDOW_NORMAL); namedWindow("gray1", WINDOW_NORMAL); namedWindow("gray2", WINDOW_NORMAL); namedWindow("gray3", WINDOW_NORMAL); Mat src = https://www.it610.com/article/imread("D:/DESKTOP/picture/shadow.jpg"); //读入图片到src imshow("src", src); //显示图片到src窗口 Mat src_gray; //创建一个图形,用来接下来原图转换为的灰度图 cvtColor(src,src_gray, COLOR_BGR2GRAY); //opencv默认图片为BGR,进行阈值分割前需转为灰度图 imshow("src_gray", src_gray); Mat src_gray_median; medianBlur(src_gray, src_gray_median, 5); //进行中值滤波,文字没有说明,作用是除噪 imshow("src_gray_median", src_gray_median); Mat gray1,gray2, gray3; threshold(src_gray_median, gray1, 50, 255, THRESH_BINARY); //直接分割 imshow("gray1", gray1); adaptiveThreshold(src_gray_median, gray2, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 21, 5); //自适应均值分割 imshow("gray2", gray2); adaptiveThreshold(src_gray_median, gray3, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 21, 5); //自适应高斯分割 imshow("gray3", gray3); waitKey(0); }

效果展示 原图:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

中值滤波后灰度图:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

直接分割后(可以看到上面亮部位的分割不清晰):
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

自适应均值分割:(就比较均匀了)
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

自适应高斯分割:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

参数设置心得 对于直接分割,就一直修改阈值到效果最佳就可以了。
对于自适应滤波,如果范围矩阵设置过小,会产生字里面出现空洞,甚至字不清楚的效果,如图:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

如果出现如图黑色过多的效果,可能是因为偏移量不够,可以试着增大偏移量:
opencv学习笔记|opencv学习笔记(1)-阈值分割3种方法,以及相关参数调试心得
文章图片

    推荐阅读