精华内容
下载资源
问答
  • 源代码在opencv库里面的cvboost.cpp文件里面,该宏的总体思路是通过定义带参数的宏,把参数传递给宏内部的函数,然后进行一系列的计算,并最终根据一定的算法找到合适的阈值。具体解析如下: #define ICV_DEF_FIND_...

    源代码在opencv库里面的cvboost.cpp文件里面,宏ICV_DEF_FIND_STUMP_THRESHOLD( suffix, type, error )的总体思路是通过定义带参数的宏,把参数传递给宏内部的函数,然后进行一系列的计算,并最终根据一定的算法找到合适的阈值。具体解析如下:

    #define ICV_DEF_FIND_STUMP_THRESHOLD( suffix, type, error )                              \
    static int icvFindStumpThreshold_##suffix(                                               \
            uchar* data, size_t datastep, //训练样本的  特征-样本数据                        \
            uchar* wdata, size_t wstep, //wdata是样本的权重矩阵                               \
            uchar* ydata, size_t ystep, //ydata是样本的类别矩阵                               \
            uchar* idxdata, size_t idxstep, int num, //idxdata是样本根据特征值大小排序后的索引数据,样本按照特征值的大小升序排列  \
            float* lerror, //左边不纯度                                                       \
            float* rerror, //右边不纯度                                                       \
            float* threshold, float* left, float* right,                                     \
            float* sumw, float* sumwy, float* sumwyy )                                       \
    {                                                                                        \
        int found = 0;                                                                       \
        float wyl  = 0.0F;                                                                   \
        float wl   = 0.0F;                                                                   \
        float wyyl = 0.0F;                                                                   \
        float wyr  = 0.0F;                                                                   \
        float wr   = 0.0F;                                                                   \
                                                                                             \
        float curleft  = 0.0F;                                                               \
        float curright = 0.0F;                                                               \
        float* prevval = NULL;                                                               \
        float* curval  = NULL;                                                               \
        float curlerror = 0.0F;                                                              \
        float currerror = 0.0F;                                                              \
                                                                                             \
        int i = 0;                                                                           \
        int idx = 0;                                                                         \
                                                                                             \
        if( *sumw == FLT_MAX )                                                               \
        {                                                                                    \
            /* calculate sums */                                                             \
            float *y = NULL;                                                                 \
            float *w = NULL;                                                                 \
            float wy = 0.0F;                                                                 \
                                                                                             \
            *sumw   = 0.0F;                                                                  \
            *sumwy  = 0.0F;                                                                  \
            *sumwyy = 0.0F;                                                                  \
            for( i = 0; i < num; i++ )                                                       \
            {                                                                                \
                idx = (int) ( *((type*) (idxdata + i*idxstep)) );//根据样本的数据和step确定其样本索引序号idx  \
                w = (float*) (wdata + idx * wstep);                                          \
                *sumw += *w;                        //计算权重和                              \
                y = (float*) (ydata + idx * ystep);                                          \
                wy = (*w) * (*y);                   //计算权重w和类别y的乘积                  \
                *sumwy += wy;                                                                \
                *sumwyy += wy * (*y);                                                        \
            }                                                                                \
        }                                                                                    \
                                                                                             \
        for( i = 0; i < num; i++ )                                                           \
        {                                                                                    \
            idx = (int) ( *((type*) (idxdata + i*idxstep)) );                                \
            curval = (float*) (data + idx * datastep);                                       \
             /* for debug purpose */                                                         \
            if( i > 0 ) assert( (*prevval) <= (*curval) );                                   \
                                                                                             \
            wyr  = *sumwy - wyl;//计算在当前特征值以前的去除重复的特征值后的权重和类别乘积和\
            wr   = *sumw  - wl;  //计算在当前特征值以前的去除重复的特征值后的权重和          \
                                                                                             \
            if( wl > 0.0 ) curleft = wyl / wl;    //在剔除出有相同特征值的样本中,计算正样本比重(因为负样本的类别为0)\
            else curleft = 0.0F;                                                             \
                                                                                             \
            if( wr > 0.0 ) curright = wyr / wr;   //在未剔除出的样本中,计算正样本的权重和比重 \
            else curright = 0.0F;                                                            \
                                                                                             \
            error                                                                            \
                                                                                             \
            if( curlerror + currerror < (*lerror) + (*rerror) )//如果当前的不纯度和小于原来的不纯度和\
            {                                                                                \
                (*lerror) = curlerror;                                                       \
                (*rerror) = currerror;                                                       \
                *threshold = *curval;                                                        \
                if( i > 0 ) {   
    /************************树桩分类器的阈值:0.5*(当前特征值值与前一个特征值的和)*************************/               
                    *threshold = 0.5F * (*threshold + *prevval); //阈值的大小为0.5*(当前特征值值与前一个特征值的和)  \
                }                                                                            \
                *left  = curleft;//树桩分类器的左边的返回值                                   \
                *right = curright;//树桩分类器右边的返回值                                    \
                found = 1;                                                                   \
            }                                                                                \
                                                                                             \
            do                                                                               \
            {   //在计算参数时,也就是计算与当前特征值重复的特征值的相关参数                 \
                wl  += *((float*) (wdata + idx * wstep));                                    \
                wyl += (*((float*) (wdata + idx * wstep)))                                   \
                    * (*((float*) (ydata + idx * ystep)));                                   \
                wyyl += *((float*) (wdata + idx * wstep))                                    \
                    * (*((float*) (ydata + idx * ystep)))                                    \
                    * (*((float*) (ydata + idx * ystep)));                                   \
            }                                                                                \
            while( (++i) < num &&                                                            \
                ( *((float*) (data + (idx =                                                  \
                    (int) ( *((type*) (idxdata + i*idxstep))) ) * datastep))                 \
                    == *curval ) );
       /*
        *do-while作用:计算与当前重复特征值的wl,wyl,wyyl。
        *while括号里的含义是当i<num时,并且idxdata中的第++i个特征值与当前的特征值相等时,就执行
        *do-while循环里的内容。对于同一个特征值,如果做阈值的话,对于分类结果只能是同一种情况
        *,所以要跳过对同一个相等的特征值来确定阈值的情况,另一个作用是这样也无形中加快了训练
        *过程。
        */
                                                                                             \
            --i;                                                                             \
            prevval = curval;  //把当前特征值变成前一个,依次遍历所有的特征值,并最终选择一个最优的阈值 \
        } /* for each value */                                                               \
                                                                                             \
        return found;                                                                        \
    } 
    


    展开全文
  • 在opencv中,强分类阈值确定实在函数icvCreateCARTStageClassifier中,具体强分类器的阈值的求解方式和虚警率的计算如下 CvIntHaarClassifier* icvCreateCARTStageClassifier( CvHaarTrainingData* data, // ...

    在opencv中,强分类器阈值的确定实在函数icvCreateCARTStageClassifier中,具体强分类器的阈值的求解方式和虚警率的计算如下

    CvIntHaarClassifier* icvCreateCARTStageClassifier(
           CvHaarTrainingData* data,        // 训练样本数据,包括图片的大小,数量,积分图,权重,类别等数据
           CvMat* sampleIdx,                // 训练样本序列,不一定与积分图的顺序一致
           CvIntHaarFeatures* haarFeatures, // 全部HAAR特征
           float minhitrate,                // 最小正检率
           float maxfalsealarm,             // 最大误检率          
           int   symmetric,                 // HAAR特征是否对称
           float weightfraction,            // 样本剔除比例(用于剔除小权值样本,以加快训练速度)
           int numsplits,                   // 每个弱分类器特征个数(一般为1)
           CvBoostType boosttype,           // adaboost类型,一般使用的是DAB
           CvStumpError stumperror,         // Discrete AdaBoost(DAB)中的阈值计算方式
           int maxsplits )                  // 弱分类器最大个数
    {
                   .................
            
    
            //我把上面强分类器的count个弱分类器的求解省略了
        
            numpos = 0;  //在data中正样本的数量对于程序来说是不知道的,那就需要在程序中求出
      
             /*确定强分类器的阈值threshold
              *遍历sampleIdx中所有样本,但是只需计算每个正样本的弱分类器置信度和,具体来说,
              *也就是,对于每个正样本,遍历上面求出的所有求出count(在这里是seq->total)个
              *弱分类器的置信度并求和,这样共得到numpos个正样本的置信度和,把他们升序排列,
              *然后就可以求阈值了,阈值为:
              *threshold = eval.data.fl[(int) ((1.0F - minhitrate) * numpos)]。
              *这个阈值的含义是根据需要的最小击中率,可以先求出正样本的漏检率,然后乘以正样
              *本的数量,这个值转化为int型,就是正样本中漏检的数量,那么对于上面刚排好序第几
              *个正样本的弱分类器的置信度和。
              */
            for( i = 0; i < numsamples; i++ )  
            {  
                // 获得样本序号,可能与积分图中样本顺序不一致,所以要求出其序号  
                idx = icvGetIdxAt( sampleIdx, i );  
      
                // 如果样本为正样本  
                if( data->cls.data.fl[idx] == 1.0F )  
                {  
                    // 初始化置信度值  
                    eval.data.fl[numpos] = 0.0F;  
      
                    // 遍历seq中所有弱分类器  
                    for( j = 0; j < seq->total; j++ )  
                    {  
                        // 获取弱分类器  
                        classifier = *((CvCARTHaarClassifier**) cvGetSeqElem( seq, j ));  
      
                        // 累积当前正样本的弱分类器置信度和  
                        eval.data.fl[numpos] += classifier->eval(   
                            (CvIntHaarClassifier*) classifier,  
                            (sum_type*) (data->sum.data.ptr + idx * data->sum.step),  
                            (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),  
                            data->normfactor.data.fl[idx] );  
                    }  
                    /* eval.data.fl[numpos] = 2.0F * eval.data.fl[numpos] - seq->total; */  
                    numpos++;  
                }  
            }  
      
            // 对弱分类器输出置信度和进行排序  
            icvSort_32f( eval.data.fl, numpos, 0 );  
      
            // 计算阈值,应该是大于threshold则为正类,小于threshold则为负类  
            threshold = eval.data.fl[(int) ((1.0F - minhitrate) * numpos)];  
      
            numneg = 0;  
            numfalse = 0;  
      
             /*确定强分类器的虚警率falsealarm
              *遍历sampleIdx中所有样本,但是只需计算每个负样本的弱分类器置信度和,具体来说,
              *也就是,对于每个负样本,遍历上面求出的所有求出count(在这里是seq->total)个
              *弱分类器的置信度并求和,然后和上面所求强分类器的阈值相比较,即:
              *if( sum_stage >= (threshold - CV_THRESHOLD_EPS) )  
                    {  
                        numfalse++;  
                    }  
              *这样就可以计算出被分类错误的负样本的数量了
              */
            for( i = 0; i < numsamples; i++ )  
            {  
                idx = icvGetIdxAt( sampleIdx, i );  
      
                // 如果样本为负样本  
                if( data->cls.data.fl[idx] == 0.0F )  
                {  
                    numneg++;  
                    sum_stage = 0.0F;  
      
                    // 遍历seq中所有弱分类器  
                    for( j = 0; j < seq->total; j++ )  
                    {  
                       classifier = *((CvCARTHaarClassifier**) cvGetSeqElem( seq, j ));  
      
                       // 累积当前负样本的分类器输出结果  
                       sum_stage += classifier->eval( (CvIntHaarClassifier*) classifier,  
                            (sum_type*) (data->sum.data.ptr + idx * data->sum.step),  
                            (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),  
                            data->normfactor.data.fl[idx] );  
                    }  
                    /* sum_stage = 2.0F * sum_stage - seq->total; */  
      
                    // 因为小于threshold为负类,所以下面是分类错误的情况  
                    if( sum_stage >= (threshold - CV_THRESHOLD_EPS) )  
                    {  
                        numfalse++;  
                    }  
                }  
            }  
      
            // 计算虚警率  
            falsealarm = ((float) numfalse) / ((float) numneg);  
    
    
                         ...............
    
    }
    

    
    

    展开全文
  • // 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用...当然,如果是对图像中的某一类型进行区域生长可能更容易一些个人理解区域生长算法需要确定一个阈值,这个值代表同一类图像信息灰度值...

    // 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用,请标明出处:https://www.cnblogs.com/lv-anchoret/

    今天我们来介绍用C++算法如何来实现图像分割算法中的区域生长算法

    我们解决的是对一整张图像所有内容进行区域生长分类,当然,如果是对图像中的某一类型进行区域生长可能更容易一些

    个人理解

    区域生长算法需要确定一个阈值,这个值代表同一类图像信息灰度值的差值,比如,我要一个人脸图(假设眼睛是蓝色的),头发是黑色的但是不同光线反射原因或者位置不同,图像中显示的灰度颜色值有5、10、3等,虽然灰度值不一样,但是他们代表的都是黑色,都是头发,区域生长,就是把这些相似灰度值的一类事物统一标注显示,这也就达到了分类识别的目的,关于阈值,比如上述的头发,我们需要将所有是头发的像素点都标注出来,那么我们的阈值就应该设置为10,如果设置为3,可能灰度值为3和5的点会统一识别,但是10就被排除在外了。

    算法核心就是一个bfs,设立一个种子点,向四周扩张,如果相邻的点的灰度值相对于种子点在阈值范围之内,那么,我们把它识别并包含统一进来,扩张完毕之后,所有相似的一类图像将被统一标注。

    关于标注我们还需要说一下,一开始,想起了四色定理,即用四种颜色就可以吧整个地图分类标注且相邻类别颜色不同,后来想了想还不如把同一类型区域中的所有点都设置为种子点灰度像素值。

    之后想起来我们光线追踪一直用的ppm彩色文件格式,索性将灰度值转成rgb彩色图看着更爽

    区域生长算法流程

    1. 找种子点

    2. 扩张原则

    3. 终止条件

    数据介绍

    我们的数据是一张灰度图 : 见 纹理相册夹中的第二张图

    我们处理输出的是一张彩色图像,图像格式是我们光线追踪的文件格式 .ppm,用我们光线追踪的图片解析器(ppmviewer)就能打开(没有的也没关系,搜索一下,下载不超过十几秒,超轻量级ppm解读器)

    我们都知道,C/C++ 中读取图像麻烦,特别是这种.jpg复杂格式数据,所以,我们用matlab先把图像读出来,输出到一个TXT中,存储为二维矩阵形式,然后用C++代码读取TXT文件内容,存储到一个二维数据序列中。(都有代码在后面)

    我们侧重实现算法本身,所以关于图像的读取和写入我们不做过多描述

    算法介绍

    算法自命名:首次左上区域生长算法

    时间复杂度:O(图像大小*种子数量*log(种子数量))

    一、区域生长的三大要素确立:

    (1)生长合并规则:

    用户自定义阈值,根据种子点和当前点的差值,如果在阈值之内,那么合并,将当前点的灰度值设为种子灰度值

    (2)种子选取:

    将图像左上角第一个点作为第一个种子,在扩张的过程中第一个不符合生长合并规则的位置,作为下一次生长的种子,即首次选定,后期自适应确定。

    (3)算法结束:

    种子为空

    二、优缺点

    该算法的优点:  针对大型全局生长而衍生

    该算法种子不会将同一个位置作为种子多次重复生长(时间空间复杂度优化)

    某个种子在开始生长时,如果已经被包含于另一个种子的生长区域中,那么该种子将不会进行生长(时间复杂度优化)

    该算法的缺点:  首次选定法不能用合适的灰度代表整个区域,只能是坐标小的点的灰度值

    生长出来的区域可能不是很完美,因为该区域是由该区域坐标最小的点生长而成的。

    三、灰度值转rgb算法设计

    因为要将单一的灰度值映射到r、g、b,使其代表的颜色具有独特性

    这个可以自己设计,我的设计如下:

    四、构架设计

    含有一个类 —— regional

    数据成员

    _img:用于存储图像灰度矩阵

    reset:用于记录某个位置的灰度是否被重置

    _delt:阈值

    成员函数

    readfile:读图像灰度矩阵文件

    bfs:进行区域生长

    out:输出处理后的图像灰度矩阵

    readout:读取处理后的图像灰度矩阵文件

    gograph:将灰度图像转为rgb图像,由于ppmview显示空间有限,所以将此图划分为6块(将原图像分为3行2列的6块),分别输出6个图像

    流程图如下:

    五、数据结构设计:(C++描述)

    用bfs算法进行的话,必然需要队列,但是种子们不能用队列去存,某个种子进行生长的时候可以用队列记录每一个生长状态

    此法采用8领域进行生长

    用队列存储当前种子生长过程中的状态点,进行bfs扩展,确定该种子生长所形成的区域

    用set容器存储各个种子,保证了种子点唯一性,即优点2,同时,set容器还会根据位置自动排序,所以导致了缺点2,其次,set容器的存取操作的时间复杂度均为O(n log n)

    Bfs状态采用只包含x、y坐标的一个结构体

    六、效果与讨论

    采用C++描述的首次左上区域生长算法针对2012*1881的灰度卫星图像矩阵数据处理时间为:78.9s

    阈值为20

    图1

    首先蓝色圈所代表的部分,如果是水域的深浅,那么这一块还是被划分的很清楚的,大致分了5部分

    再看下阈值为25的图

    图2

    如我们所预期的那样,图1中蓝色圈的水深划分等级更少了

    其次,我们看图1的红色圈代表的水体,内部中间划分出来的区域更小了,或者说水体的边缘区域扩张了。

    再如,黑色圈代表的水域,中间的黑色圈有一块东西,它的区域更小了,不利于捕捉细微的水内状况

    如果图1的黑色内的小黑圈部分看不太清楚,那么可以看一下下面这个,都是一样的

    XnView打开效果

    图3

    如果把黄色部分看做是竖着的地质锤,那么图2显然少了锤头~

    还有水边一片房子聚集地,也被基本划分为一种色调

    图4

    而针对下图以及图4以及原图上方一片森林山脉,将各种处理方法进行叠加,效果可能会更好,方案如下:

    有很多星星点点的噪声,可以选择先去噪声,但是,效果也不是很好

    如果要将其纳入到统一的大片区域中,还是选择先做一个平滑处理,将其尖锐的边缘过渡更加平滑些,再进行区域生长,加以阈值调整,星点可能会减少,可能还存在一些,但是不会那么显眼,和周围环境的色差不会那么大了

    图5

    七、代码

    matlab 代码

    matlab:

    function writetxt

    I= imread('poyanghu.jpg');

    fid= fopen('image.txt','w');

    [x,y]=size(I);

    fprintf(fid,'%d %d\n',x,y);for i = 1:xfor j = 1:y

    fprintf(fid,'%d',I(i,j));

    end

    fprintf(fid,'\n');

    end

    fclose(fid);

    C++:

    regional.h

    //regional.h#pragma once

    namespaceregion

    {

    constexprint dir[8][2]

    {

    {-1,-1},

    {-1, 0},

    {-1, 1},

    {0,-1},

    {0, 1},

    {1,-1},

    {1, 0},

    {1, 1}

    };

    constexpr size_t H= 2012;

    constexpr size_t L= 1881;classregional

    {public:structpos

    {int_x, _y;

    pos(const int a, const intb) :_x(a), _y(b) { }bool operator

    }

    };public:

    regional(constsize_t delt);voidreadfile();voidbfs();void out();voidreadout();void gograph()const;private:short _img[2012 + 1][1881 + 1];bool reset[H + 1][L + 1];

    size_t _delt;

    };

    }

    regional.cpp

    #include "regional.h"#include#include#include#include

    using namespacestd;using namespaceregion;

    regional::regional(constsize_t delt)

    :_delt(delt)

    {

    memset(reset,false, sizeofreset);

    }voidregional::readfile()

    {

    ifstream infile;

    infile.open("image.txt");if (!infile.is_open())

    cerr<< "open failed" <

    infile>> x >>y;for (int i = 1; i <= x; ++i)for (int j = 1; j <= y; ++j)

    infile>>_img[i][j];

    infile.close();

    }voidregional::bfs()

    {

    queueQcurrent;setQnew;

    Qnew.insert(pos(1, 1));while(Qnew.size())

    {

    Qcurrent.push(*Qnew.begin());

    Qnew.erase(Qnew.begin());if (reset[Qcurrent.front()._x][Qcurrent.front()._y])//该种子点已经访问过

    {

    Qcurrent.pop();continue;

    }while(Qcurrent.size())

    {

    pos seed=Qcurrent.front();

    reset[seed._x][seed._y]= true;

    Qcurrent.pop();for (int trans = 0; trans < 8; ++trans)

    {

    pos p(seed._x+ dir[trans][0], seed._y + dir[trans][1]);if (p._x > 0 && p._x <= H && p._y > 0 && p._y <= L && !reset[p._x][p._y])if (abs(_img[p._x][p._y] - _img[seed._x][seed._y]) <_delt>

    {

    _img[p._x][p._y]=_img[seed._x][seed._y];

    reset[p._x][p._y]= true;

    Qcurrent.push(p);

    }elseQnew.insert(p);

    }

    }

    }

    }void regional::out()

    {

    ofstream outfile;

    outfile.open("outall.txt");if (!outfile.is_open())

    cerr<< "open failed" <

    {for (int j = 1; j <= L; ++j)

    outfile<< _img[i][j] << " ";

    outfile<

    }

    outfile.close();

    }voidregional::readout()

    {

    ifstream infile("outall.txt");if (!infile.is_open())

    {

    cerr<< "error open" <

    }for (int i = 1; i <= H; ++i)for (int j = 1; j <= L; ++j)

    infile>>_img[i][j];

    infile.close();

    }void regional::gograph()const{

    ofstream file;

    auto left= [&](intcnt)

    {for (int i = (cnt - 1) * 700 + 1; i <= 700 * cnt; ++i)for (int j = 1; j <= 1000; ++j)

    file<< (int)((0.2 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.5 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.7 + float(_img[i][j] % 10) / 10)*_img[i][j]) <

    };

    auto right= [&](intcnt)

    {for (int i = (cnt - 1) * 700 + 1; i <= 700 * cnt; ++i)for (int j = L - 1000 + 1; j <= L; ++j)

    file<< (int)((0.2 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.5 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.7 + float(_img[i][j] % 10) / 10)*_img[i][j]) <

    };

    file.open("slip1'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    left(1);

    file.close();

    file.open("slip2'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    right(1);

    file.close();

    file.open("slip3'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    left(2);

    file.close();

    file.open("slip4'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    right(2);

    file.close();

    file.open("slip5'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    left(3);

    file.close();

    file.open("slip6'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    right(3);

    file.close();

    }

    main.cpp

    #include "regional.h"

    using namespaceregion;

    #include#include

    #define stds std::

    intmain()

    {

    regional reg(25);

    reg.readfile();

    reg.bfs();

    reg.out();//reg.readout();

    reg.gograph();

    stds cout<< "complished" <

    }

    感谢您的阅读,生活愉快~

    展开全文
  • 一、最大类间方差法 或者 大津法 或者 OTSU 1、简介 最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫...如何确定这个阈值K?算法分类的原理是让背景和目标之间...

    一、最大类间方差法 或者 大津法 或者 OTSU

    1、简介

    最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标两部分,或者说,是寻找一个阈值为K,将图像的颜色分为1,2.....K和K+1.....256两部分。

    如何确定这个阈值K?算法分类的原理是让背景和目标之间的类间方差最大,因为背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,错分的可能性越小。下面进行公式推导:

    2、最大类间方差法推到公式:

    M*N 为一张图像所有的像素点。N1为小于等于当前像素的所有点数目,w1为 小于等于当前像素的所有点数占所有像素点的比。

    N2为大于当前像素点的所有点的数目,w2为 大于当前像素点的所有点的数目的占比。u1 为所有小于等于当前像素点值的和 除上N1,也就是小于等于当前像素值所有数的平均值,u2为大于当前像素所有数的平均值,u为以当前像素为分割点时的期望(平均值),g为方差。


    代码:

    int ThresholdByOtsu( stImage* pImage)           // 最大类间方差法求阈值。
    {
    	int iWidth = pImage->cols;
    	int iHeight = pImage->rows;
    	unsigned char* pGrayImg = pImage->buffer;
    
    	// verify the input parameters
    	if ((pGrayImg == 0) || (iWidth <= 0) || (iHeight <= 0))
    	{
    		return -1;
    	}
    	int thresholdValue = 0; // Threshold
    	int n, n1, n2;
    	double m1, m2, sum, csum, fmax, sb;
    	memset(ihist, 0, sizeof(ihist)); // set ihist[] to zero 
    	n = iHeight*iWidth;
    	sum = csum = 0.0;
    	fmax = -1.0;
    	n1 = 0;
    	// hist generation
    	for (int i = 0; i < iHeight; i++)
    	{
    		for (int j = 0; j < iWidth; j++)
    		{
    			ihist[*pGrayImg]++;         //统计每个像素值的个数。
    			pGrayImg++;
    		}
    	}
    	pGrayImg -= n;                           // 等于 pGrayImg = pImage->buffer;
    	for (int k = 0; k <= 255; k++)
    	{
    		sum += (double)k * (double)ihist[k];         // 像素值乘以当前个数。
    	}
    	// Otsu Algorithm
    	for (int k = 0; k <= 255; k++)
    	{
    		n1 += ihist[k];                                          //n1为小于等于当前像素的个数
    		if (n1 == 0)continue;
    		n2 = n - n1;                                             // n2 为当前当前像素的个数。
    		if (n2 == 0)break;
    
    		csum += (double)k *ihist[k];
    		m1 = csum / n1;         // average level of class 1       // m1 遍历到当前像素值得,平均值水平。
    
    		m2 = (sum - csum) / n2; // average level of class 2        //m2 剩下的(大于当前)像素值的平均值水平。
    
    		sb = (double)n1 *(double)n2 *(m1 - m2) * (m1 - m2);        // 这里虽然是用的n1和n2不是公式中的w1、w2(比重).其实最终相求的,等同于w1、w2都扩大了iHeight*iWidth这么多倍。
    		if (sb > fmax)
    		{
    			fmax = sb;
    			thresholdValue = k;
    		}
    	}
    	return(thresholdValue);
    }

    二、迭代法求图像阈值

    迭代法阈值选择算法是对双峰法的改进,他首先选择一个近似的阈值T,将图像分割成两个部分,R1和R2,计算出区域R1和R2的均值u1和u2,再选择新的

    阈值T=(u1+u2)/2;

    重复上面的过程,知道u1和u2不在变化为止。

    由于迭代法比较易实现,在这就不写代码了。

    三,矩阵区域块自适应阈值(使用积分阈值自适应处理)

     摘要:  图像阈值处理是许多计算机视觉和图形应用中的常见任务。 对图像进行阈值处理的目的是将像素分类为“暗”或“亮”。 自适应阈值处理是一种阈值处理,它考虑了照明的空间变化。 我们提出了一种使用输入的积分图像进行实时自适应阈值处理的技术。 我们的技术是以前方法的扩展。 但是,我们的解决方案对图像中的照明变化更加稳健。 此外,我们的方法简单易行。我们的技术适用于以实时帧速处理实时视频流,使其成为增强现实等交互式应用的有用工具。

    1、简介(introduction)
    图像阈值化基于像素的特定特征(例如强度值)来分割数字图像。目标是创建二值图像,将每个像素分类为两个类别之一,例如“暗”或“亮”。这是许多图像处理应用程序和一些计算机图形应用程序中的常见任务。例如,它通常是基于标记的增强现实系统的第一步[Billinghurstet al。 2001;布拉德利和罗斯2004; Fiala 2005],它已被用于高动态范围摄影[Ward2003]。最基本的阈值处理方法是选择固定的阈值并将每个像素与该值进行比较。这些技术已在许多调查论文中进行了广泛的描述和评估[Weszka andRosenfeld 1978; Palumbo等人。 1986; Sahoo等。 1988;李等人。 1990; Glasbey 1993;特里尔和耆那教1995; Sezginand Sankur 2004]。然而,如果照明在图像中在空间上变化或在视频流中超时,则固定阈值经常失败。

    为了解释照明的变化,常见的解决方案是自适应阈值处理。主要区别在于为图像中的每个像素计算不同的阈值。该技术为照明变化提供了更强大的功能。存在许多自适应阈值方法[White和Rohrer 1983; Bernsen1986;帕克1991; Wellner 1993;杨等人。 1994; Shen和Ip 1997;陈等人。 1998; Savakis 1998; Sauvolaand Pietikainen 2000;杨和燕2000]。进一步的例子和比较可以在[Venkateswarlu andBoyle 1995; Sezgin和Sankur 2004]。我们使用积分图像提出了一种非常简单明了的技术。我们的方法易于实现实时视频流的实时性能。虽然我们的技术是以前方法的扩展[Wellner 1993],但我们增强了强光照变化的稳健性。此外,我们提供清晰整洁的解决方案,而不会增加实施的复杂性。我们的技术也类似于White和Rohrer用于光学字符识别的阈值处理方法[White and Rohrer 1983],但我们提出了一种针对实时视频设计的实现方法。这项工作的动机是找到真正的现实应用程序。 Pintaric还提出了一种适用于增强现实标记的自适应阈值算法[Pintaric 2003],但是他的方法要求在前一帧中定位一个元素,以便技术正确地进行阈值处理。我们的算法不做任何假设,更通用,适合在任何应用中使用。源代码可在本文末尾列出的地址在线获取。

    2、背景 

    2.1实时自适应阈值处理
    在本文中,我们专注于从实时视频流中自适应地阈值化图像。 为了保持实时性能,阈值算法必须限制通过每个图像的迭代次数。 阈值处理通常是一个子任务,它构成了一个更大的过程的一部分。 例如,在增强现实中,必须对输入图像进行分段以定位场景中用于动态建立相机设置的已知标记。 因此,简单快速的自适应阈值技术是一个重要的工具

    2.2积分图像
    积分图像(也称为summed-area table)是一种工具,当我们有一个从像素到数值(比如灰度值)的映射函数f(x, y),并且希望计算一个矩形区域内的函数值的和时,积分图是一个非常高效的工具。已应用积分图像的示例包括纹理映射[Crow 1984],图像中的人脸检测[Viola and Jones 2004]和立体对应[Veksler 2003]。在没有积分图像的情况下,我们计算每个矩形窗口中像素点的映射函数的和,需要通过分别计算每个像素的函数值最后叠加实现。但是,如果我们需要计算多个重叠矩形窗口的总和,为了降低时间复杂度和操作次数,我们可以使用积分图像。

    为了计算积分图像,我们在每个位置I(x,y)存储左边和上面像素(x,y)的所有f(x,y)项的总和。 对于每个像素,使用以下等式在线性时间内完成(考虑边界情况),

    图2(左和中)说明了积分图像的计算。 一旦我们得到积分图像,任何具有左上角(x1,y1)和右下角(x2,y2)的矩形的函数的总和可以使用以下等式计算,计算时间不稳定。

    图2(右)说明使用等式2计算矩形D上的f(x,y)之和相当于计算矩形上的和(A + B + C + D) - (A + B) - (A+ C)+ A。

    图2:积分图像。 左:图像值的简单输入。 中心:计算的积分图像。 右:使用积分图像计算矩形D的总和。

    3、技术                         ----> 这个是最重要的。

        我们的自适应阈值技术是Wellner方法的简单扩展[WELNER 1993 ]。Welnne算法的主要思想是将每个像素与周围像素的平均值进行比较。特别地,在遍历图像时计算了最后一个像素的近似移动平均值。如果当前像素的值比平均值低百分之t,那么它被设置为黑色,否则它被设置为白色。这种方法的工作是将像素与附近像素的平均值进行比较,从而保持硬对比线,忽略软梯度变化。这种方法的优点是只需要遍历一次图像。WELNER使用1/8倍的图像宽度来表示s的值,t=15。然而,这种方法的一个问题是它依赖于像素的扫描顺序。此外,由于邻域样本在各个方向上不均匀分布,所以在使用平均步长并不是一个很好的表现形式。通过使用积分图像(和骶一个额外的迭代通过图像),我们提出了一个解决方案,不遭受这些问题。我们的技术是干净的,直截了当的,易于编码,并产针对不同的处理方式产生生相同的输出。我们不是计算最后看到的s个像素的平均值,而是计算以每个像素为中心的s x s像素窗口的平均值。 这是比较好的平均值,因为它考虑了所有边上的相邻像素。利用积分图像进行平均计算的时间是线性的。我们在第一次遍历图像的时候计算积分图像在第二遍中,我们利用积分图像计算每个像素的s x s的平均值,使用时间为常量,然后进行比较。如果当前像素的值小于这个平均值,则将其设置为黑色,否则它被设置为白色

    代码:

    void AdaptiveThresholdPartOptUsingSram(unsigned char * org_img, unsigned char * new_img, int width, int height, int block, int ratio)
    {
    	//org_img 原图   new_img 二值化后的图   block块略等于1/8宽度 ratio?
    	int S = (block - 1) / 2;//101
    	int T = 20; //15
    	T = (ratio >= 100 || ratio <= 0) ? 20 : ratio;
    
    	int i, j;
    	long sum = 0;
    	int count = 0;
    	int index = 0;
    	int x1, y1, x2, y2;
    	// 计算积分图像    别说积分好不好,挺吓人的,不就是求dp[i][j]吗,dp[i][j] 为从(0,0)为起点到(i,j)为终点的矩形内,所有点之和。
    	Lx_2Row[0][0] = Lx_1Col[0] = org_img[0];
    	// 原来这就是图像积分。
    	for (i = 1; i<width; i++)
    	{
    		Lx_2Row[0][i] = Lx_2Row[0][i - 1] + org_img[i];      // 横向累加  第一行
    	}
    
    	for (j = 1; j<height; j++)
    	{
    		Lx_1Col[j] = Lx_1Col[j - 1] + org_img[j*width];      //  第一列 横向累加。        
    	}
    	
    	memcpy(&integralImg[0][0], &Lx_2Row[0][0], width * sizeof(unsigned int));
    
    	for (j = 1; j<height; j++)
    	{
    		int row0 = (j) & 0x01, row1 = (j + 1) & 0x01;
    		Lx_2Row[row0][0] = Lx_1Col[j];
    		index = j*width + 1;
    		for (i = 1; i<width; i++)
    		{
    			Lx_2Row[row0][i] = Lx_2Row[row0][i - 1] + Lx_2Row[row1][i] - Lx_2Row[row1][i - 1] + org_img[index++];
    			// 其实这句话的推到公式可以简化为 dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j] + map[i][j];
    			// dp[i][j] 为 以0,0为点,以i、j终点的矩形中所有点的和。
    			// 在第一行和一列已经累加出来的前提下。
    		}
    		memcpy(&integralImg[j][0], &Lx_2Row[row0][0], width * sizeof(unsigned int));
    	}
    	// integralImg 积分后的图像。
    
    	memset(new_img, 255, (height*width));    //放这输入输出图可以用同一帧。全是255为了中值后图片与固定阈值分割的图逻辑与操作使用
    
    	count = block*block * 100;
    	for (i = (S + 1); i< (height - S); i++)
    	{
    		for (j = (S + 1); j< (width - S); j++)
    		{
    			index = i*width + j;
    
    			// set the SxS region
    			x1 = j - S;
    			x2 = j + S;
    			y1 = i - S;
    			y2 = i + S;
    
    			sum = integralImg[y2][x2] - integralImg[y1][x2] - integralImg[y2][x1] + integralImg[y1][x1];
    			// 求以(y1,x1)为起点,(y2,x2)为终点的 矩阵所有点之和。
    
    			//bin[index] = (((unsigned int)( input[index] * count- sum*(100 - T) ))&&(1)) * 255;
    
    			if ((org_img[index] * count) < (sum*(100 - T)))  //不懂这句话的,请看上文技术,如果当前像素的值比平均值低百分之t,那么它被设置为黑色,否则它被设置为白色       
    				new_img[index] = 0;
    			//else
    			//	new_img[index] = 255;
    
    		}
    	}
    }

    四、就是给图像加边框后,再进行块状区域积分求阈值

    static int SurroundImage(unsigned char* src, unsigned char* dst, int width, int height, int exWidth, int exHeight)
    {
    	//原图像是data;扩展后是DataDst width、height为原图的宽高,exwidth、exheight为块状区域的宽高
    	int i, j;
    	unsigned char* pSrc, *pDst;
    	int dstWidth = width + exWidth;
    	int dstHeight = height + exHeight;
    
    	if ((0 != width % 2) || (0 != height % 2))
    	{
    		memset(src, 0, (height*width));
    		return -1;
    	}
    
    	//center
    	pSrc = src;
    	pDst = dst + (exHeight / 2)*(width + exWidth) + exWidth / 2;
    	for (j = exHeight / 2; j < (height + exHeight / 2); j++)   // 把原图复制过来。
    	{
    		memcpy(pDst, pSrc, (width));             //
    		pSrc += (width);
    		pDst += (width + exWidth);
    	}
    
    	//  9月17号 打卡
    	//  9月18号 继续? 继续
    	//4 corners /*加4个边角*/  
    	pSrc = src;
    	pDst = dst;
    	/*左上角的方框,全部赋值为原图的左上角点*/
    	for (i = 0; i < (exWidth / 2); i++)
    		for (j = 0; j < (exHeight / 2); j++)
    			*(pDst + i + j*(dstWidth)) = *(pSrc + 0 + 0 * width);//pSrc[0][0];   // dstWidth  = width + exWidth
    	/*右上角的方框,全部赋值为原图的右上角点*/
    	for (i = (width + exWidth / 2); i < (width + exWidth); i++)
    		for (j = 0; j < (exHeight / 2); j++)
    			*(pDst + i + j*(dstWidth)) = *(pSrc + width - 1 + 0 * width); //pSrc[width-1][0];
    
    	/*右下角的方框,全部赋值为原图的右下角点*/
    	for (i = (width + exWidth / 2); i < (width + exWidth); i++)
    		for (j = (height + exHeight / 2); j < (height + exHeight); j++)    // 行数
    			*(pDst + i + j*(dstWidth)) = *(pSrc + width - 1 + (height - 1) * width); ;// pSrc[width - 1][height - 1];
    
    	/*左下角的方框,全部赋值为原图的左下角点*/
    	for (i = 0; i < (exWidth / 2); i++)
    		for (j = (height + exHeight / 2); j < (height + exHeight); j++)
    			*(pDst + i + j*(dstWidth)) = *(pSrc + 0 + (height - 1) * width); //pSrc[0][height-1];
    
    																			 //4line
    	pSrc = src;
    	pDst = dst;
    	//up
    	/* 上方的线,都用原图中的第一行赋值*/
    	for (i = 0; i < (width); i++)
    		for (j = 0; j < (exHeight / 2); j++)
    		{
    			*(pDst + i + exWidth / 2 + j*(dstWidth)) = *(pSrc + i + 0 * width); //pSrc[i][0];
    		}
    	//right
    	/*右边的线exWidth/2 * height 这么多点,有height行,每行exWidth/2个点,全部用原图最右边的线上对应行的那个点赋值*/
    	for (j = 0; j < (height); j++)
    	{
    		memset((pDst + width + exWidth / 2 + (j + exHeight / 2)*(dstWidth)), *(pSrc + (j + 1)*width - 1), (exWidth / 2)); //pSrc[][];
    	}
    	//down
    
    	for (i = 0; i < (width); i++)
    		for (j = (exHeight / 2 + height); j < (exHeight + height); j++)
    		{
    			*(pDst + i + exWidth / 2 + j*(dstWidth)) = *(pSrc + width*(height - 1) + i); //pSrc[i][0];
    		}
    	//left
    	for (j = 0; j < (height); j++)
    	{
    		memset((pDst + 0 + (j + exHeight / 2)*(dstWidth)), *(pSrc + j*width), (exWidth / 2)); //pSrc[][];
    	}
    	/*关于为什么这么赋值,我想应该经过验证的。*/
    	return 0;
    }
    void BinAdaptiveThresholdFull(unsigned char* input, int height, int width, unsigned char* bin, int block, int ratio)
    {
    	//input 原图,width、height原图的宽高,bin要输出的图像,block 块状区域大小,ratio根据这个值,调整T的。
    	//ratio can be modified : 20 means 20%
    	int T = 20; //15
    	int halfBlock = (block - 1) / 2;
     
    	long sum = 0;
    	int count = 0;
    	int index = 0;
    	int x1, y1, x2, y2;
    
    	if (0 == block % 2)//block must be odd
    		return;
    
    	T = (ratio >= 100 || ratio <= 0) ? 20: ratio;
    	count = block*block * 100;
    
    	SurroundImage(input, (unsigned char*)pSurroundImage, width, height, block - 1, block - 1);
    #if (!DSP_HARDWARE_) &&( !UNIT_TEST_VERSION)
    //IplSurroundImage = cvCreateImage(cvSize(width + block - 1 , height + block - 1), IPL_DEPTH_8U, 1);//debug
    //IplSurroundImage->imageData = pSurroundImage;
    #endif
    	// 计算积分图像	
    	integralFullImg[0] = pSurroundImage[0];
    	//Y=0
    	for (int i = 1; i<(width + block - 1); i++)
    	{
    		int j = 0;
    		integralFullImg[i + j*(width + block - 1)] = integralFullImg[i - 1 + j*(width + block - 1)] + pSurroundImage[i + j*(width + block - 1)];
    	}
    	//X=0
    	for (int j = 1; j<(height + block - 1); j++)
    	{
    		int i = 0;
    		integralFullImg[i + j*(width + block - 1)] = integralFullImg[i + (j - 1)*(width + block - 1)] + pSurroundImage[i + j*(width + block - 1)];
    	}
    
    	for (int j = 1; j<(height + block - 1); j++)
    	{
    		for (int i = 1; i<(width + block - 1); i++)
    		{
    			integralFullImg[i + j*(width + block - 1)] = integralFullImg[i - 1 + j*(width + block - 1)] + integralFullImg[i + (j - 1)*(width + block - 1)] - integralFullImg[i - 1 + (j - 1)*(width + block - 1)] + pSurroundImage[i + j*(width + block - 1)];
    		}
    	}
    
    	for (int i = 0; i< (width); i++)
    	{
    		for (int j = 0; j< (height); j++)
    		{
    			// set the (block-1)*(block-1) region
    			x1 = i;
    			x2 = i + block - 1;
    			y1 = j;
    			y2 = j + block - 1;
    
    			sum = integralFullImg[x2 + y2*(width + block - 1)] - integralFullImg[x2 + y1*(width + block - 1)] - integralFullImg[x1 + y2*(width + block - 1)] + integralFullImg[x1 + y1*(width + block - 1)];
    
    			//bin[index] = (((unsigned int)( input[index] * count- sum*(100 - T) ))&&(1)) * 255;
    			if ((input[i + width*j] * count) < (sum*(100 - T)))
    				bin[i + width*j] = 0;
    			else
    				bin[i + width*j] = 255;
    		}
    	}
    }

     

    展开全文
  • 在图像处理与目标识别中广为应用的阈值法是图像分割的一种重要方法,因此如何确定阈值是图像分割的关键。提出了一种新的图像阈值分割方法,把图像的一维灰度直方图的灰度级L和对应灰度级L的概率P视为二维平面上的点...
  • 最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的...如何确定这个阈值K?算法分类的原理是让背景和目标之间的类间方差最大,因为背景和目标之间的类间方差越大,说明构成...
  • 级联分类器的识别过程是十分清楚地,一级一级的。 但是训练过程是如何做的呢? 如何确定每一级的阈值? 如何保证后面的分类器比前面的分类器效果好?
  • python实现二分类的卡方分箱示例发布时间:...1、自由度k,如何确定,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1%算法扩展:1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,...
  • 1、自由度k,如何确定,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1% 算法扩展: 1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,以及最小箱占比,坏人率约束等。 2、需要实现更...
  • python实现二分类的卡方分箱

    千次阅读 2018-11-28 19:19:44
    1、自由度k,如何确定,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1% 算法扩展: 1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,以及最小箱占比,坏人率约束等。 2、需要实现...
  • 1、自由度k,如何确定,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1%算法扩展:1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,以及最小箱占比,坏人率约束等。2、需要实现更多...
  • 1、自由度k,如何确定,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1%算法扩展:1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,以及最小箱占比,坏人率约束等。2、需要实现更多...
  • ROC又叫受试者工作特征曲线。它是用来验证一个二分类器模型的性能指标,也就是说,给出一个模型,输入一个模型,输入已知正负类的一组数据,并通过对比模型对改组数据进行的预测,...由TPR和FPR可以确定一个点,在...
  • 对博主而言,最主要的是迭代部分的第二步骤是如何如何确定阈值呢,也就是说有一个特征就有一个强分类器,n个特征就有n个强分类器,那如果你特别大的话,肯定需要筛选特征,该如何筛选呢;也就是对于多维或者高维特征...
  • 深度学习文章一般用EER(Equal Error Rate)等错误概率作为衡量分类器的一个客观标准,博文ROC曲线解释了如何计算EER。 下面是对EER计算的简单介绍 EER(平均错误概率)是一种生物识别安全系统算法,用于预先确定其...
  • 数据预处理

    2019-05-16 16:16:39
    问题:当数据出现噪声时该如何处理 思路:两种 (1)多项式拟合,利用最小二乘法确定一个阈值 确定使用几阶多项式(确定一部分数据进行一次拟合) 最小二乘法(根据拟合曲线确定一个阈值,在什么范围内的是有效...
  • 最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定...如何确定这个阈值K?算法分类的原理是让背景和目标之间的类间方差最大,因为背景和目标之间的类间方差越大,说明构成图像的...
  • 两类的线形判别问题可以看作是把所有样本都投影到一个方向上 然后在这 个一维空间中确定一个分类阈值 过这个预置点且与投影方向垂直的超平面就 是两类的分类面 第一个问题如何确定投影方向 这里只讨论两类分类的...
  • ROC-AUC笔记

    2018-03-03 22:17:53
    名词解释 ROC曲线:Receiver Operating Characteristic Curve AUC:Area Under Curve ... 分类模型尝试将各个实例(instance)划归...这里就涉及到如何确定阈值(thresholdvalue),使得模型结果大于这个值,划为...
  • 以前的论文没有系统性的提出该如何确定网络结构,因此本论文利用遗传算法进行网络结构的空间搜索。首先将主网络和辅助分类器联合训练,后利用遗传算法搜索辅助分类器的位置和阈值,最后interfence过程中若某个辅助...
  • (一) 分类模型尝试将各个实例(instance)划归到某个特定的类,而分类模型的...这里就涉及到如何确定阈值(threshold value),使得模型结果大于这个值,划为一类,小于这个值,划归为另一类。 考虑一个二分
  • 决策树的本质:本质是从训练数据中,总结出一套分类规则,也可以...两个最好要如何确定,是个重要问题。 如何选择呢?在候选特征中找出信息增益高于平均水平的特征,然后在这些特征中再选择信息增益率最高的特征(...
  • zz在Excel中作ROC曲线

    2010-07-16 17:16:00
    Comment from Xinwei: 最近在帮高老师review一片PRL的论文,看到ROC曲线,查了一下Stentor的大作,觉得解释的很不错,...这里就涉及到如何确定阈值(threshold value),使得模型结果大于这个值,划为一类,小于这...
  • 在Excel中作ROC曲线

    2009-02-14 19:26:00
    这里就涉及到如何确定阈值(threshold value),使得模型结果大于这个值,划为一类,小于这个值,划归为另一类。 考虑一个二分问题,即将实例分成正类(positive)或负类(negative)。对一个二分问题来说,会...
  • 机器学习 之 决策树

    2020-10-20 17:53:19
    决策树是一种机器学习的方法。决策树的生成算法有ID3, C4.5和C5.0等。 就是这么一个东西,但这种东西是自动生成的,如何生成这个,就是各种算法了。 这是有监督学习。监管学习就是给出一堆样本,...阈值确定:选择适
  • 测试覆盖率

    2011-10-28 11:16:51
    可以设定一个阈值,在缺陷发现率低于该阈值时才能部署软件。也可根据执行模型中的起源报告缺陷计数,以允许检测"较差的模块"、"热点"或需要再三修复的软件部分,从而指示一些更基本的设计缺陷。  这种分析中包含的...

空空如也

空空如也

1 2
收藏数 36
精华内容 14
关键字:

如何确定分类阈值