参见论文原文(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通道,该通道能很好的将肤色和背景区分开来。
最大类间方差法(OTSU)是一种基于图像灰度直方图的阈值选择方法,旨在最大化两类间的方差,从而找到最佳阈值。此方法适用于背景和目标区分明显的图像,例如在肤色分割中,通过转换到YCrCb空间并分割Cr通道,可以有效抵抗光照影响,实现理想分割效果。
4832

被折叠的 条评论
为什么被折叠?



