在图像阈值化操作中,更关注的是从二值化图像中,分离目标区域和背景区域,但是仅仅通过设定固定阈值很难达到理想的分割效果。而自适应阈值,则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值。这样做的好处:
1. 每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。
2. 亮度较高的图像区域的二值化阈值通常会较高,而亮度低的图像区域的二值化阈值则会相适应的变小。
3. 不同亮度、对比度、纹理的局部图像区域将会拥有相对应的局部二值化阈值。
函数原型
1. void adaptiveThreshold(InputArray src, OutputArray dst, 2. double maxValue, int adaptiveMethod, 3. int thresholdType, int bolckSize, double C)
参数说明
参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可。
参数2:函数运算后的结果存放在这。即为输出图像(与输入图像同样的尺寸和类型)。
参数3:预设满足条件的最大值。
参数4:指定自适应阈值算法。可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种。(具体见下面的解释)。
参数5:指定阈值类型。可选择THRESH_BINARY或者THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值)。
参数6:表示邻域块大小,用来计算区域阈值,一般选择为3、5、7......等。
参数7:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。(具体见下面的解释)。
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对参数4与参数7内容的解释:
自适应阈值化计算大概过程是为每一个象素点单独计算的阈值,即每个像素点的阈值都是不同的,就是将该像素点周围B*B区域内的像素加权平均,然后减去一个常数C,从而得到该点的阈值。B由参数6指定,常数C由参数7指定。
ADAPTIVE_THRESH_MEAN_C,为局部邻域块的平均值,该算法是先求出块中的均值,再减去常熟C。
ADAPTIVE_THRESH_GAUSSIAN_C,为局部邻域块的高斯加权和。该算法是在区域中(x, y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算,再减去常数C。
举个例子:如果使用平均值方法,平均值mean为190,差值delta(即常数C)为30。那么灰度小于160的像素为0,大于等于160的像素为255。如下图:
如果是反向二值化,如下图:
delta(常数C)选择负值也是可以的。
代码演示
/* 自适应阈值:adaptiveThreshold()函数 */ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace std; using namespace cv; int main() { //------------【1】读取源图像并检查图像是否读取成功------------ Mat srcImage = imread("D:\\OutPutResult\\ImageTest\\build.jpg"); if (!srcImage.data) { cout << "读取图片错误,请重新输入正确路径!\n"; system("pause"); return -1; } imshow("【源图像】", srcImage); //------------【2】灰度转换------------ Mat srcGray; cvtColor(srcImage, srcGray, CV_RGB2GRAY); imshow("【灰度图】", srcGray); //------------【3】初始化相关变量--------------- Mat dstImage; //初始化自适应阈值参数 const int maxVal = 255; int blockSize = 3; //取值3、5、7....等 int constValue = 10; int adaptiveMethod = 0; int thresholdType = 1; /* 自适应阈值算法 0:ADAPTIVE_THRESH_MEAN_C 1:ADAPTIVE_THRESH_GAUSSIAN_C -------------------------------------- 阈值类型 0:THRESH_BINARY 1:THRESH_BINARY_INV */ //---------------【4】图像自适应阈值操作------------------------- adaptiveThreshold(srcGray, dstImage, maxVal, adaptiveMethod, thresholdType, blockSize, constValue); imshow("【自适应阈值】", dstImage); waitKey(0); return 0; }
显示结果
可以发现自适应阈值能很好的观测到边缘信息。阈值的选取是算法自动完成的,很方便。
滤波处理
另外,做不做滤波处理等对图像分割影响也比较大。
1. adaptiveThreshold分割
Mat img=imread("D:/ImageTest/sudoku.png",CV_LOAD_IMAGE_COLOR); Mat dst1; Mat dst2; Mat dst3; cv::cvtColor(img,img,COLOR_RGB2GRAY);//进行,灰度处理 medianBlur(img,img,5);//中值滤波 threshold(img,dst1, 127, 255, THRESH_BINARY);//阈值分割 adaptiveThreshold(img,dst2,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,11,2);//自动阈值分割,邻域均值 adaptiveThreshold(img,dst3,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,11,2);//自动阈值分割,高斯邻域 //ADAPTIVE_THRESH_MEAN_C : threshold value is the mean of neighbourhood area //ADAPTIVE_THRESH_GAUSSIAN_C : threshold value is the weighted sum of neighbourhood values where weights are a gaussian window. imshow("dst1", dst1); imshow("dst2", dst2); imshow("dst3", dst3); imshow("img", img); waitKey(0);
效果对比,很明显加入邻域权重后处理更理想:
2. 加入滤波处理的最大类间方差分割
Mat img=imread("D:/ImageTest/pic2.png",CV_LOAD_IMAGE_COLOR); Mat dst1; Mat dst2; Mat dst3; cv::cvtColor(img,img,COLOR_RGB2GRAY);//进行,灰度处理 // medianBlur(img,img,5); threshold(img,dst1, 127, 255, THRESH_BINARY); threshold(img,dst2,0, 255, THRESH_OTSU);//最大类间方差法分割 Otsu algorithm to choose the optimal threshold value Mat img2=img.clone(); GaussianBlur(img2,img2,Size(5,5),0);//高斯滤波去除小噪点 threshold(img2,dst3, 0, 255, THRESH_OTSU); imshow("BINARY dst1", dst1); imshow("OTSU dst2", dst2); imshow("GaussianBlur OTSU dst3", dst3); imshow("original img", img); waitKey(0);
效果如下,显然不滤波和滤波差别明显:
参考文章:https://blog.csdn.net/sinat_36264666/article/details/77586964
https://blog.csdn.net/abcvincent/article/details/78822191
原文地址:https://www.cnblogs.com/GaloisY/p/11037350.html