图像二值化----otsu(最大类间方差法)

/*****转自:http://blog.csdn.net/abcjennifer/article/details/6671288******/

最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均灰度记为μ,类间方差记为g。假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:      ω0=N0/ M×N (1)      ω1=N1/ M×N (2)      N0+N1=M×N (3)      ω0+ω1=1 (4)      μ=ω0*μ0+ω1*μ1 (5)      g=ω0(μ0-μ)^2+ω1(μ1-μ)^2 (6)将式(5)代入式(6),得到等价公式: g=ω0ω1(μ0-μ1)^2 (7)采用遍历的方法得到使类间方差最大的阈值T,即为所求。

Otsu算法步骤如下:设图象包含L个灰度级(0,1…,L-1),灰度值为i的的象素点数为Ni ,图象总的象素点数为N=N0+N1+...+N(L-1)。灰度值为i的点的概为:P(i) = N(i)/N.门限t将整幅图象分为暗区c1和亮区c2两类,则类间方差σ是t的函数:σ=a1*a2(u1-u2)^2 (2)式中,aj 为类cj的面积与图象总面积之比,a1 = sum(P(i)) i->t, a2 = 1-a1; uj为类cj的均值,u1 = sum(i*P(i))/a1 0->t, u2 = sum(i*P(i))/a2, t+1->L-1 该法选择最佳门限t^ 使类间方差最大,即:令Δu=u1-u2,σb = max{a1(t)*a2(t)Δu^2}

/****************************************以下部分内容为原创;OTSU代码**********************************************/


#include <stdio.h>
#include <string>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
   
   
#include 
      
      
       
       
#include 
       
       
        
        
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
// OTSU大均法函数实现
int OTSU(cv::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;
	}
	// 统计灰度级中每个像素在整幅图像中的个数 
	for (int i = 0; i < nCols; i++)
	{
		for (int j = 0; j < nRows; j++)
		{
			nSumPix[(int)srcImage.at
        
        
         
         (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()
{
	// 图像读取及判断
	cv::Mat srcImage = cv::imread("..\\images\\people.jpg");
	if (!srcImage.data)
		return 1;
	// 灰度转换
	cv::Mat srcGray;
	cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
	cv::imshow("srcGray", srcGray);
	// 调用OTSU二值化算法得到阈值
	int  ostuThreshold = OTSU(srcGray);
	std::cout << ostuThreshold << std::endl;
	// 定义输出结果图像
	cv::Mat otsuResultImage =
		cv::Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1);
	// 利用得到的阈值实现二值化操作
	for (int i = 0; i < srcGray.rows; i++)
	{
		for (int j = 0; j < srcGray.cols; j++)
		{
			// 满足大于阈值ostuThreshold置255
			if (srcGray.at
         
         
          
          (i, j) > ostuThreshold)
				otsuResultImage.at
          
          
           
           (i, j) = 255;
			else
				otsuResultImage.at
           
           
             (i, j) = 0; } } cv::imshow("otsuResultImage", otsuResultImage); cv::waitKey(0); return 0; } 
           
          
          
         
         
        
        
       
       
      
      
// OTSU大均法函数实现 int OTSU(cv::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; } // 统计灰度级中每个像素在整幅图像中的个数 for (int i = 0; i < nCols; i++) { for (int j = 0; j < nRows; j++) { 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() { // 图像读取及判断 cv::Mat srcImage = cv::imread("..\\images\\people.jpg"); if (!srcImage.data) return 1; // 灰度转换 cv::Mat srcGray; cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY); cv::imshow("srcGray", srcGray); // 调用OTSU二值化算法得到阈值 int ostuThreshold = OTSU(srcGray); std::cout << ostuThreshold << std::endl; // 定义输出结果图像 cv::Mat otsuResultImage = cv::Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1); // 利用得到的阈值实现二值化操作 for (int i = 0; i < srcGray.rows; i++) { for (int j = 0; j < srcGray.cols; j++) { // 满足大于阈值ostuThreshold置255 if (srcGray.at<uchar>(i, j) > ostuThreshold) otsuResultImage.at<uchar>(i, j) = 255; else otsuResultImage.at<uchar>(i, j) = 0; } } cv::imshow("otsuResultImage", otsuResultImage); cv::waitKey(0); return 0; }



/****************************************以下内容为MATLAB实现的OTSU代码**********************************************/




[plain]  view plain  copy
  1. I=imread('D:\Images\pic_loc\1870405130305041503.jpg');  
  2. a=rgb2gray(I);  
  3. level = graythresh(a);  
  4. a=im2bw(a,level);  
  5. imshow(a,[]); 
  6.  
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值