欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()

程序员文章站 2024-03-22 09:36:58
...

0.前言

阈值化在图像处理中是一种常用的操作,比如图像的二值化就是一种最常见的一种阈值化操作。OpenCV中提供了直接阈值化操作cv::threshold()和自适应阈值化操作cv::adaptiveThreshold()两种接口,本文主要学习下基本的使用。

主要参照:https://blog.csdn.net/guduruyu/article/details/68059450

一个比较好的博客:https://blog.csdn.net/Vichael_Chan/article/details/100584013

参照文档:https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html

参照博客:https://www.cnblogs.com/skyfsm/p/6872648.html

1.直接阈值化 cv::threshold()

阈值化操作的基本思想是,给定一个输入数组和一个阈值,数组中的每个元素将根据其与阈值之间的大小发生相应的改变。

double cv::threshold(
	InputArray src,  //参数1:src输入数组(多通道,8位或32位浮点)
	OutputArray dst, //参数2:与src同大小和类型、通道数的输出数组
	double thresh,   //参数3:thresh阈值
	double maxval,   //参数4:maxval:THRESH_BINARY和THRESH_BINARY_INV阈值类型使用的最大值
	int type);       //参数5:type阈值类型
返回值:如果使用Otsu或Triangle方法计算的阈值

主要通过第五个参数(cv::ThresholdTypes枚举)来控制计算方式(详情参见官方文档):

OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()

OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()

下面测试下第五个参数阈值类型的不同效果:

	Mat src_image = imread("F:/Src/001.jpg",cv::IMREAD_GRAYSCALE);
	Mat image;
	//原图太大了,缩放下
	resize(src_image, image, cv::Size(int(src_image.cols*0.3),int(src_image.rows*0.3)));
	//显示图片
	imshow("source", image);


	//threshold_type = CV_THRESH_BINARY:如果 src(x, y) > threshold, dst(x, y) = max_value; 否则, dst(x, y) = 0;
	//即大于阈值150的为maxvalue255,否则为0(0是黑色)
	Mat img_0;
	threshold(image, img_0, 150, 255, CV_THRESH_BINARY);
	imshow("img_0 CV_THRESH_BINARY", img_0);

	//threshold_type = CV_THRESH_BINARY_INV:如果 src(x, y) > threshold, dst(x, y) = 0; 否则, dst(x, y) = max_value.
	//即大于阈值150的为0,否则为maxvalue255(0是黑色)
	Mat img_1;
	threshold(image, img_1, 150, 255, CV_THRESH_BINARY_INV);
	imshow("img_1 CV_THRESH_BINARY_INV", img_1);

	//threshold_type = CV_THRESH_TRUNC:如果 src(x, y) > threshold,dst(x, y) = threshold; 否则dst(x, y) = src(x, y).
	//即大于阈值150的为threshold150,否则为原值(所以测试图像变暗淡了)
	Mat img_2;
	threshold(image, img_2, 150, 255, CV_THRESH_TRUNC);
	imshow("img_2 CV_THRESH_TRUNC", img_2);

	//threshold_type = CV_THRESH_TOZERO:如果src(x, y) > threshold,dst(x, y) = src(x, y); 否则 dst(x, y) = 0
	//即大于阈值150的为原值,否则为0
	Mat img_3;
	threshold(image, img_3, 150, 255, CV_THRESH_TOZERO);
	imshow("img_3 CV_THRESH_TOZERO", img_3);

	//threshold_type = CV_THRESH_TOZERO_INV:如果 src(x, y) > threshold,dst(x, y) = 0; 否则dst(x, y) = src(x, y).
	//即大于阈值150的为0,否则为原值
	Mat img_4;
	threshold(image, img_4, 150, 255, CV_THRESH_TOZERO_INV);
	imshow("img_4 CV_THRESH_TOZERO_INV", img_4);

	//不知道干嘛的
	Mat img_5;
	threshold(image, img_5, 150, 255, CV_THRESH_MASK);
	imshow("img_5 THRESH_MASK", img_5);

	//THRESH_OTSU和THRESH_TRIANGLE和前面的type可以组合使用,
	//好处是不用自己指定thresh值,系统会进行计算并且作为返回值返回。
	//OTSU(最大类间方差法)。
	//该算法的主要思想是,在进行阈值化时,考虑所有可能的阈值,
	//分别计算低于阈值和高于阈值像素的方差
	//THRESH_OTSU最适用于双波峰
	//如果图像黑白分明,就可以用这个
	Mat img_6;
	threshold(image, img_6, 150, 255, CV_THRESH_OTSU);
	imshow("img_6 CV_THRESH_OTSU", img_6);

	//THRESH_TRIANGLE最适用于单个波峰,最开始用于医学分割细胞等。
	//计算图像灰度直方图
	//寻找直方图中两侧边界
	//寻找直方图最大值
	//检测是否最大波峰在亮的一侧,否则翻转
	//计算阈值得到阈值T, 如果翻转则255 - T
	Mat img_7;
	threshold(image, img_7, 150, 255, CV_THRESH_TRIANGLE);
	imshow("img_7 CV_THRESH_TRIANGLE", img_7);

运行效果:

OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()

2.自适应阈值化 cv::adaptiveThreshold()

自适应阈值化能够根据图像不同区域亮度分布的,改变阈值。

void cv::adaptiveThreshold(
	InputArray src,     //参数1:源8位单通道图像
	OutputArray dst,    //参数2:与src具有相同大小和相同类型的目标图像
	double maxValue,    //参数3:分配给满足条件的像素的非零值
	int adaptiveMethod, //参数4:自适应阈值算法,为ADAPTIVE_THRESH_MEAN_C或ADAPTIVE_THRESH_GAUSSIAN_C 
	int thresholdType,  //参数5:阈值类型,为THRESH_BINARY或THRESH_BINARY_INV
	int blockSize,      //参数6:用于计算像素阈值的像素邻域的大小:3、5、7,依此类推
	double C);          //参数7:从平均值或加权平均值中减去常数

该函数根据以下公式将灰度图像转换为二进制图像(对应参数5):

OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()

函数支持两种自适应方法(cv::AdaptiveThresholdTypes枚举),即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。(摘自参考博客1)

OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()

下面分别测试两种算法的效果:

	Mat src_image = imread("F:/Src/001.jpg",cv::IMREAD_GRAYSCALE);
	Mat image;
	//原图太大了,缩放下
	resize(src_image, image, cv::Size(int(src_image.cols*0.3),int(src_image.rows*0.3)));
	//显示图片
	imshow("source", image);

	int blockSize = 25;
	int constValue = 10;

	//CV_ADAPTIVE_THRESH_MEAN_C 平均
	Mat img_1;
	adaptiveThreshold(image, img_1, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);
	imshow("adaptive CV_ADAPTIVE_THRESH_MEAN_C", img_1);

	//CV_ADAPTIVE_THRESH_GAUSSIAN_C 高斯
	Mat img_2;
	adaptiveThreshold(image, img_2, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);
	imshow("adaptive CV_ADAPTIVE_THRESH_GAUSSIAN_C", img_2);

 OpenCV3学习笔记(5):阈值化操作,threshold()和adaptiveThreshold()