大津法(OTSU)是一种确定图像二值化分割阈值的算法,由日本学者大津于1979年提出。从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。
它被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用。它是按图像的灰度特性,将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
应用: 是求图像全局阈值的最佳方法,应用不言而喻,适用于大部分需要求图像全局阈值的场合。
优点: 计算简单快速,不受图像亮度和对比度的影响。
缺点: 对图像噪声敏感;只能针对单一目标分割;当目标和背景大小比例悬殊、类间方差函数可能呈现双峰或者多峰,这个时候效果不好。
原理非常简单,涉及的知识点就是均值、方差等概念和一些公式推导。为了便于理解,我们从目的入手,反推一下这著名的OTSU算法。
求类间方差:
OTSU算法的假设是存在阈值TH将图像所有像素分为两类C1(小于TH)和C2(大于TH),则这两类像素各自的均值就为m1、m2,图像全局均值为mG。同时像素被分为C1和C2类的概率分别为p1、p2。因此就有:
根据原文,式(4)还可以进一步变形:
分割:
这个分割就是二值化,OpenCV给了以下几种方式,很简单,可以参考:
前面介绍了OTSU算法,但这算法属于全局阈值法,所以对于某些光照不均的图像,这种全局阈值分割的方法会显得苍白无力,如下图:
显然,这样的阈值处理结果不是我们想要的,那么就需要一种方法来应对这样的情况。
这种办法就是自适应阈值法(adaptiveThreshold),它的思想不是计算全局图像的阈值,而是根据图像不同区域亮度分布,计算其局部阈值,所以对于图像不同区域,能够自适应计算不同的阈值,因此被称为自适应阈值法。(其实就是局部阈值法)
如何确定局部阈值呢?可以计算某个邻域(局部)的均值、中值、高斯加权平均(高斯滤波)来确定阈值。值得说明的是:如果用局部的均值作为局部的阈值,就是常说的移动平均法。
double cv::threshold ( InputArray src,
OutputArray dst,
double thresh,
double maxval,
int type
)
#include
#include
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
Mat img = imread(argv[1], -1);
if (img.empty())
{
cout <<"Error: Could not load image" <<endl;
return 0;
}
Mat gray;
cvtColor(img, gray, CV_BGR2GRAY);
Mat dst;
threshold(gray, dst, 0, 255, CV_THRESH_OTSU);
imshow("src", img);
imshow("gray", gray);
imshow("dst", dst);
waitKey(0);
return 0;
}
void adaptiveThreshold(InputArray src, OutputArray dst,
double maxValue,
int adaptiveMethod,
int thresholdType,
int blockSize, double C)
#include
#include
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
Mat img = imread(argv[1], -1);
if (img.empty())
{
cout <<"Error: Could not load image" <<endl;
return 0;
}
Mat gray;
cvtColor(img, gray, CV_BGR2GRAY);
Mat dst;
cv::adaptiveThreshold(gray,, dst, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 21, 10);;
imshow("src", img);
imshow("gray", gray);
imshow("dst", dst);
waitKey(0);
return 0;
}