二维OTSU算法快速实现

        OTSU自适应阈值选取算法作为一种经典的阈值分割算法,在图像领域有广泛的应用。在一维OTSU算法上发展而来的二维OTSU算法因为计算时间复杂度高而制约了其应用。通过消除二维自适应阈值算法中的冗余计算,用迭代的方式得到查询表,从而大大的提高了二维阈值计算的速度。

        实现的代码:

// 二维OTSU算法实现.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include <highgui.h>
#include <cv.h>
#include <iostream> 
#include <stdio.h>
#include<opencv\highgui.h>
#include<opencv2\core\core.hpp>
#include "math.h"

int OTSU2d(IplImage * src)
{
	int height = src->height;
	int width = src->width;
	long pixel = height * width;
	int histogram[256][256];
	int i,j;

	for (i = 0;i < 256;i++)//初始化直方图
	{
		for (j = 0; j < 256;j++)
			histogram[i][j] = 0;
	}

	IplImage * temp = cvCreateImage(cvGetSize(src),8,1);
	cvSmooth(src,temp,CV_BLUR,3,0);
	
	for (i = 0;i < height;i++)//计算直方图
	{
		for (j = 0; j < width;j++)
		{
			int data1 = cvGetReal2D(src,i,j);
			int data2 = cvGetReal2D(temp,i,j);
			histogram[data1][data2]++;
		}
	}

	double p_histogram[256][256];
	for (i = 0; i < 256;i++)//直方图归一化
		for(j = 0; j < 256;j++)
			p_histogram[i][j] = (histogram[i][j]*1.0)/(pixel*1.0);

	double Pst_0[256][256];//Pst_0用来存储概率分布情况
	Pst_0[0][0] = p_histogram[0][0];
	for(i = 0;i < 256;i++)//计算概率分布情况
		for(j = 0;j < 256;j++)
		{
		   double temp = 0.0;
		   if(i-1 >= 0)
			   temp = temp + Pst_0[i-1][j];
		   if(j-1 >= 0)
			   temp = temp + Pst_0[i][j-1];
		   if(i-1 >= 0 && j-1 >= 0)
			   temp = temp - Pst_0[i-1][j-1];
		   temp = temp + p_histogram[i][j];
		   Pst_0[i][j] = temp;
		}
		
	double Xst_0[256][256];//存储x方向上的均值矢量
	Xst_0[0][0] = 0 * Pst_0[0][0];
	for(i = 0 ; i < 256;i++)//计算x方向上的均值矢量
		for(j = 0 ; j < 256;j++)
		{
		   double temp = 0.0;
		   if(i-1 >= 0)
			   temp = temp + Xst_0[i-1][j];
		   if(j-1 >= 0)
			   temp = temp + Xst_0[i][j-1];
		   if(i-1 >= 0 && j-1 >= 0)
			   temp = temp - Xst_0[i-1][j-1];
		   temp = temp + i * p_histogram[i][j];
		   Xst_0[i][j] = temp;
		}

	double Yst_0[256][256];//存储y方向上的均值矢量
	Yst_0[0][0] = 0 * Pst_0[0][0];
	for(i = 0 ; i < 256;i++)//计算y方向上的均值矢量
		for(j = 0 ; j < 256;j++)
		{
		   double temp = 0.0;
		   if(i-1 >= 0)
			   temp = temp + Yst_0[i-1][j];
		   if(j-1 >= 0)
			   temp = temp + Yst_0[i][j-1];
		   if(i-1 >= 0 && j-1 >= 0)
			   temp = temp - Yst_0[i-1][j-1];
		   temp = temp + j * p_histogram[i][j];
		   Yst_0[i][j] = temp;
		}
	 
	int threshold1;
	int threshold2;
	double variance = 0.0;
	double maxvariance = 0.0;
	for(i = 0;i < 256;i++)//计算类间离散测度
		for(j = 0;j < 256;j++)
		{
			 long double p0 = Pst_0[i][j];
			 long double v0 = pow(((Xst_0[i][j]/p0)-Xst_0[255][255]),2) + pow(((Yst_0[i][j]/p0)-Yst_0[255][255]),2);
			 long double p1 = Pst_0[255][255]-Pst_0[255][j]-Pst_0[i][255]+Pst_0[i][j];
			 long double vi = Xst_0[255][255]-Xst_0[255][j]-Xst_0[i][255]+Xst_0[i][j];
			 long double vj = Yst_0[255][255]-Yst_0[255][j]-Yst_0[i][255]+Yst_0[i][j];
			 long double v1 = pow(((vi/p1)-Xst_0[255][255]),2)+pow(((vj/p1)-Yst_0[255][255]),2);
			
			 variance = p0*v0+p1*v1;
		   
		   if(variance > maxvariance)
		   {
		      maxvariance = variance;
			  threshold1 = i;
			  threshold2 = j;
		   }
		}

	//printf("%d  %d",threshold1,threshold2);

	return (threshold1+threshold2)/2;

}

int _tmain(int argc, _TCHAR* argv[])
{
	const char * filename  = "rice.jpg";
	IplImage * img = cvLoadImage(filename,0);
	IplImage * dst = cvCreateImage(cvGetSize(img),8,1);
	int threshold = OTSU2d(img);
	cvThreshold(img,dst,threshold,255,CV_THRESH_BINARY);
	cvNamedWindow( "img", 1 );  
	cvShowImage("img", dst);  
	cvWaitKey(-1);
	return 0;
}

 

二值化前:
     

二值化后:

       

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值