大津阈值分割算法,返回的阈值可以用于分割图像,对图像进行二值化处理、边缘检测等。
输入:
Mat 类型的地址(如Otsu(&src);)
输出:
返回一个int类型的阈值。
int Otsu(Mat* src)
{
int iHeight = src->rows; // 图片高度
int iWidth = src->cols; // 图片宽度
long lSize = iHeight * iWidth; // 图片大小
float fHistogram[256] = { 0 };
for (int i = 0; i < iHeight; i++) {
unsigned char* p = (unsigned char*)src->data + src->step * i;
for (int j = 0; j < iWidth; j++)
fHistogram[int(*p++)]++;
}
int iThreshold; // 返回的阈值
long lFrontgroundTotalGrayValue = 0,
lBackgroundTotalGrayValue = 0; // 存储前景的灰度总和和背景灰度总和
long lFrontgroundTotalNum = 0,
lBackgroundTotalNum = 0; // 前景的总个数和背景的总个数
double dbFrontgroundRation = 0,
dbBackgroundRation = 0; // 前景和背景所占整幅图像的比例
double dbFrontgroundAveGrayValue = 0,
dbBackgroundAveGrayValue = 0; // 前景和背景的平均灰度
double dbVariance = 0; // 最大类间方差
double dbAveGrayValue = 0;
double dbMaxVariance = 0;
for (int i = 1; i < 256; i++) //一次遍历每个像素
{
// 重新初始化
lFrontgroundTotalGrayValue = 0;
lBackgroundTotalGrayValue = 0;
lFrontgroundTotalNum = 0;
lBackgroundTotalNum = 0;
dbFrontgroundRation = 0;
dbBackgroundRation = 0;
for (int j = 0; j < i; j++)
{
lFrontgroundTotalNum += (long)(fHistogram[j]);
lFrontgroundTotalGrayValue += (long)(j * fHistogram[j]);
}
dbFrontgroundAveGrayValue = (double)lFrontgroundTotalGrayValue / lFrontgroundTotalNum;
dbFrontgroundRation = (double)lFrontgroundTotalNum / lSize;
for (int j = i; j < 256; j++)
{
lBackgroundTotalNum += (long)fHistogram[j];
lBackgroundTotalGrayValue += (long)(j * fHistogram[j]);
}
dbBackgroundAveGrayValue = (double)lBackgroundTotalGrayValue / lBackgroundTotalNum;
dbBackgroundRation = 1 - dbFrontgroundRation; // (double)lBackgroundTotalNum / size;
dbAveGrayValue = dbFrontgroundAveGrayValue * dbFrontgroundRation
+ dbBackgroundAveGrayValue * dbBackgroundRation; //图像的平均灰度
dbVariance = dbFrontgroundRation * dbBackgroundRation * (dbFrontgroundAveGrayValue - dbBackgroundAveGrayValue)
* (dbFrontgroundAveGrayValue - dbBackgroundAveGrayValue);
if (dbVariance > dbMaxVariance)
{
dbMaxVariance = dbVariance;
iThreshold = i;
}
}
printf("iThreshold = %d\n", iThreshold);
return iThreshold;
}