目录
0x01 OTSU
0X02 固定阈值化
0x03 自适应阈值化
0x04 双阈值化
0x05 半阈值化
在图像处理中,处理灰度图像的计算量要小于处理彩色图像,而二值化图像(只含灰度值0或1)的计算复杂度更优于以上两者,因此二值化操作在数字图像处理中有着不可或缺的实用价值。一幅图像包括目标、背景以及噪声,想要直接提取出目标物体,通常是采用灰度变换阈值化操作。
图像的阈值化操作就是利用图像像素点分布的规律,设定阈值进行像素点分割,进而得到图像的二值化图像。
图像阈值化操作:
OTSU
固定阈值
自适应阈值
双阈值
半阈值化
算法步骤:
统计灰度级中每个像素在整幅图像中的个数。
计算每个像素在整幅图像的概率分布。
对灰度级进行遍历搜索,计算当前灰度值下前景背景类间概率。
通过目标函数计算出类内与类间方差下对应的阈值。
int OTSU(const cv::Mat& image)
{
int nCols = image.cols;
int nRows = image.rows;
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 < nCols; i++)
{
for (int j = 0; j < nRows; j++)
{
nSumPix[(int)image.at(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)
{
//当前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 ostuThreshold = OTSU(image_reduced);
cv::Mat otsuResultImage(304,304,CV_8UC1);
cv::threshold(image_reduced, otsuResultImage, ostuThreshold, 255, cv::THRESH_BINARY);
cv::imshow("OTSU", otsuResultImage);
效果:
Opencv提供了阈值化函数threshold,对应5种阈值化类型参数:
cv::threshold(src, //源图像数组
dst, //输出图像数组
thresh, //阈值
maxval, //阈值设置
type); //阈值化处理的类型设置
Threshold函数应用在单通道图像中固定阈值化处理,通常是为了得到二值化灰度图像(只包含0或1灰度值)或为了去除噪声。参数类型:
(1)THRESH_BINARY 二进制阈值化
对8位灰度图应用该阈值进行操作时,预先设定好特定的阈值量thresh。阈值化操作只需要将大于thresh的灰度值设定为255,将低于thresh的灰度值设定为0:
(2)THRESH_BINARY_INV 反二进制阈值化
对8位灰度图应用该阈值进行操作时,预先设定好特定的阈值量thresh,阈值化操作只需要将大于thresh的灰度值设定位0,将不大于thresh的灰度值设定位255:
(3)THRESH_TRUNC截断阈值化
对8位灰度图应用该阈值进行操作时,预先设定好特定的阈值量thresh,阈值化操作只需要将大于thresh的灰度值设定为threshold,将低于thresh的灰度值设定为不变。
(4)THRESH_TOZERO阈值化为0
对8位灰度图应用该阈值进行操作时,预先设定好特定的阈值量thresh,阈值化操作只需要将大于thresh的灰度值设定为不变,将低于thresh的灰度值设定为0。
(5)THRESH_TOZERO_INV反阈值化为0
对8位灰度图应用该阈值进行操作时,预先设定后特定的阈值量是thresh,阈值化操作只需要将大于thresh的灰度值设定为0,将低于thresh的灰度值设定为不变。
在图像阈值化操作中,我们更官辛的是从二值化图像中分离目标区域和背景区域,仅仅提供给定一个固定的阈值是难以达到理想的分割效果的。
在实际应用中,目标及背景区域通常相互依存在图像块中,我们可以通过图像像素领域块的分特征来自适应来确定区域的二值化阈值。对于图像块中亮度变化明显的区域,自适应阈值通常会设置为较大或较小,进而保证图像中各个像素的阈值都会随着周围领域块的变化而变化。
void adaptiveThreshold(InputArray src, //源图像数组
OutputArray dst, //输出图像数组
double maxValue, //预设满足条件的最大值
int adaptiveMethod, //算法选择
int thresholdType, //阈值类型
int blockSize, //领域块的大小
double C) //从均值或加权均值提取的常数,可以是负数
使用可以如下:
//初始化自适应阈值参数
int blockSize = 5;
int constValue = 20;
const int maxVal = 255;
cv::Mat image_adaptive(304, 304, CV_8UC1);
cv::adaptiveThreshold(image_reduced, image_adaptive, maxVal,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,blockSize,constValue);
对于图像中国有明显的双分界线特征,需要考虑使用双阈值法来进行二值化操作。
对8位灰度图应用该阈值化方法进行操作时,预先设定好特定的阈值量thresh1、thresh2,且thresh1
双阈值化中的两个阈值可以根据实际场景需求进行设置。其中maxval可以为一个固定值,通常情况下8位无符号图像设置为最大灰度值255,双阈值化操作:
其实说白了就是给定一个阈值范围,在这个范围内确定黑白:
cv::Mat DualThreshold(const cv::Mat& image,int maxval,int low_threshold,int high_threshold)
{
cv::Mat dstTempImage1, dstTempImage2, dstImage;
//小阈值对源灰度图像进行阈值化操作
cv::threshold(image,dstTempImage1,low_threshold,maxval,cv::THRESH_BINARY);
//大阈值对源灰度图像进行阈值化操作
cv::threshold(image,dstTempImage2,high_threshold,maxval,cv::THRESH_BINARY_INV);
//矩阵与运算可得二值化结果
cv::bitwise_and(dstTempImage1,dstTempImage2,dstImage);
return dstImage;
}
对于图像中有明显得目标与背景差异特征,如手写体字符分割与识别,我们可以考虑用半阈值法进行阈值化操作。
原理:预先设定好阈值量thresh,版阈值化操作只需要将大于thresh的灰度值设定为不变,将其余情况设定为0。
为什么要使用半阈值化?
图像半阈值化操作应用于字符分割领域,对字符区域进行分割,一般阈值化方法会倒是字符间存在粘连或漏空,给字符特征提取带来诸多难题,而图像半阈值化操作有利于保存字符间的边界信息,可有效实现粘连字符的分割。
实现:
cv::Mat HalfThresh(const cv::Mat& image,int maxval,int thresholdval)
{
cv::Mat dstTempImage, dstImage;
//阈值对源灰度图像进行阈值化操作
cv::threshold(image,dstTempImage,thresholdval,255,cv::THRESH_BINARY);
//矩阵与运算
cv::bitwise_and(image,dstTempImage,dstImage);
return dstImage;
}