OSTU二值化算法


介紹

Ostu方法又名最大類間差方法,通過統計整個圖像的直方圖特性來實現全局閾值T的自動選取,其算法步驟為:

  1. 先計算圖像的直方圖,即將圖像所有的像素點按照0~255共256個bin,統計落在每個bin的像素點數量

  2. 歸一化直方圖,也即將每個bin中像素點數量除以總的像素點

  3. i表示分類的閾值,也即一個灰度級,從0開始迭代

  4. 通過歸一化的直方圖,統計0~i 灰度級的像素(假設像素值在此范圍的像素叫做前景像素) 所占整幅圖像的比例w0,並統計前景像素的平均灰度u0;統計i~255灰度級的像素(假設像素值在此范圍的像素叫做背景像素) 所占整幅圖像的比例w1,並統計背景像素的平均灰度u1;

  5. 計算前景像素和背景像素的方差 g = w0*w1*(u0-u1) (u0-u1)

  6. i++;轉到4),直到i為256時結束迭代

7)將最大g相應的i值作為圖像的全局閾值

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

#include <iostream>

int getOstu(const Mat & in);

int main()
{
	Mat img = imread("mobile2.jpeg" ,0);
	Mat img_high_Light = imread("mobile3.jpeg" ,0);
	Mat  dst , dst_HL;

	if(img.empty()  | img_high_Light.empty())
	{
		std::cout<<"Error!!";
		return -1;
	}

	std::cout<<"The return value of getOstu is: "<<getOstu(img);
	std::cout<<"\n"<<"The return value of opencv threshold is: "<<threshold(img , dst ,0,255,CV_THRESH_OTSU);//opencv已實現的大津法

	imshow("origin" ,img);
	imshow("new" , dst);

    waitKey(0);

	threshold(img_high_Light , dst_HL ,0,255,CV_THRESH_OTSU);
	imshow("origin" ,img_high_Light );
	imshow("new",  dst_HL);


	waitKey(0);

	return 0;
}

int getOstu(const Mat & in)
{
	int rows = in.rows;
	int cols = in.cols;
	long size = rows * cols;

	float histogram[256] = {0};
	for( int i = 0; i < rows; ++i)
	{
		//獲取第 i行首像素指針
		const uchar * p = in.ptr<uchar>(i);
		//對第i 行的每個像素(byte)操作
		for( int j = 0; j < cols; ++j )
		{
			histogram[int(*p++)]++;
		}
	}
	int threshold;
	long sum0 = 0, sum1 = 0; //存儲前景的灰度總和及背景灰度總和
	long cnt0 = 0, cnt1 = 0; //前景的總個數及背景的總個數
	double w0 = 0, w1 = 0; //前景及背景所占整幅圖像的比例
	double u0 = 0, u1 = 0;  //前景及背景的平均灰度
	double variance = 0; //最大類間方差


	double maxVariance = 0;
	for(int i = 1; i < 256; i++) //一次遍歷每個像素
	{
		sum0 = 0;
		sum1 = 0;
		cnt0 = 0;
		cnt1 = 0;
		w0 = 0;
		w1 = 0;
		for(int j = 0; j < i; j++)
		{
			cnt0 += histogram[j];
			sum0 += j * histogram[j];
		}

		u0 = (double)sum0 /  cnt0;
		w0 = (double)cnt0 / size;

		for(int j = i ; j <= 255; j++)
		{
			cnt1 += histogram[j];
			sum1 += j * histogram[j];
		}

		u1 = (double)sum1 / cnt1;
		w1 = 1 - w0; // (double)cnt1 / size;

		variance =  w0 * w1 *  (u0 - u1) * (u0 - u1);
		if(variance > maxVariance)
		{
			maxVariance = variance;
			threshold = i;
		}
	}

	return threshold;
}

缺陷

OSTU算法在處理光照不均勻的圖像的時候,效果會明顯不好,因為利用的是全局像素信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM