在对图像的分割中,阈值化是最简单的图像分割的方法。比如我们从一副图像中利用阈值分割出我们需要的物体部分(当然这里的物体可以是一部分或者整体)。这样的图像分割方法是基于图像中物体与背景之间的灰度差异,而且此分割属于像素级的分割。为了从一副图像中提取出我们需要的部分,应该用图像中的每一个像素点的灰度值与选取的阈值进行比较,并作出相应的判断。(注意:阈值的选取依赖于具体的问题。即:物体在不同的图像中有可能会有不同的灰度值。一旦找到了需要分割的物体的像素点,我们可以对这些像素点设定一些特定的值来表示。(例如:可以将该物体的像素点的灰度值设定为:‘0’(黑色),其他的像素点的灰度值为:‘255’(白色);当然像素点的灰度值可以任意,但最好设定的两种颜色对比度较强,方便观察结果)。
OpenCV中提供了阈值(threshold)函数: threshold 。这个函数有5种阈值化类型,在接下来具体介绍。为了解释阈值分割的过程,我们来看一个简单有关像素灰度的图片,该图如下。该图中的蓝色水平线代表着具体的一个阈值。
解释:同样首先需要选定一个阈值,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变。(例如:阈值选取为125,那小于125的阈值不改变,大于125的灰度值(230)的像素点就设定为该阈值)。
解释:先选定一个阈值,然后对图像做如下处理:1 像素点的灰度值大于该阈值的不进行任何改变;2 像素点的灰度值小于该阈值的,其灰度值全部变为0。
解释:原理类似于0阈值,但是在对图像做处理的时候相反,即:像素点的灰度值小于该阈值的不进行任何改变,而大于该阈值的部分,其灰度值全部变为0。
/*【threshold ( )函数源代码】*********************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)
* @源码路径:…\opencv\sources\modules\imgproc\src\ thresh.cpp
* @起始行数:1186行
********************************************************************************/
double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double maxval, int type )
{
CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
ocl_threshold(_src, _dst, thresh, maxval, type), thresh)
Mat src = _src.getMat();
int automatic_thresh = (type & ~CV_THRESH_MASK);
type &= THRESH_MASK;
CV_Assert( automatic_thresh != (CV_THRESH_OTSU | CV_THRESH_TRIANGLE) );
if( automatic_thresh == CV_THRESH_OTSU )
{
CV_Assert( src.type() == CV_8UC1 );
thresh = getThreshVal_Otsu_8u( src );
}
else if( automatic_thresh == CV_THRESH_TRIANGLE )
{
CV_Assert( src.type() == CV_8UC1 );
thresh = getThreshVal_Triangle_8u( src );
}
_dst.create( src.size(), src.type() );
Mat dst = _dst.getMat();
if( src.depth() == CV_8U )
{
int ithresh = cvFloor(thresh);
thresh = ithresh;
int imaxval = cvRound(maxval);
if( type == THRESH_TRUNC )
imaxval = ithresh;
imaxval = saturate_cast(imaxval);
if( ithresh < 0 || ithresh >= 255 )
{
if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < 0) ||
(type == THRESH_TOZERO && ithresh >= 255) )
{
int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) :
type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
/*type == THRESH_TRUNC ? imaxval :*/ 0;
dst.setTo(v);
}
else
src.copyTo(dst);
return thresh;
}
thresh = ithresh;
maxval = imaxval;
}
else if( src.depth() == CV_16S )
{
int ithresh = cvFloor(thresh);
thresh = ithresh;
int imaxval = cvRound(maxval);
if( type == THRESH_TRUNC )
imaxval = ithresh;
imaxval = saturate_cast(imaxval);
if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX )
{
if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < SHRT_MIN) ||
(type == THRESH_TOZERO && ithresh >= SHRT_MAX) )
{
int v = type == THRESH_BINARY ? (ithresh >= SHRT_MAX ? 0 : imaxval) :
type == THRESH_BINARY_INV ? (ithresh >= SHRT_MAX ? imaxval : 0) :
/*type == THRESH_TRUNC ? imaxval :*/ 0;
dst.setTo(v);
}
else
src.copyTo(dst);
return thresh;
}
thresh = ithresh;
maxval = imaxval;
}
else if( src.depth() == CV_32F )
;
else
CV_Error( CV_StsUnsupportedFormat, "" );
parallel_for_(Range(0, dst.rows),
ThresholdRunner(src, dst, thresh, maxval, type),
dst.total()/(double)(1<<16));
return thresh;
}
threshold 方法是通过遍历灰度图中点,将图像信息二值化,处理过后的图片只有二种色值。
其函数原型如下:
C++: double threshold(InputArray src,
OutputArray dst,
double thresh,
double maxVal,
int thresholdType)
【参数】
第一个参数,InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可。
第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第一个参数中的Mat变量有一样的尺寸和类型。
第三个参数,double类型的thresh,阈值的具体值。
第四个参数,double类型的maxval,当第五个参数阈值类型type取 THRESH_BINARY 或THRESH_BINARY_INV阈值类型时的最大值.
第五个参数,int类型的type,阈值类型。其它参数很好理解,我们来看看第五个参数,第五参数有以下几种类型
0: THRESH_BINARY 当前点值大于阈值时,取Maxval,也就是第四个参数,下面再不说明,否则设置为0
1: THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval
2: THRESH_TRUNC 当前点值大于阈值时,设置为阈值,否则不改变
3: THRESH_TOZERO 当前点值大于阈值时,不改变,否则设置为0
4: THRESH_TOZERO_INV 当前点值大于阈值时,设置为0,否则不改变
/*【adaptiveThreshold ( )函数源代码】**************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)
* @源码路径:…\opencv\sources\modules\imgproc\src\ thresh.cpp
* @起始行数:1276行
********************************************************************************/
void cv::adaptiveThreshold( InputArray _src, OutputArray _dst, double maxValue,
int method, int type, int blockSize, double delta )
{
Mat src = _src.getMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
Size size = src.size();
_dst.create( size, src.type() );
Mat dst = _dst.getMat();
if( maxValue < 0 )
{
dst = Scalar(0);
return;
}
Mat mean;
if( src.data != dst.data )
mean = dst;
if( method == ADAPTIVE_THRESH_MEAN_C )
boxFilter( src, mean, src.type(), Size(blockSize, blockSize),
Point(-1,-1), true, BORDER_REPLICATE );
else if( method == ADAPTIVE_THRESH_GAUSSIAN_C )
GaussianBlur( src, mean, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE );
else
CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive threshold method" );
int i, j;
uchar imaxval = saturate_cast(maxValue);
int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
uchar tab[768];
if( type == CV_THRESH_BINARY )
for( i = 0; i < 768; i++ )
tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
else if( type == CV_THRESH_BINARY_INV )
for( i = 0; i < 768; i++ )
tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
else
CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" );
if( src.isContinuous() && mean.isContinuous() && dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
for( i = 0; i < size.height; i++ )
{
const uchar* sdata = src.ptr(i);
const uchar* mdata = mean.ptr(i);
uchar* ddata = dst.ptr(i);
for( j = 0; j < size.width; j++ )
ddata[j] = tab[sdata[j] - mdata[j] + 255];
}
}
CV_IMPL double
cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst;
CV_Assert( src.size == dst.size && src.channels() == dst.channels() &&
(src.depth() == dst.depth() || dst.depth() == CV_8U));
thresh = cv::threshold( src, dst, thresh, maxval, type );
if( dst0.data != dst.data )
dst.convertTo( dst0, dst0.depth() );
return thresh;
}
函数原型:
C++: void adaptiveThreshold(InputArray src,
OutputArray dst,
double maxValue,
int adaptiveMethod,
int thresholdType,
int blockSize, double C)
C: void cvAdaptiveThreshold(const CvArr* src,
CvArr* dst,
double max_value,
int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C,
int threshold_type=CV_THRESH_BINARY,
int block_size=3,
double param1=5 )
【参数】
第一个参数,src – Source 8-bit single-channel image.
第二个参数,dst – Destination image of the same size and the same type as src .
第三个参数,maxValue – Non-zero value assigned to the pixels for which the condition is satisfied. See the details below.
第四个参数adaptiveMethod – Adaptive thresholding algorithm to use, ADAPTIVE_THRESH_MEAN_C or ADAPTIVE_THRESH_GAUSSIAN_C . See the details below.
第五个参数,thresholdType – Thresholding type that must be either THRESH_BINARY or THRESH_BINARY_INV .
第六个参数,blockSize – Size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on.
第七个参数,C – Constant subtracted from the mean or weighted mean (see the details below). Normally, it is positive but may be zero or negative as well.
The function transforms a grayscale image to a binary image according to the formulae:(第五个参数)
THRESH_BINARY
where T(x,y) is a threshold calculated individually for each pixel.
For the method ADAPTIVE_THRESH_MEAN_C , the threshold value is a mean of the neighborhood of minus C .
For the method ADAPTIVE_THRESH_GAUSSIAN_C , the threshold value is a weighted sum (cross-correlation with a Gaussian window) of the neighborhood of minus C . The default sigma (standard deviation) is used for the specified blockSize . See getGaussianKernel() .
代码参看附件【demo1】
参考:
英文:https://docs.opencv.org/master/db/d8e/tutorial_threshold.html
中文:
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/threshold/threshold.html#basic-threshold
请点击参考链接
【注意】博主在附件中的代码只有Linux版本的,如何使用Windows使用该代码请参看博主的另一篇博文
Opencv环境搭建(Visual Studio+Windows)- 请点击
有任何问题请联系博主。