图像处理之大津法OTSU(C++)

本文详细介绍了大津法的基本原理,提供C++手动实现以及OpenCVAPI的示例,并比较了两者在处理速度上的差异。作者展示了如何通过计算类间方差找到最佳阈值进行图像分割。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图像处理之大津法OTSU(C++)



前言

大津法,又称最大类间方差法(OTSU)是一种常用的阈值处理方法。
该方法假设图像包含两类像素(前景和背景),通过计算使得两类像素间方差最大的灰度值。
应用场景:直方图为双峰直方图、单个目标物体的分割。


一、大津法原理

大津法公式
参数解释:

  1. mG:全局平均灰度值
  2. P1(k):灰度值从0到k的概率和
  3. m(k):灰度值从0到k的灰度值的平均
  4. σ*σB:灰度值为k时的类间方差,我们的目标就是求得最大类间方差时的灰度值K。
    P1(k)
    m1(k)

二、代码实现

1.C++手动实现

/*
* @param cv::Mat src 输入图像(CV_8U)
* @param cv::Mat dst 输出图像
* @param int	thresh OTSU最大类间方差的灰度值
* @brief 计算OTSU的灰度值并返回
*/
int OtsuThreshold(const cv::Mat& src, cv::Mat& dst,int& thresh)
{
	int h = src.rows;
	int w = src.cols;
	//利用查表法计算各个灰度级的概率
	double grayTable[256] = { 0 };
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++)
			grayTable[src.at<uchar>(i, j)]++;

	for (int i = 0; i < 256; i++)
		grayTable[i] /= (h * w);

	//计算全局灰度平均值
	double mg = 0;
	for (int i = 0; i < 256; i++)
		mg += (i * grayTable[i]);

	//计算各个灰度级的方差
	double sigmmaTable[256] = { 0 };
	double m = 0;
	double p1= 0;
	for (int k = 0; k < 256; k++)
	{
		m += (k * grayTable[k]);	//	灰度级为k的累加均值m
		p1 += grayTable[k];			//  灰度级为k的累加概率p1
		sigmmaTable[k] = pow((mg * p1 - m), 2) / (p1 * (1 - p1));
	}

	//查找方差最大的灰度值k
	double max = sigmmaTable[0];
	thresh = 0;
	for (int i = 1; i < 256; i++)
	{
		if (max < sigmmaTable[i])
		{
			max = sigmmaTable[i];
			thresh = i;
		}
	}

	dst = src.clone();
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++) {
			if (src.at<uchar>(i, j) > thresh)
				dst.at<uchar>(i, j) = 255;
			else
				dst.at<uchar>(i, j) = 0;
		}
			
	return thresh;
}
int main()
{
	//读取图片
	string filepath = "F://work_study//algorithm_demo//baby.jpg";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		std::cout << "imread error" << std::endl;
		return -1;
	}
	cv::Mat dst(src.size(), src.type());
	// 调用自己实现的OTSU函数
	OtsuThreshold(src,dst,thresh2);
	//显示图片
	cv::imshow("dst.bmp", dst);
	cv::waitKey(0);
	return 0;
}

2.调用OpenCV的API

int main()
{
	//读取图片
	string filepath = "F://work_study//algorithm_demo//baby.jpg";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		std::cout << "imread error" << std::endl;
		return -1;
	}

	cv::Mat dst(src.size(), src.type());
	
	// 调用OpenCV的API
    cv::threshold(src, dst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

	//显示图片
	cv::imshow("dst.bmp", dst);
	cv::waitKey(0);
	return 0;
}

三、结果展示

OTSU结果图


总结

本文介绍了大津法的原理和C++代码实现,和opencv API进行对比,自己实现的算法处理速度是2ms,OpenCV的是5ms,计算得到的最大类间对应的灰度值一致,欢迎大家阅读。
因为笔者水平有限,有错误欢迎指出,代码本人均在本地运行实验正确,大家放心使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值