#双峰法阈值分割原理及实现

双峰法阈值分割原理及实现

#双峰法阈值分割原理及实现_第1张图片

优点:

​ 双峰法是常用的阈值分割的一种,它被用于图像的灰度直方图具有典型双峰特征的图像中,此时分割效果较好,算法效率较高

缺点:

​ 算法的缺点也很明显,只能针对典型双峰特征图像,受噪声干扰大。

算法基本原理:

步骤1:首先统计图像的灰度信息,得到灰度直方图,设定初始阈值th和迭代次数itertime

步骤2:初始设定第一个最高峰的灰度值V1为0,第二个峰的灰度值V2为255

步骤3:直方图中灰度值为V1的个数记P1,灰度值为V1+1时的个数记为P2,如果P2>P1,则更新V1的值为V1+1.峰值V2则与V2-1相比。

步骤4:第一个峰值从左到右遍历到阈值th,第二个峰值从右遍历到左边。

步骤5:更新新的阈值为(v1 + V2)/2

可以设置迭代次数进行多次迭代

#include
#include
#include
#include

using namespace std;
using namespace cv;


void calcGrayHist(Mat& image, Mat& histImage)
{
	Mat hist;//用于存放直方图计算结果
	const int channels[1] = { 0 };//通道索引
	float inRanges[2] = { 0,255 };
	const float* ranges[1] = { inRanges };//像素灰度值范围
	const int bins[1] = { 256 };//直方图的维度,其实就是像素灰度值的最大值
	calcHist(&image, 1, channels, Mat(), hist, 1, bins, ranges);//计算图像直方图
	//准备绘制直方图
	int hist_w = 256;
	int hist_h = 400;
	int width = 1;
	histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	for (int i = 1; i <= hist.rows; ++i) {
		rectangle(histImage, Point(width * (i - 1), hist_h - 1),
			Point(width * i - 1, hist_h - cvRound(hist.at(i - 1))/2),//调整显示高度
			Scalar(255, 255, 255), -1);
	}
	imshow("hist", histImage);

}
//input         输入图像
//th            预设阈值
//itertime      迭代次数
int Peakfind(Mat input,int th, int itertime)
{
	if (input.channels() == 3)
	{
		cvtColor(input, input, COLOR_RGB2GRAY);
	}
	Mat histimg;
	calcGrayHist(input, histimg);

	int hist[255] = { 0 };
	int width = input.cols;
	int height = input.rows;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			int value = input.at(i, j);//统计直方图
			hist[value]++;
		}
	}
	
	int Pth = th;
	while (itertime--)
	{
		int v1 = 0, P1 = 0;   //峰值1的灰度值和灰度个数
		int v2 = 255, P2 = 0;//峰值2的灰度值和灰度个数
		for (int i = 0; i < Pth; i++)
		{
			
			if (hist[i]>P1)     
			{
				v1 = i;
				P1 = hist[i];
			}
		}

		for (int j = 255; j > Pth; j--)
		{
			if (hist[j] > P2)
			{
				v2 = j;
				P2 = hist[j];
			}
		}
		int Pthcer = (v1 + v2) / 2;
		if (Pth == Pthcer)
		{
			break;
		}
		else
		{
			Pth = Pthcer;
		}
		
	}
	return Pth;


}


int main()
{

	Mat a = imread("mayi.png");
	int th=Peakfind(a, 30,1);
	cout << th << endl;
	threshold(a, a, th, 255, THRESH_BINARY_INV);
	imshow("1", a);
	imwrite("mayiresult.png", a);
	waitKey(0);

}

#双峰法阈值分割原理及实现_第2张图片

#双峰法阈值分割原理及实现_第3张图片

阈值为30迭代次数为1时分割效果

该方法不适合直方图中双峰差别很大或双峰间的谷比较宽广而平坦的图像,以及单峰直方图的情况。

你可能感兴趣的:(Opencv基础图像处理,计算机视觉,opencv,算法)