一、OTSU閾值化處理(非API實現)
1、非API方式實現OTSU算法:
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <stdio.h>
#include <string.h>
using namespace std;
using namespace cv;
int OTSU(Mat src)
{
int nRows = src.rows;
int nCols = src.cols;
int threshold = 0;
//初始化統計參數
int nSumpix[256];
float nDis[256];
for (int i = 0; i < 256; i++)
{
nSumpix[i] = 0;
nDis[i] = 0;
}
//統計灰度級中每個像素在整幅圖的個數
for (int i = 0; i < nRows; i++)
{
for (int j = 0; j < nCols; j++)
{
nSumpix[(int)src.at<uchar>(i, j)]++;
}
}
//計算每個灰度級佔圖像中的分佈
for (int i = 0; i < 256; i++)
{
nDis[i] = (float)nSumpix[i] / (nRows*nCols);
}
//遍歷灰度級[0,255],計算最大類方差的閾值
float w0, w1, u0_temp, u1_temp, u0, u1, delta;
double delta_max = 0.0;
for (int i = 0; i < 256; i++)
{
//初始化參數
w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta = 0;
for (int j = 0; j < 256; j++)
{
if (j <= i)
{
//當前i爲分割閾值
w0 += nDis[j];
u0_temp += j * nDis[j];
}
//前景部分
else
{
//當前i爲分割閾值
w1 += nDis[j];
u1_temp += j * nDis[j];
}
}
//分別計算各類平均值
u0 = u0_temp / w0;
u1 = u1_temp / w1;
delta = (float)(w0*w1*pow((u0 - u1), 2));
//依次尋找最大類間方差的閾值
if (delta>delta_max)
{
delta_max = delta;
threshold = i;
}
}
return threshold;
}
int main(int argc, char* argv[])
{
Mat src = imread(".//res//num.jpg");
if (!src.data)
return -1;
else
imshow("src", src);
Mat srcGray;
cvtColor(src, srcGray, CV_BGR2GRAY);
//調用UTSO得到閾值
int otsuThreshold = OTSU(srcGray);
Mat dst(srcGray.size(), CV_8UC1);
for (int i = 0; i < srcGray.rows; i++)
{
for (int j = 0; j < srcGray.cols; j++)
{
if (srcGray.at<uchar>(i, j) > otsuThreshold)
dst.at<uchar>(i, j) = 255;
else
dst.at<uchar>(i, j) = 0;
}
}
imshow("OTSU", dst);
waitKey(0);
return 0;
}
2、Opencv的API方式實現:
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread(".//res//num.jpg");
cvtColor(src, src, CV_BGR2GRAY);
Mat dst;
threshold(src, dst, 167, 255, THRESH_OTSU);
imshow("dst", dst);
waitKey();
return 0;
}
上面函數就是採用的THRESH_OTSU方式,即Opencv封裝好的大津算法的二值化。二、其他方式的閾值化處理
THRESH_BINARY_INV,表示dsti=(srci>T)?0:M
THRESH_TRUNC,表示dsti=(srci>T)?M:srci
THRESH_TOZERO_INV,表示dsti=(srci>T)?0:srci
THRESH_TOZERO,表示dsti=(srci>T)?srci:0
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread(".//res//num.jpg");
imshow("src", src);
cvtColor(src, src, CV_BGR2GRAY);
Mat otsu;
threshold(src, otsu, 167, 255, THRESH_OTSU);
imshow("otsu", otsu);
Mat binary;
threshold(src, binary, 167, 255, THRESH_BINARY);
imshow("binary", binary);
Mat binary_inv;
threshold(src, binary_inv, 167, 255, THRESH_BINARY_INV);
imshow("binary_inv", binary_inv);
Mat trunc;
threshold(src, trunc, 167, 255, THRESH_TRUNC);
imshow("trunc", trunc);
Mat tozero_inv;
threshold(src, tozero_inv, 167, 255, THRESH_TOZERO_INV);
imshow("tozero_inv", tozero_inv);
Mat tozero;
threshold(src, tozero, 167, 255, THRESH_TOZERO);
imshow("tozero", tozero);
waitKey();
return 0;
}
不同類型的閾值化有不同的效果: