Opencv2.4学习::二值化(1)OTSU算法

二值化系列:

(1)OTSU算法

(2)固定二值化

(3)自适应二值化

code: 

#include<stdio.h>
#include<string>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//OTSU实现函数
int OTSU(Mat srcImage)
{
	int nCols = srcImage.cols;
	int nRows = srcImage.rows;
	int threshold = 0;
	//初始化统计参数
	int nSumPix[256];
	float nProDis[256];
	for (int i = 0; i < 256; i++){
		nSumPix[i] = 0;
		nProDis[i] = 0;
	}
	//统计灰度级(0-255)中每个像素在整幅图像中的个数
	for (int i = 0; i < nRows; i++){
		for (int j = 0; j < nCols; j++){
			if ((int)srcImage.at<uchar>(i, j) < 0 || (int)srcImage.at<uchar>(i, j) >= 256){
				cout << "yue jie" << endl;
				system("pause");
			}
			nSumPix[(int)srcImage.at<uchar>(i, j)]++;
		}
	}
	//计算每个灰度级占图像中的概率分布(即求占总像素百分比)
	for (int i = 0; i < 256; i++){
		nProDis[i] = (float)nSumPix[i] / (nCols*nRows);
	}
	//遍历灰度级【0,255】,计算出最大类间方差下的阈值
	float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
	double delta_max = 0.0;
	for (int i = 0; i < 256; i++){
		//初始化相关参数
		w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
		for (int j = 0; j < 256; j++){
			//背景部分?
			if (j <= i){
				//当前i为分割阈值,第一类总的概率
				w0 += nProDis[j];
				u0_temp += j*nProDis[j];
			}
			//前景部分?
			else{
				//当前i为分割阈值,第一类总的概率
				w1 += nProDis[j];
				u1_temp += j*nProDis[j];//总灰度(值大小)
			}
		}
		//分别计算各类的平均灰度(值大小)
		u0 = u0_temp / w0;
		u1 = u1_temp / w1;
		delta_temp = (float)(w0*w1*pow((u0 - u1), 2));
		//依次找到最大类间方差下的阈值
		if (delta_temp > delta_max){
			delta_max = delta_temp;
			threshold = i;
		}
	}
	return threshold;
}
int main()
{
	Mat srcImage = imread("F:\\opencv_re_learn\\2.jpg");
	if (!srcImage.data){
		cout << "failed to read" << endl;
		system("pause");
		return -1;
	}
	//转换为灰度图
	Mat srcGray;
	cvtColor(srcImage, srcGray, CV_RGB2GRAY);
	imshow("gray", srcGray);
	//调用OTSU函数计算阈值
	int otsuThreshold = OTSU(srcGray);
	cout << otsuThreshold << endl;
	Mat threshold_result;
	threshold(srcGray, threshold_result, otsuThreshold, 255, THRESH_BINARY);
	imshow("oust_result", threshold_result);
	waitKey(0);
	return 0;
}

结果:

当然,也可以用opencv中自带的OTSU算法,至于两者的差别,需在具体情况下讨论。

threshold(srcGray, threshold_result, otsuThreshold, 255, THRESH_OTSU);   使用OTSU参数,会使得前面的阈值无效

猜你喜欢

转载自blog.csdn.net/dieju8330/article/details/82466704
今日推荐