adaptiveThreshold自适应二值化源码分析

来源:互联网 发布:hive sql union 编辑:程序博客网 时间:2024/06/05 09:03
自适应二值化介绍:二值化算法是用输入像素的值I与一个值C来比较,根据比较结果确定输出值。自适应二值化的每一个像素的比较值C都不同,比较值C由这个像素为中心的一个块范围计算在减去差值delta得到。C的常用计算方法有两种:  1.平均值减去差值delta(使用盒过滤boxfilter,性能会非常不错)  2.高斯分布加权和减去差值delta (使用高斯滤波GaussionBlur)  只要高兴用什么其他方法都行。最后,总算法就是用每一个像素的灰度值I,与所对应的比较值C,确定结果输出到对应的像素。 举个例子:如果使用平均值方法,平均值mean为190,差值delta为30。那么灰度小于160的像素为0,大于等于160的像素为255。如下图:如果是反向二值化,如下图:delta选择负值也是可以的。 opencv中adaptiveThreshold函数分析:参数:  _src      要二值化的灰度图  _dst      二值化后的图  maxValue  二值化后要设置的那个值  method   块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)  type      二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)  blockSize  块大小(奇数,大于1)  delta     差值(负值也可以)源码和注释如下:复制代码/** @brief 自适应二值化*@param _src     要二值化的灰度图*@param _dst     二值化后的图*@param maxValue    二值化后要设置的那个值*@param method 块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)*@param type     二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)*@param blockSize    块大小(奇数,大于1)*@param delta 差值(负值也可以)*/void cv::adaptiveThreshold(InputArray _src, OutputArray _dst, double maxValue,    int method, int type, int blockSize, double delta){    Mat src = _src.getMat();    // 原图必须是单通道无符号8位    CV_Assert(src.type() == CV_8UC1);    // 块大小必须大于1,并且是奇数    CV_Assert(blockSize % 2 == 1 && blockSize > 1);    Size size = src.size();    // 构建与原图像相同的图像    _dst.create(size, src.type());    Mat dst = _dst.getMat();    if (maxValue < 0)    {        // 二值化后值小于0,图像都为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;    // 将maxValue夹到[0,255]的uchar范围区间,用作二值化后的值    uchar imaxval = saturate_cast<uchar>(maxValue);    // 根据二值化类型计算delta值    int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);    // 计算生成每个像素差对应的值表格,以后查表就可以。但像素差范围为什么是768,我确实认为512已经够了    uchar tab[768];    if (type == CV_THRESH_BINARY)        for (i = 0; i < 768; i++)            // i = src[j] - mean[j] + 255            // i - 255 > -idelta ? imaxval : 0            // = src[j] - mean[j] + 255 -255 > -idelta ? imaxval : 0            // = src[j] > mean[j] - idelta ? imaxval : 0            tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);    else if (type == CV_THRESH_BINARY_INV)        for (i = 0; i < 768; i++)            // i = src[j] - mean[j] + 255            // i - 255 <= -idelta ? imaxval : 0            // = src[j] - mean[j] + 255 - 255 <= -idelta ? imaxval : 0            // = src[j] <= mean[j] - idelta ? imaxval : 0            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;    }    // 逐像素计算src[j] - mean[j] + 255,并查表得到结果    for (i = 0; i < size.height; i++)    {        const uchar* sdata = src.data + src.step*i;        const uchar* mdata = mean.data + mean.step*i;        uchar* ddata = dst.data + dst.step*i;        for (j = 0; j < size.width; j++)            // 将[-255, 255] 映射到[0, 510]然后查表            ddata[j] = tab[sdata[j] - mdata[j] + 255];    }}