二值化是图像分割的一种方法,即将256个亮度等级的灰度图像通过适当的阈值选取,使得所有小于该阈值的像素置为一个值,所有大于该阈值的像素置为另一个值,最终得到一张非黑即白的二值图像。可见阈值的选择非常重要,不同的阈值,运算后得到的结果图像是完全不同的。对于多张图像,如何选取每一张图像合适的阈值呢?采用主观判定显然不太现实,合理的选择应该是采用一种自适应的阈值计算方法。自适应阈值计算,我主要看了
大津法(维基百科)
,即最大类间方差法,由日本学者大津展之于1979年提出,简称Otsu,算法基本思想是:设使用某一个阈值将灰度图像根据灰度大小,分成前景部分和背景部分,在这两部分“类间差异最大”(也即“类内差异最小”)的时候,得到的阈值即是最优的二值化阈值。算法原理维基百科讲的很详细,这里不再赘述,只是配的程序实在不敢恭维,或许也就计算机能明白。
大津法c++实现:
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace cv;
// 大津法求阈值
uchar OtsuThreshold(Mat &imgGray)
{
int width = imgGray.cols;
int height = imgGray.rows;
int histData[256] = { 0 };
// 直方图统计
uchar *pImg = imgGray.data;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
histData[pImg[j]]++;
}
pImg += imgGray.step;
}
// 计算像素总数及灰度总和
int totalCount = width * height;
double graySum = 0.0;
for (int i = 0; i < 256; i++)
{
graySum += i * histData[i];
}
uchar threshold = 0;
int backCount = 0, foreCount = 0;
double backGraySum = 0.0, varMax = -999.9;
for (int i = 0; i < 256; i++)
{
// 背景像素数
backCount += histData[i];
if (backCount == 0)
{
continue;
}
// 前景像素数
foreCount = totalCount - backCount;
if (foreCount == 0)
{
break;
}
// 背景像素灰度总和
backGraySum += double(i * histData[i]);
// 背景/前景均值
double backMean = backGraySum / backCount;
double foreMean = (graySum - backGraySum) / foreCount;
// 计算类间差异
double varBetween = backCount * foreCount * (backMean - foreMean) * (backMean - foreMean);
// 最大值位置,即阈值
if (varBetween > varMax)
{
varMax = varBetween;
threshold = i;
}
}
return threshold;
}
int main(int argc, _TCHAR* argv[])
{
Mat img = imread("image\\snow.jpg");
imshow("src", img);
// 计算阈值
Mat imgGray;
cvtColor(img, imgGray, CV_BGR2GRAY);
uchar threshold = OtsuThreshold(imgGray);
// 二值化
int width = imgGray.cols;
int height = imgGray.rows;
uchar *pImg = imgGray.data;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
pImg[j] = (pImg[j] > threshold) ? 255 : 0;
}
pImg += imgGray.step;
}
imshow("result", imgGray);
waitKey();
return 0;
}
运行结果:
工程下载链接:http://download.csdn.net/detail/u013085897/6774265
程序基于vs2005 + opencv210实现,下载工程后,如果与自己使用的opencv版本不一致,则需要对工程进行简单配置才能正确运行。