本文共 3122 字,大约阅读时间需要 10 分钟。
大津法(OTSU)是一种经典的图像二值化阈值分割算法,由日本学者大津在1979年提出。其核心思想是通过最大化图像两部分之间的类间方差来确定最优的阈值。这种方法被广泛认为是图像分割中阈值选取的最佳方案,因其计算简单且不受图像亮度和对比度的影响。
大津法的核心在于计算图像中灰度级的类间方差,并找出使类间方差最大的阈值。具体步骤如下:
初始化统计数据:首先统计图像中每个灰度级的像素数量,计算每个灰度级的概率分布(概率密度函数)。
计算累计概率和累计均值:遍历所有灰度级,逐步累加概率和累计均值。
计算类间方差:对于每个灰度级k,计算其与全局均值的类间方差。具体公式为:[\sigma^2 = \frac{(mG \cdot p_k - m_k)^2}{p_k \cdot (1 - p_k)}]其中,(mG)为图像全局均值,(p_k)为灰度级k的概率,(m_k)为灰度级k的累计均值。
寻找最大类间方差:遍历所有灰度级,找出使得类间方差最大的k值,这个k值即为OTSU算法的阈值。
OpenCV提供了OTSU算法的接口,函数定义如下:
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
#include#include #include #include using namespace cv;int Otsu(Mat& src, Mat& dst, int thresh) { const int Grayscale = 256; int graynum[Grayscale] = {0}; int r = src.rows; int c = src.cols; for (int i = 0; i < r; ++i) { const uchar* ptr = src.ptr(i); for (int j = 0; j < c; ++j) { graynum[ptr[j]]++; } } double P[Grayscale] = {0}; double PK[Grayscale] = {0}; double MK[Grayscale] = {0}; double sumtmpPK = 0, sumtmpMK = 0; for (int i = 0; i < Grayscale; ++i) { P[i] = graynum[i] / (r * c); PK[i] = sumtmpPK + P[i]; sumtmpPK = PK[i]; MK[i] = sumtmpMK + i * P[i]; sumtmpMK = MK[i]; } double Var = 0; int best_thresh = thresh; for (int k = 0; k < Grayscale; ++k) { double numerator = (MK[Grayscale-1] * PK[k] - MK[k]); double denominator = PK[k] * (1 - PK[k]); if (denominator == 0) continue; double current_var = numerator * numerator / denominator; if (current_var > Var) { Var = current_var; best_thresh = k; } } if (best_thresh != thresh) { src.copyTo(dst); for (int i = 0; i < r; ++i) { uchar* ptr = dst.ptr(i); for (int j = 0; j < c; ++j) { if (ptr[j] > best_thresh) ptr[j] = 255; else ptr[j] = 0; } } } return best_thresh;}int main() { Mat src = cv::imread("I:\\Learning-and-Practice\\Img\\Fig1039(a)(polymersomes).tif"); if (src.empty()) { return -1; } if (src.channels() > 1) { cvtColor(src, src, CV_RGB2GRAY); } Mat dst, dst2; int thresh = 0; // 通过OTSU算法计算阈值 thresh = Otsu(src, dst, thresh); // 使用OpenCV自带函数计算阈值 double Otsu_thresh = threshold(src, dst2, thresh, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); cout << "Mythresh=" << thresh << endl; cout << "OpenCVthresh=" << Otsu_thresh << endl; namedWindow("src", CV_WINDOW_NORMAL); imshow("src", src); namedWindow("dst", CV_WINDOW_NORMAL); imshow("dst", dst); namedWindow("dst2", CV_WINDOW_NORMAL); imshow("dst2", dst2); waitKey(0); return 0;}
转载地址:http://xrrfk.baihongyu.com/