您的位置:首页 > 其它

最大类间方差法(OTSU)求阈值

2013-07-27 12:44 260 查看
参见论文原文(a threshold selection method from gray-level histograms)
最大类间方差的基本思想是使用一个阈值将整个数据分成两个类,假如两个类之间的方差最大,那么这个阈值就是最佳的阈值。
方差的定义



假设使用一个阈值T,将灰度级[1 L]分割成两个类[1 T-1]和[T L],那么有



那么被k分割出来的两个类的方差则为:



同时定义类内方差与类间方差、总方差如下



由上面公式可知总方差σT是与分割阈值T无关的一个常量值,那么要求最小类内方差就可以转换为求最大类间方差。
σB可以根据前面的式子进一步推导,如下:



例子程序,使用otsu进行肤色分割(首先转换到YCrCb空间,然后再对Cr通道进行分割)
// ostu_test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2/opencv.hpp>

int otsu(const cv::Mat &img)
{
float histogram[256]={0};
for(int i=0;i<img.rows;i++)
{
const unsigned char* p=(const unsigned char*)img.ptr(i);
for(int j=0;j<img.cols;j++)
{
histogram[p[j]]++;
}
}

float avgValue = 0;
int numPixel = img.cols*img.rows;
for(int i=0;i<256;i++)
{
histogram[i] = histogram[i]/numPixel;
avgValue += i*histogram[i];
}

int threshold = 0;
float gmax=0;
float wk=0,uk=0;
for(int i=0;i<256;i++) {

wk+=histogram[i];
uk+=i*histogram[i];

float ut=avgValue*wk-uk;
float g=ut*ut/(wk*(1-wk));

if(g > gmax)
{
gmax = g;
threshold = i;
}
}
return threshold;
}

int _tmain(int argc, _TCHAR* argv[])
{
cv::VideoCapture cap;
cap.open(0);

cv::Mat img;
cv::Mat ycrcb;
cv::Mat channels[3];

while(1)
{
cap>>img;

if(ycrcb.empty())
ycrcb.create(img.rows,img.cols,CV_8UC3);
cv::cvtColor(img,ycrcb,CV_BGR2YCrCb);
cv::split(ycrcb,channels);

int thresh = otsu(channels[1]);
cv::threshold(channels[1],channels[1],thresh,255,CV_THRESH_BINARY);

cv::imshow("src",img);
cv::imshow("thresh",channels[1]);
cv::waitKey(25);
}
return 0;
}


下面是运行截图



说明:
otsu使用图像的统计信息进行阈值计算,在场景比较简单的情况下(即背景和目标占图像像素中的大部分),使用otsu计算得到的阈值进行分割可以达到比较理想的分割效果,抗光照影响的能力比较好。所以再用otsu进行阈值计算的之前,在从源图像转换到灰度图的这个过程中,需要尽量的将背景和目标之间的差异扩大,上面例子中是取转换后的Cr通道,该通道能很好的将肤色和背景区分开来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: