代码也没进行优化,可能运行速度比较慢。
此函数根据输入的图像返回其最适应阈值。
public static int OtsuThreshold(Mat image)
{
if (image.NumberOfChannels != 1)
{
throw new Exception("通道必须为1");
}
//提取直方图------------------------------------
long[] his = new long[256];
for (int i = 0; i < 256; i++)
{
his[i] = 0;
}
unsafe
{
byte* data = (byte*)image.DataPointer.ToPointer();
for (int row = 0; row < image.Height; row++)
{
//data = data + row * image.Cols;
for (int col = 0; col < image.Width; col++)
{
his[*data]++;
data++;
}
}
}
//-----------------------------------------------
float _PK;
float _MK;//第k级累加灰度均值;
float _MG = 0;//整个图片的灰度均值
double _MN = image.Rows * image.Cols;//图片的像素数目
float[] _Ks = new float[256];//存储类值最大方差
float _Max;//类间最大方差
List<int> _MaxKs = new List<int>();//存储使类间最大方差的多个K值;
for (int i = 0; i < 256; i++)//计算图片平均灰度值
{
_MG += (float)(i * (double)his[i] / _MN);
}
for (int k = 0; k < 256; k++)//计算 图片在不同K的类值最大方差
{
long _count = 0;//表示在k中存在的像素
for (int _index = 0; _index <= k; _index++)//若所有像素都在k内,就将其方差置为0
{
_count += his[_index];
}
if (_count == image.Rows * image.Cols)
{
_Ks[k] = 0;
continue;
}
else if (_count == 0)
{
_Ks[k] = 0;
continue;
}
_PK = (float)(_count / _MN);
_MK = 0;
for (int i = 0; i <= k; i++)
{
float p = (float)(his[i] / _MN);
//_PK += p;
_MK += i * p;
}
_Ks[k] = (float)Math.Pow(_MG * _PK - _MK, 2) / (_PK * (1 - _PK));
}
_Max = _Ks.Max();
for (int i = 0; i < 256; i++)
{
if (_Ks[i] == _Max)
_MaxKs.Add(i);
}
int _K = (int)_MaxKs.Average();
return _K;
}