(三)opencv入门之图像的基本操作——图像阈值分割(ostu算法)

所谓图像分割是根据灰度、彩色、空间纹理、几何形状等特征把图像划分成若干个互不相交的区域,使得这些特征在同一区域内表现出一致性和相似性。

现有的图像分割有以下几类:
1.基于阈值分割:通过设定不同的特征阈值,把图像像素点分为若干类。

最稳定,且无需参数,对于现实图像保持了最好的均匀性和形状特性

2.基于区域分割

3.基于边缘分割:图像中边缘处像素的灰度值不连续,这种不连续性可通过求导数来检测。
常用的一阶微分算子有Roberts算子、Prewitt算子和Sobel算子,二阶微分算子有Laplace算子和Kirsh算子等。

4.基于特定的理论分割方法

下面是基于阈值分割ostu算法实现:

#include "pch.h"
#include
#include    
#include   
#include   
#include   

using namespace std;
using namespace cv;

int Otsu(Mat matSrc)
{
	if (CV_8UC1 != matSrc.type())
	{
		cout << "Please input Gray-image!" << endl;
		return 0;
	}
	int nCols = matSrc.cols;
	int nRows = matSrc.rows;
	int nPixelNum = nCols * nRows;    //图像像素总数  

	int pixelNum[256];
	double probability[256];
	for (int i = 0; i < 256; i++)     //图像像素初始化
	{
		pixelNum[i] = 0;
		probability[i] = 0.0;
	}
	// 统计像素数和频率
	for (int j = 0; j < nRows; j++)
	{
		for (int i = 0; i < nCols; i++)
		{
			pixelNum[matSrc.at(j, i)]++;
		}
	}
	for (int i = 0; i < 256; i++)
	{
		probability[i] = (double)0.1*pixelNum[i] / nPixelNum;
	}

	int T = 0;          // 最佳阈值
	double dMaxDelta = 0;      // 最大类间方差
	double f = 0;        // 前景平均灰度
	double b = 0;        // 背景平均灰度
	double dDelta = 0;         // 类间方差
	double f_temp = 0;   // 前景均值中间值
	double b_temp = 0;   // 背景均值中间值
	double fProbability = 0;  // 前景频率值
	double bProbability = 0;   // 背景频率值

	for (int j = 0; j < 256; j++)
	{
		for (int i = 0; i < 256; i++)
		{
			if (i < j)// 前景部分
			{
				fProbability += probability[i];
				f_temp += i * probability[i];     //计算前景部分灰度中间值
			}
			else      // 背景部分
			{
				bProbability += probability[i];
				b_temp += i * probability[i];     //计算背景部分灰度中间值
			}
		}
		
		f = f_temp / fProbability;    //前景的灰度
		b = b_temp / bProbability;    //背景的灰度

		dDelta = (double)(fProbability * bProbability * pow((f - b), 2));   //当前类方差的计算

		if (dDelta > dMaxDelta)
		{
			dMaxDelta = dDelta;
			T = j;
		}
		
	    fProbability = 0;
		bProbability = 0;
		f_temp = 0;
		b_temp = 0;
		f = 0;
		b = 0;
		dDelta = 0;
		
	}
	return T;
}

int main()
{
	
	Mat img = imread("D:\\Visual Studio project\\ConsoleApplication2\\风景.jpg",IMREAD_GRAYSCALE);  //读取一张灰色的风景图片
	
	int nCols = img.cols;
	int nRows = img.rows;

	imshow("gray", img);

	int nOstuThreshold = Otsu(img);
	cout << nOstuThreshold << endl;

	Mat matOstu = Mat::zeros(img.rows, img.cols, CV_8UC1);
	
	for (int j = 0; j < nRows; j++)
	{
		for (int i = 0; i < nCols; i++)
		{
			if (img.at(j, i) < nOstuThreshold)
			{
				matOstu.at(j, i) = img.at(j, i);
			}
			else
			{
				matOstu.at(j, i) = 0;
			}
		}
	}

	imshow("ostu", matOstu);
	imwrite("D:\\Visual Studio project\\ConsoleApplication2\\ostu.jpg", matOstu);
	waitKey();
	return 0;
}

输出结果:
(三)opencv入门之图像的基本操作——图像阈值分割(ostu算法)_第1张图片
(三)opencv入门之图像的基本操作——图像阈值分割(ostu算法)_第2张图片
参考文章:https://www.cnblogs.com/Tang-tangt/p/9420405.html

你可能感兴趣的:(图像处理,图像阈值分割,ostu算法,opencv,opencv入门)