##1、OTSU阈值化
  最大类间方差算法,步骤如下:
  统计每个像素在整幅图中的个数——计算每个像素的概率分布——对灰度值进行遍历搜索,计算当前灰度值下前景背景类间概率——通过目标函数计算出类内与类间方差下对应的阈值。
  代码如下:

int OTSU(Mat srcImg)//输入灰度图像
{
int nCols = srcImg.cols;//纵方向x
int nRows = srcImg.rows;//横方向y
int threshold = 0;//输出的灰度阈值
int nSumPix[256];//灰度级统计数组
float nProDis[256];//灰度级概率分布数组
for (int i = 0; i < 256; i++)//初始化统计数组
{
nSumPix[i] = 0;
nProDis[i] = 0;
}
for (int i = 0; i < nRows; i++)//统计灰度
{
for (int j = 0; j < nCols; j++)
{
nSumPix[(int)srcImg.at<uchar>(i, j)]++;
}
}
for (int i = 0; i < 256; i++)//计算概率分布
{
nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
}
//遍历灰度级[0, 255],计算出最大类间方差下的阈值
float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
double delta_max = 0.0;
for (int i = 0; i < 256; i++)
{
w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
for (int j = 0; j < 256; j++)
{
if (j <= i)//背景
{
w0 += nProDis[j];
u0_temp += j * nProDis[j];
}
else //前景
{
w1 += nProDis[j];
u1_temp += j * nProDis[j];
}
}
//求平均灰度
u0 = u0_temp / w0;
u1 = u1_temp / w1;
delta_temp = (float)(w0 * w1 * pow((u0 - u1), 2));//求方差
if (delta_temp > delta_max)//找出最大方差
{
delta_max = delta_temp;
threshold = i;
}
}
return threshold;
}
int main()
{
……
Mat srcGray;
int ostuThresHold = OTSU(srcGray);//得到阈值
Mat otImg = Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1);//创建二值图像
for (size_t i = 0; i < srcGray.rows; i++)
{
for (size_t j = 0; j < srcGray.cols; j++)
{
if (srcGray.at<uchar>(i, j) > ostuThresHold)//灰度像素读取操作
otImg.at<uchar>(i, j) = 255;
else
otImg.at<uchar>(i, j) = 0;
}
}
imshow("otImg_2", otImg);
waitKey(0);
return 0;
}

##2、固定阈值化
  利用阈值化函数threshold:

double threshold (InputArray src, OutputArray dst, double thresh, double maxval, int type);
  • src:单通道图像组
  • dst:输出图像组(与输入图像同样尺寸和类型)
  • thresh:表示二值化的分界阈值[0, 255]
  • maxVal:表示二值化的最大值[0, 255]
    OpenCV提供了THRESH_BINARY和THRESH_BINARY_INV两种默认参数,或者定义为:
const int maxVal = 255;
  • type:表示阈值化处理的类型
    0、1:非黑[255]即白[0]
    2、3、4:可利用参数maxVal自设
type 代码类型 含义
THRESH_BINARY
二进制阈值化
0 $dst \left( x,y \right)= \begin{cases} maxval & src\left( x,y \right) > thresh \ 0 & \text{其他} \ \end{cases}$
THRESH_BINARY_INV
反二进制阈值化
1 $dst \left( x,y \right)= \begin{cases} maxval & src\left( x,y \right) \leqslant thresh \ 0 & \text{其他} \ \end{cases}$
THRESH_TRUNC
截断阈值化
2 $dst \left( x,y \right)= \begin{cases} threshold & src\left( x,y \right) > thresh \ src\left( x,y \right) & \text{其他} \ \end{cases}$
THRESH_TOZERO
阈值化为0
3 $dst \left( x,y \right)= \begin{cases} src\left( x,y \right) & src\left( x,y \right) > thresh \ 0 & \text{其他} \ \end{cases}$
THRESH_TOZERO_INV
反阈值化为0
4 $dst\left( x,y \right)= \begin{cases} threshold & src\left( x,y \right) > thresh \ src\left( x,y \right) & \text{其他} \ \end{cases}$

##3、自适应阈值化
  利用函数adaptiveThreshold:

void adaptiveThreshold (InputArray src, OutputArray dst, double maxVal, int adaptiveMethod, int thresholdType, int blockSize, double C);
  • adaptiveMethod:自适应算法
    0:ADAPTIVE_THRESH_MEAN_C
    1:ADAPTIVE_THRESH_GAUSSIAN_C
  • ThresholdType:阈值类型
    0:THRESH_BINARY
    1:THRESH_BINART_INV
  • blockSize:表示邻块大小用来计算区域阈值,一般为3、5、7……
  • C:常数
    我也不太清楚怎么设QAQ

##4、双阈值化

  对于图像中有明显的双分界特征,可以利用双阈值法进行操作。不过需要预先设定好两个阈值量,相当于上界和下界,然后将落在二者中间的像素设定为maxVal,其余的像素设定为0。

int main()
{
……
Mat srcImg;
//初始化参数
const int maxVal = 255;
int low_threshold=150;
int high_threshold=210;
Mat temp1, temp2, resImg;
//小阈值操作
threshold(srcImg, temp1, low_threshold, maxVal, THRESH_BINARY);
//大阈值操作
threshold(srcImg, temp2, high_threshold, maxVal, THRESH_BINARY_INV);
//矩阵与运算得到二值化结果
bitwise_and(temp1, temp2, resImg);
……
}