mser

static void extractMSER_8UC1_Pass( int* ioptr,  

             int* imgptr,  

             int*** heap_cur,  

             LinkedPoint* ptsptr,  

             MSERGrowHistory* histptr,  

             MSERConnectedComp* comptr,  

             int step,  

             int stepmask,  

             int stepgap,  

             MSERParams params,  

             int color,  

             CvSeq* contours,  

             CvMemStorage* storage )  

{  

   //设置第一个组块的灰度值为256,该灰度值是真实图像中不存在的灰度值,以区分真实图像的组块,从而判断程序是否结束  

   comptr->grey_level = 256;  

   //步骤2和步骤3  

   //指向第二个组块  

   comptr++;  

   //设置第二个组块为输入图像第一个像素(左上角)的灰度值  

   comptr->grey_level = (*imgptr)&0xff;  

   //初始化该组块  

   initMSERComp( comptr );  

   //在最高位标注该像素为已被访问过,即该值小于0  

   *imgptr |= 0x80000000;  

   //得到该像素所对应的堆,即指向它所对应的灰度值  

   heap_cur += (*imgptr)&0xff;  

   //定义方向,即偏移量,因为是4邻域,所以该数组分别对应右、下、左、上  

   int dir[] = { 1, step, -1, -step };  

#ifdef __INTRIN_ENABLED__  

   unsigned long heapbit[] = { 0, 0, 0, 0, 0, 0, 0, 0 };  

   unsigned long* bit_cur = heapbit+(((*imgptr)&0x700)>>8);  

#endif  

   //死循环,退出该死循环的条件有两个:一是到达组块的栈底;二是边界像素堆中没有任何值。达到栈底也就意味着堆中没有值,在此函数中两者是一致的。  

   for ( ; ; )  

   {  

       // take tour of all the 4 directions  

       //步骤4  

       //在4邻域内进行搜索  

       while ( ((*imgptr)&0x70000) < 0x40000 )  

       {  

           // get the neighbor  

           /* ((*imgptr)&0x70000)>>16得到第16位至第18位数据,该数据对应的4邻域的方向,再通过dir数组得到4邻域的偏移量,因此imgptr_nbr为当前像素4邻域中某一个方向上邻域的地址指针 */  

           int* imgptr_nbr = imgptr+dir[((*imgptr)&0x70000)>>16];  

           //检查邻域像素是否被访问过,如果被访问过,则会在第一位置1,因此该值会小于0,否则第一位为0,该值大于0  

           if ( *imgptr_nbr >= 0 ) // if the neighbor is not visited yet  

           {  

               //标注该像素已被访问过,即把第一位置1  

               *imgptr_nbr |= 0x80000000; // mark it as visited  

               //比较当前像素与邻域像素灰度值  

               if ( ((*imgptr_nbr)&0xff) < ((*imgptr)&0xff) )  

               {  

                   //如果邻域值小于当前值,把当前值放入堆中  

                   // when the value of neighbor smaller than current  

                   // push current to boundary heap and make the neighbor to be the current one  

                   // create an empty comp  

                   //堆中该像素灰度值的数量加1,即对该灰度值像素个数计数  

                   (*heap_cur)++;  

                   //把当前值的地址放入堆中  

                   **heap_cur = imgptr;  

                   //重新标注当前值的方向位,以备下一次访问该值时搜索下一个邻域  

                   *imgptr += 0x10000;  

                   //定位邻域值所对应的堆的位置  

                   //当前heap_cur所指向的灰度值为while循环搜索中的最小灰度值,即水溢过的最低点  

                   heap_cur += ((*imgptr_nbr)&0xff)-((*imgptr)&0xff);  

#ifdef __INTRIN_ENABLED__  

                   _bitset( bit_cur, (*imgptr)&0x1f );  

                   bit_cur += (((*imgptr_nbr)&0x700)-((*imgptr)&0x700))>>8;  

#endif  

                   imgptr = imgptr_nbr;    //邻域值换为当前值  

                   //步骤3  

                   comptr++;    //创建一个组块  

                   initMSERComp( comptr );    //初始化该组块  

                   comptr->grey_level = (*imgptr)&0xff;    //为该组块的灰度值赋值  

                   //当某个邻域值小于当前值,则不对当前值再做任何操作,继续下次循环,在下次循环中,处理的则是该邻域值,即再次执行步骤4  

                   continue;  

               } else {  

                   //如果邻域值大于当前值,把邻域值放入堆中  

                   // otherwise, push the neighbor to boundary heap  

                   //找到该邻域值在堆中的灰度值位置,并对其计数,即对该灰度值像素个数计数  

                   heap_cur[((*imgptr_nbr)&0xff)-((*imgptr)&0xff)]++;  

                   //把该邻域像素地址放入堆中  

                   *heap_cur[((*imgptr_nbr)&0xff)-((*imgptr)&0xff)] = imgptr_nbr;  

#ifdef __INTRIN_ENABLED__  

                   _bitset( bit_cur+((((*imgptr_nbr)&0x700)-((*imgptr)&0x700))>>8), (*imgptr_nbr)&0x1f );  

#endif  

               }  

           }  

           *imgptr += 0x10000;    //重新标注当前值的领域方向  

       }  

       //imsk表示结束while循环后所得到的最后像素地址与图像首地址的相对距离  

       int imsk = (int)(imgptr-ioptr);  

       //得到结束while循环后的最后像素的坐标位置  

       //从这里可以看出图像的宽采样2^N的好处,即imsk>>stepgap  

       ptsptr->pt = cvPoint( imsk&stepmask, imsk>>stepgap );  

       // get the current location  

       //步骤5  

       //对栈顶的组块的像素个数累加,即计算组块的面积大小,并链接组块内的像素点  

       //结束while循环后,栈顶组块的灰度值就是该次循环后得到的最小灰度值,也就是该组块为极低点,就相当于水已经流到了最低的位置  

       accumulateMSERComp( comptr, ptsptr );  

       //指向下一个像素点链表位置  

       ptsptr++;  

       // get the next pixel from boundary heap  

       //步骤6  

       /*结束while循环后,如果**heap_cur有值的话,heap_cur指向的应该是while循环中得到的灰度值最小值,也就是在组块的边界像素中,有与组块相同的灰度值,因此要把该值作为当前值继续while循环,也就是相当于组块面积的扩展*/  

       if ( **heap_cur )    //有值  

       {  

           imgptr = **heap_cur;    //把该像素点作为当前值  

           (*heap_cur)--;    //像素的个数要相应的减1  

#ifdef __INTRIN_ENABLED__  

           if ( !**heap_cur )  

               _bitreset( bit_cur, (*imgptr)&0x1f );  

#endif  

       //步骤7  

       //已经找到了最小灰度值的组块,并且边界像素堆中的灰度值都比组块的灰度值大,则这时需要组块,即计算最大稳定极值区域  

       } else {  

#ifdef __INTRIN_ENABLED__  

           bool found_pixel = 0;  

           unsigned long pixel_val;  

           for ( int i = ((*imgptr)&0x700)>>8; i < 8; i++ )  

           {  

               if ( _BitScanForward( &pixel_val, *bit_cur ) )  

               {  

                   found_pixel = 1;  

                   pixel_val += i<<5;  

                   heap_cur += pixel_val-((*imgptr)&0xff);  

                   break;  

               }  

               bit_cur++;  

           }  

           if ( found_pixel )  

#else  

           heap_cur++;    //指向高一级的灰度值  

           unsigned long pixel_val = 0;  

           //在边界像素堆中,找到边界像素中的最小灰度值  

           for ( unsigned long i = ((*imgptr)&0xff)+1; i < 256; i++ )  

           {  

               if ( **heap_cur )  

               {  

                   pixel_val = i;    //灰度值  

                   break;  

               }  

               //定位在堆中所对应的灰度值,与pixel_val是相等的  

               heap_cur++;  

           }  

           if ( pixel_val )    //如果找到了像素值  

#endif  

           {  

               imgptr = **heap_cur;    //从堆中提取出该像素  

               (*heap_cur)--;    //对应的像素个数减1  

#ifdef __INTRIN_ENABLED__  

               if ( !**heap_cur )  

                   _bitreset( bit_cur, pixel_val&0x1f );  

#endif  

               //进入处理栈子模块  

               if ( pixel_val < comptr[-1].grey_level )  

               //如果从堆中提取出的最小灰度值小于距栈顶第二个组块的灰度值,则说明栈顶组块和第二个组块之间仍然有没有处理过的组块,因此在计算完MSER值后还要继续返回步骤4搜索该组块  

               {  

                   // check the stablity and push a new history, increase the grey level  

                   //利用公式2计算栈顶组块的q(i)值  

                   if ( MSERStableCheck( comptr, params ) )    //是MSER  

                   {  

                       //得到组块内的像素点  

                       CvContour* contour = MSERToContour( comptr, storage );  

                       contour->color = color;    //标注是MSER-还是MSER+  

                       //把组块像素点放入序列中  

                       cvSeqPush( contours, &contour );  

                   }  

                   MSERNewHistory( comptr, histptr );  

                   //改变栈顶组块的灰度值,这样就可以和上一层的组块进行合并  

                   comptr[0].grey_level = pixel_val;  

                   histptr++;  

               } else {  

                   //从堆中提取出的最小灰度值大于等于距栈顶第二个组块的灰度值  

                   // keep merging top two comp in stack until the grey level >= pixel_val  

                   //死循环,用于处理灰度值相同并且相连的组块之间的合并  

                   for ( ; ; )  

                   {  

                       //指向距栈顶第二个组块  

                       comptr--;  

                       //合并前两个组块,并把合并后的组块作为栈顶组块  

                       MSERMergeComp( comptr+1, comptr, comptr, histptr );  

                       histptr++;  

                       /*如果pixel_val = comptr[0].grey_level,说明在边界上还有属于该组块的像素;如果pixel_val < comptr[0].grey_level,说明还有比栈顶组块灰度值更小的组块没有搜索到。这两种情况都需要回到步骤4中继续搜索组块*/  

                       if ( pixel_val <= comptr[0].grey_level )  

                           break;  

                       //合并栈内前两个组块,直到pixel_val < comptr[-1].grey_level为止  

                       if ( pixel_val < comptr[-1].grey_level )  

                       {  

                           // check the stablity here otherwise it wouldn‘t be an ER  

                           if ( MSERStableCheck( comptr, params ) )  

                           {  

                               CvContour* contour = MSERToContour( comptr, storage );  

                               contour->color = color;  

                               cvSeqPush( contours, &contour );  

                           }  

                           MSERNewHistory( comptr, histptr );  

                           comptr[0].grey_level = pixel_val;  

                           histptr++;  

                           break;  

                       }  

                   }  

               }  

           } else  

               //边界像素堆中没有任何像素,则退出死循环,该函数返回。  

               break;  

       }  

   }  

}

  

时间: 2024-10-15 11:42:46

mser的相关文章

matlab实现MSER(最大极值稳定区域)来进行文本定位

一.自然场景文本定位综述   场景图像中文本占据的范围一般都较小,图像中存在着大范围的非文本区域.因此,场景图像文本定位作为一个独立步骤越来越受到重视.这包括从最先的CD和杂志封面文本定位到智能交通系统中的车牌定位.视频中的字幕提取,再到限制条件少,复杂背景下的场景文本定位.与此同时文本定位算法的鲁棒性越来越高,适用的范围也越来越广泛.文本定位的方式一般可以分为三种,基于连通域的.基于学习的和两者结合的方式.基于连通域的流程一般是首先提取候选文本区域,然后采用先验信息滤除部分非文本区域,最后根据

Matlab mser(最大极值稳定区域)

在Matlab R2013a 和R2014a中已经实现MSER特征的提取. 一.函数detectMSERFeatures 输入的是M*N的灰度图片.可以指定阈值刻度,区域范围,感兴趣区域等参数. 输出的是MSERRegions class,即框住区域的椭圆由椭圆中心的坐标,椭圆的长短轴,椭圆的方向(有长轴与x方向形成的角),即区域内所有像素的坐标. Detect MSER features and return MSERRegions object Syntax · regions = dete

opencv mser算法框出图片文字区域

MSER(Maximally Stable Extrernal Regions)是区域检测中影响最大的算法 1. 原理 MSER基于分水岭的概念:对图像进行二值化,二值化阈值取[0, 255],这样二值化图像就经历一个从全黑到全白的过程(就像水位不断上升的俯瞰图).在这个过程中,有些连通区域面积随阈值上升的变化很小,这种区域就叫MSER. ,其中Qi表示第i个连通区域的面积,Δ表示微小的阈值变化(注水),当vi小于给定阈值时认为该区域为MSER. 显然,这样检测得到的MSER内部灰度值是小于边界

mser 最大稳定极值区域(文字区域定位)算法 附完整C代码

mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. 也就是中文车牌识别开源项目EasyPR的作者liuruoze,刘兄. 自那时起就有一块石头没放下,想要找个时间好好理理这个算法. 学习一些它的一些思路. 因为一般我学习算法的思路:3个做法, 第一步,编写demo示例. 第二步,进行算法移植或效果改进. 第三步,进行算法性能优化. 然后在这三个过程中

最大稳定极值区域(MSER)检测

http://blog.csdn.net/zizi7/article/details/50379973 http://www.cnblogs.com/dawnminghuang/p/3779552.html http://www.cnblogs.com/frischzenger/p/3334569.html 作者:wangduo 出处:http://www.cnblogs.com/wangduo/ 本博客中未标明转载的文章归作者wangduo和博客园共有,欢迎转载,但未经作者同意必须保留此段声明

Warning: Name is nonexistent or not a directory

Every time I start up MATLAB, I receive this message: Warning: Name is nonexistent or not a directory: C:\POSTDOC\vlfeat\toolbox\mexw32. Warning: Name is nonexistent or not a directory: C:\POSTDOC\vlfeat\toolbox\special. Warning: Name is nonexistent

论文阅读(BaiXiang——【CVPR2016】Multi-Oriented Text Detection with Fully Convolutional Networks)

BaiXiang--[CVPR2016]Multi-Oriented Text Detection with Fully Convolutional Networks 目录 作者和相关链接 方法概括 方法细节 创新点和贡献 实验结果 问题讨论 总结与收获点 作者和相关链接 作者: paper下载 方法概括 Step 1--文本块检测: 先利用text-block FCN得到salient map,再对salient map进行连通分量分析得到text block: Step 2--文本线形成:

总结一些机器视觉库

通用库/General Library OpenCV   无需多言. RAVL  Recognition And Vision Library. 线程安全.强大的IO机制.包含AAM. CImg  很酷的一个图像处理包.整个库只有一个头文件.包含一个基于PDE的光流算法. 图像,视频IO/Image, Video IO FreeImage DevIL ImageMagick FFMPEG VideoInput portVideo AR相关/Augmented Reality ARToolKit 

[转]计算机视觉、机器学习相关领域论文和源代码大集合

计算机视觉.机器学习相关领域论文和源代码大集合--持续更新…… [email protected] http://blog.csdn.net/zouxy09 注:下面有project网站的大部分都有paper和相应的code.Code一般是C/C++或者Matlab代码. 最近一次更新:2013-3-17 一.特征提取Feature Extraction: ·         SIFT [1] [Demo program][SIFT Library] [VLFeat] ·         PCA