精华内容
下载资源
问答
  • 点云常用分割方法

    千次阅读 2020-09-01 15:00:50
    转载自博客园IronStark点云分割系列:https://www.cnblogs.com/ironstark/p/5027269.html ... 点云分割  点云分割可谓点云处理的精髓,也是三维图像相对二维图像最大...而在现实点云数据中,往往对场景中的物体一定.

    转载自博客园IronStark点云分割系列https://www.cnblogs.com/ironstark/p/5027269.html

    转载自菜鸟知识搬运工https://blog.csdn.net/qq_30815237/article/details/91345015###

    点云分割

      点云分割可谓点云处理的精髓,也是三维图像相对二维图像最大优势的体现。

      点云分割的目的是提取点云中的不同物体,从而实现分而治之,突出重点,单独处理的目的。而在现实点云数据中,往往对场景中的物体有一定先验知识。比如:桌面墙面多半是大平面,桌上的罐子应该是圆柱体,长方体的盒子可能是牛奶盒......对于复杂场景中的物体,其几何外形可以归结于简单的几何形状。这为分割带来了巨大的便利,因为简单几何形状是可以用方程来描述的,或者说,可以用有限的参数来描述复杂的物体。而方程则代表的物体的拓扑抽象。于是,RanSaC算法可以很好的将此类物体分割出来。

    1、RanSaC算法

      RanSaC算法(随机采样一致)原本是用于数据处理的一种经典算法,其作用是在大量噪声情况下,提取物体中特定的成分。下图是对RanSaC算法效果的说明。图中有一些点显然是满足某条直线的,另外有一团点是纯噪声。目的是在大量噪声的情况下找到直线方程,此时噪声数据量是直线的3倍。

                             

      如果用最小二乘法是无法得到这样的效果的,直线大约会在图中直线偏上一点。关于随机采样一致性算法的原理参考博客:

    https://blog.csdn.net/qq_30815237/article/details/90405087

      这个算法就是从一堆数据里挑出自己最心仪的数据。所谓心仪当然是有个标准(目标的形式:满足直线方程?满足圆方程?以及能容忍的误差e)。平面中确定一条直线需要2点,确定一个圆则需要3点。

    1. 平面中随机找两个点,拟合一条直线,并计算在容忍误差e中有多少点满足这条直线
    2. 重新随机选两点,拟合直线,看看这条直线是不是能容忍更多的点,如果是则记此直线为结果
    3. 重复步骤二(循环迭代)
    4. 迭代结束,记录当前结果

         算法的优点是噪声可以分布的任意广,噪声可以远大于模型信息。这个算法有两个缺点,第一,必须先指定一个合适的容忍误差e。第二,必须指定迭代次数作为收敛条件

      综合以上特性,本算法非常适合从杂乱点云中检测某些具有特殊外形的物体。

    PCL中基于RanSaC的点云分割方法:

    
     
    1. //创建一个模型参数对象,用于记录结果

    2. pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);

    3. //inliers表示误差能容忍的点 记录的是点云的序号

    4. pcl::PointIndices::Ptr inliers (new pcl::PointIndices);

    5. // 创建一个分割器

    6. pcl::SACSegmentation<pcl::PointXYZ> seg;

    7. // Optional

    8. seg.setOptimizeCoefficients (true);

    9. // Mandatory-设置目标几何形状

    10. seg.setModelType (pcl::SACMODEL_PLANE);

    11. //分割方法:随机采样法

    12. seg.setMethodType (pcl::SAC_RANSAC);

    13. //设置误差容忍范围

    14. seg.setDistanceThreshold (0.01);

    15. //输入点云

    16. seg.setInputCloud (cloud);

    17. //分割点云

    18. seg.segment (*inliers, *coefficients);

    除了平面以外,PCL几乎支持所有的几何形状。作为点云分割的基础算法,RanSaC很强大且必收敛,可以作为机器人抓取,识别等后续任务的前处理。

    2、基于临近信息的点云分割

          分割给人最直观的影响大概就是邻居和我不一样。 除了之前提到的基于采样一致的分割方式以外,还存在基于邻近搜索的分割方式。通过对比某点和其最近一点的某些特征,来实现点云的分割。图像所能提供的分割信息仅是灰度或RGB向量,而三维点云却能够提供更多的信息。故点云在分割上的优势是图像所无法比拟的。

    kdTree&OcTree

      由于分割工作需要对点云的邻近点进行操作,不断对比和访问某个点的邻居,所以决定点云的相邻关系是非常重要的。对于Scan来说,邻居关系是天然的。但对于很多杂乱点云,或者滤波,分割后的点云来说,邻居关系就已经被破坏了。确定一个点云之间的相邻关系可以通过“树”来完成,目前比较主流的方法包括:kdTree和OcTree,这两种方法各有特点。

    2.1、kdTree---一种递归的邻近搜索策略

      kdTree实际上包括两个部分:1.建立kdTree,2.在kdTree中查找。建立kdTree实际上是一个不断划分的过程,首先选择最sparse的维度,然后找到该维度上的中间点,垂直该维度做第一次划分。此时k维超平面被一分为二,在两个子平面中再找最sparse的维度,依次类推知道最后一个点也被划分。那么就形了一个不断二分的树。如图所示。

      

         一般情况下,一个点的邻近点只需要在其父节点和子节点中搜索即可,大大缩小了邻近点的搜索规模。并且kdtree可以有效的对插入点进行判断其最近点在哪个位置。对于低层次视觉来说kdTree算法是非常重要的。在很多情况下需要给出某个点,再查k临近点的编号,或者差某半径范围内的点。

    2.2、OcTree

      OcTree是一种更容易理解也更自然的思想。对于一个空间,如果某个角落里有个盒子我们却不知道在哪儿。显而易见的方法就是把空间化成8个卦限,然后询问在哪个卦限内。再将存在的卦限继续化成8个。意思大概就是太极生两仪,两仪生四象,四象生八卦,就这么一直划分下去,最后一定会确定一个非常小的空间。对于点云而言,只要将点云的立方体凸包用octree生成很多很多小的卦限,那么在相邻卦限里的点则为相邻点。

      显然,对于不同点云应该采取不同的搜索策略,如果点云是疏散的,分布很广泛,且没什么规律(如lidar测得的点云或双目视觉捕捉的点云)kdTree能更好的划分,而octree则很难决定最小立方体应该是多少。太大则一个立方体里可能有很多点云,太小则可能立方体之间连不起来。如果点云分布非常规整,是某个特定物体的点云模型,则应该使用ocTree,因为很容易求解凸包并且点与点之间相对距离无需再次比对父节点和子节点,更加明晰。典型的例子是斯坦福的兔子。

    欧几里得与区域生长算法

      基于欧式距离的分割和基于区域生长的分割本质上都是用区分邻里关系远近来完成的。由于点云数据提供了更高维度的数据,故有很多信息可以提取获得。欧几里得算法使用邻居之间距离作为判定标准,而区域生长算法则利用了法线,曲率,颜色等信息来判断点云是否应该聚成一类。

    2.1.欧几里得算法

      从前有一个脑筋急转弯,说一个锅里有两粒豆子,如果不用手,要怎么把它们分开。当时的答案是豆子本来就是分开的,又没黏在一起,怎么不叫分开。OK,实际上欧几里德算法就是这个意思。两团点云就像是两粒豆子,只要找到某个合适的度量方式,就有办法把点云和点云分开。

         如果两团点云之间最近两点的距离小于单个点云内部点之间的距离,则可以由算法判断其分为两类。假设总点云集合为A,聚类所得点云团为Q

      具体的实现方法大致是:

    1. 找到空间中某点p10,用kdTree找到离他最近的n个点,判断这n个点到p的距离。将距离小于阈值r的点p12,p13,p14....放在类Q里
    2. 在 Q里找到一点p12,重复1
    3. 在 Q里找到一点p13,重复1,找到p22,p23,p24....全部放进Q里.
    4. 当 Q 再也不能有新点加入了,则完成搜索了

      听起来好像这个算法并没什么用,因为点云总是连成片的,很少有什么东西会浮在空中让你来分。但是如果和前面介绍的内容联系起来就会发现这个算法威力巨大了。比如:

    1. 半径滤波删除离群点
    2. 采样一致找到桌面,抽掉桌面

    显然,一旦桌面被抽,桌上的物体就自然成了一个个的浮空点云团。就能够直接用欧几里德算法进行分割了。如图所示。

    区域生长算法

    1、基于法线和曲率

      区域生长算法直观感觉上和欧几里德算法相差不大,都是从一个点出发,最终占领整个被分割区域。欧几里德算法是通过距离远近,来判断烧到哪儿。区域生长算法则不然,烧到哪儿靠燃料(点)的性质是否类似来决定。对于普通点云,其可由法线、曲率估计算法获得其法线和曲率值。通过法线和曲率来判断某点是否属于该类。其算法可以总结为:

    1. 种子周围的点和种子相比
    2. 法线方向是否足够相近
    3. 曲率是否足够小
    4. 如果满足1,2,则该点可用做种子
    5. 如果只满足1,则归类而不做种
    6. 从某个种子出发,直到其“子种子”不再出现,则一类聚集完成
    7. 类的规模既不能太大也不能太小

    显然,上述算法是针对小曲率变化面设计的。尤其适合对连续阶梯平面进行分割:比如SLAM算法所获得的建筑走廊。

    2、基于颜色:

          除了普通点云之外,还有一种特殊的点云,成为RGB点云。显而易见,这种点云除了结构信息之外,还存在颜色信息。颜色信息可以很好的将复杂场景中的特殊物体分割出来。而颜色点云也并不那么遥不可及,Xbox Kinect就可以轻松的捕捉颜色点云。

          基于颜色的区域生长分割原理上和基于曲率,法线的分割方法是一致的。只不过比较目标换成了颜色,去掉了点云规模上限的限制。可以认为,同一个颜色且挨得近,是一类的可能性很大,不需要上限来限制。所以这种方式比较适合用于室内场景分割。尤其是复杂室内场景,颜色分割可以轻松的将连续的场景点云变成不同的物体。哪怕是高低不平的地面,没法用采样一致分割器抽掉,颜色分割算法同样能完成分割任务。

    3.基于点云频率的分割(滤波)方法

    点云的频率

      点云和图像一样,有可能也存在频率的概念。点云表达的是三维空间中的一种信息,这种信息本身并没有一一对应的函数值。故点云本身并没有在讲诉一种变化的信号。点云虽然没有明确的时间关系,但应该会存在某种空间关系(例如LiDar点云)。我们可以人为的指定点云空间中的一个点(例如Scan的重心或LiDar的“源”),基于此点来讨论点云在各个方向上所谓的频率。

      在传统的信号处理中,高频信号一般指信号变化快,低频信号一般指信号变化缓慢。在图像处理中,高低频的概念被引申至不同方向上图像灰度的变化,在点云处理中,定义点云法线向量差为点云所表达的信号。换言之,如果某处点云曲率大,则点云表达的是一个变化的信号。如果点云曲率小,则其表达的是一个不变的信号。这和我们的直观感受也是相近的,地面曲率小,它表达的信息量也小;人的五官部分曲率大,表达更大的信息量。

    DoN算法

      使用频率信息的思想已经被广泛的应用在了各个方面,最著名的莫过于DoN算法。DoN算法被作者归类于点云分割算法中,但本质上DoN只是一种前处理,应该算是一种比较先进的点云滤波算法。分割本质上还是由欧式分割算法完成的。DoN 是 Difference of Normal 的简写。算法的目的是在去除点云低频滤波,低频信息(例如建筑物墙面,地面)往往会对分割产生干扰,高频信息(例如建筑物窗框,路面障碍锥)往往尺度上很小,直接采用 基于临近信息 的滤波器会将此类信息合并至墙面或路面中。所以DoN算法利用了多尺度空间的思想,算法如下:

    1. 在小尺度上计算点云法线1
    2. 在大尺度上计算点云法线2
    3. 法线1-法线2
    4. 滤去3中值较小的点
    5. 欧式分割

                                                                

      显然,在小尺度上是可以对高频信息进行检测的,此算法可以很好的小尺度高频信息。其在大规模点云中优势尤其明显。算法运行过程可用图表示为:

     

    from:http://www.pointclouds.org/documentation/tutorials/don_segmentation.php

    4、最小割算法

    点云分割的精度

       基于采样一致的点云分割算法显然是意识流的,它只能割出大概的点云(可能是杯子的一部分,但杯把儿肯定没分割出来)。基于欧式算法的点云分割面对有连接的点云就无力了(比如风筝和人,在不用三维形态学去掉中间的线之前,是无法分割风筝和人的)。基于法线等信息的区域生长算法则对平面更有效,没法靠它来分割桌上的碗和杯子。

        我们还需要一个方法来解决分割的“好不好”这个问题。也就是说,有没有哪种方法,可以在一个点不多,一个点不少的情况下,把目标和“其他”分开。

      最小割(min-cut)早就用在网络规划,求解桥问题,图像分割等领域,被移植到点云分割上也不足为奇。最小割算法是图论中的一个概念,其作用是以某种方式,将两个点分开,当然这两个点中间可能是通过无数的点再相连的。如图所示。

                                                                 

      如果要分开最左边的点和最右边的点,红绿两种割法都是可行的,但是红线跨过了三条线,绿线只跨过了两条。单从跨线数量上来论可以得出绿线这种切割方法更优的结论。但假设线上有不同的权值,那么最优切割则和权值有关了。它到底是怎么找到那条绿线的暂且不论。总而言之,就是有那么一个算法,当你给出了点之间的 “图” (广义的),以及连线的权值时,最小割算法就能按照你的要求把图分开。

    点云 “图”

      切割有两个非常重要的因素,第一个是获得点与点之间的拓扑关系,也就是生成一张“图”。第二个是给图中的连线赋予合适的权值。点云有天然分开的点,是一种非常适合分割的对象。有了点之后,只要把点云中所有的点连起来就可以了。连接算法如下:

    1. 找到每个点最近的n个点
    2. 将这n个点和父点连接
    3. 找到距离最小的两个块(A块中某点与B块中某点距离最小),并连接
    4. 重复3,直至只剩一个块

      现在已经有了“图”,只要给图附上合适的权值,就完成了所有任务。物体分割给人一个直观印象就是属于该物体的点,应该相互之间不会太远。也就是说,可以用点与点之间的欧式距离来构造权值。所有线的权值可映射为线长的函数。

                                                                 smoothCost=e^{-(\frac{dist}{ \sigma })^2}

     分割总是有一个目标的——目标需要人为指定(center),尺寸需要提前给出(radius)。

      我们指定了目标物体上的一个点,接下来要做的,就是让除此对象之外的物体被保护起来,保护的方法就是认为加重目标范围之外的权值(罚函数)

                              backgroundPenalty=(\frac{distanceToCenter}{radius})

    5、超体聚类分割方法

      超体(supervoxel)是一种集合,集合的元素是“体”。与体素滤波器中的体类似,其本质是一个个的小方块。与之前提到的所有分割手段不同,超体聚类的实质是对点云实施过分割(over segmentation),将场景点云化成很多小块,并研究每个小块之间的关系。将更小单元合并的分割思路。本质上这种方法是对局部的一种总结,纹理,材质,颜色类似的部分会被自动的分割成一块,有利于后续识别工作。比如对人的识别,如果能将头发,面部,四肢,躯干分开,则能更好的对各种姿态,性别的人进行识别。

     点云和图像不一样,其不存在像素邻接关系。所以,超体聚类之前,必须以八叉树对点云进行划分,获得不同点团之间的邻接关系。与图像相似点云的邻接关系也有很多,如面邻接,线邻接,点邻接。其具体解释如下图:

                          

      基于超体聚类的点云分割,使用点邻接(蓝色)作为相邻判据。

    超体聚类的实现步骤

        超体聚类实际上是一种特殊的区域生长算法,和无限制的生长不同,超体聚类首先需要规律的布置区域生长“晶核”。晶核在空间中实际上是均匀分布的,并指定晶核距离(Rseed)。再指定粒子距离(Rvoxel)。再指定最小晶粒(MOV),过小的晶粒需要融入最近的大晶粒。关系如图所示:

                                              

      有了晶粒和结晶范围之后,我们只需要控制结晶过程,就能将整个空间划分开了。结晶过程的本质就是不断吸纳类似的粒子(八分空间)。类似是一个比较模糊的概念,关于类似的定义有以下公式:

                                                   

       公式中的D_c表示颜色上的差异,D_n表示法线上的差异,D_s代表点距离上的差异。w_*表示一系列权重。用于控制结晶形状。在晶核周围寻找一圈,D最小的体素被认为是下一个“被发展的党员”。需要注意的是,结晶过程并不是长完一个晶核再长下一个,二是所有的晶核同时开始生长(虽然计算机计算时必然有先后,但从层次上来说是同时的)。其生长顺序如下图所示:

     

      接下来所有晶核继续公平竞争,发展第二个“党员”,以此循环,最终所有晶体应该几乎同时完成生长。整个点云也被晶格所分割开来。并且保证了一个晶包里的粒子都是类似的。

    6、基于凹凸型的分割

    对于二维图像而言,其凹凸性较难描述,但对于三维图像而言,凹凸几乎是与生俱来的性质。

    6.1、LCCP方法 

      LCCP是Locally Convex Connected Patches的缩写,翻译成中文叫做 ”局部凸连接“, LCCP方法并不依赖于点云颜色,所以只使用空间信息和法线信息。算法大致可以分成两个部分:

    1. 基于超体聚类的过分割。
    2. 在超体聚类的基础上再聚类。

    算法理论

      点云完成超体聚类之后,对于过分割的点云需要计算不同的块之间凹凸关系。凹凸关系通过 CC(Extended Convexity Criterion) 和 SC (Sanity criterion)判据来进行判断。其中 CC 利用相邻两片中心连线向量与法向量夹角来判断两片是凹是凸。显然,如果图中a1>a2则为凹,反之则为凸。

                                                   

      考虑到测量噪声等因素,需要在实际使用过程中引入门限值(a1需要比a2大出一定量)来滤出较小的凹凸误判。此外,为去除一些小噪声引起的误判,还需要引入“第三方验证”,如果某块和相邻两块都相交,则其凹凸关系必相同。CC 判据最终如CC_e

                                         

                                                       
       如果相邻两面中,有一个面是单独的,cc判据是无法将其分开的。举个简单的例子,两本厚度不同的书并排放置,视觉算法应该将两本书分割开。如果是台阶,则视觉算法应该将台阶作为一个整体。本质上就是因为厚度不同的书存在surface-singularities。为此需要引入SC判据,来对此进行区分。

                                                 

      如图所示,相邻两面是否真正联通,是否存在单独面,与θ角有关,θ角越大,则两面真的形成凸关系的可能性就越大。据此,可以设计SC判据:

      其中S(向量)为两平面法向量的叉积。最终,两相邻面之间凸边判据为:

      
       在标记完各个小区域的凹凸关系后,则采用区域增长算法将小区域聚类成较大的物体。此区域增长算法受到小区域凹凸性限制,既:只允许区域跨越凸边增长。

    6.2、CPC

      CPC方法的全称为Constrained Planar Cuts,和LCCP方法不同,此方法的分割对象是object。此方法能够将物体分成有意义的块:比如人的肢体等。

      本方法也需要先进行超体聚类。在完成超体聚类之后,采用和LCCP相同的凹凸性判据获得各个块之间的凹凸关系。在获得凹凸性之后,CPC方法所采取的措施是不同的。其操作称为半全局分割 。

      在分割之前,首先需要生成 EEC(Euclidean edge cloud), EEC的想法比较神奇,因为凹凸性定义在相邻两个”片“上,换言之,定义在连接相邻两“片”的edge上。将每个edge抽象成一个点云,则得到了附带凹凸信息的点云。如图所示,左图是普通点云,但附带了邻接和凹凸信息。右边是EEC,对凹边赋权值1,其他为0。此方法称作  weighted RanSac

                                            

     显而易见,某处如果蓝色的点多,那么就越,就越应该切开(所谓切开实际上是用平面划分)。问题就转化为利用蓝点求平面了。利用点云求一个最可能的平面当然需要请出我们的ransac但此处引入一个评价函数,用于评价此次分割的优良程度S_m,Pm 是EEC中的点.

                                                
     单纯的weighted RanSac算法并不够。其会导致对某些图形的错误分割,所以作者对此做了第一次“修补".错误的分割如下图所示

      此修补方法称作 directional weighted RanSac方法的原理很简单,垂直于凹边表面的点具有更高的权重,显然,对于EEC中的凹点,只要取其少量邻点即可估计垂直方向。这种修补后还有一个问题,如果这个分割面过长的情况下,有可能会误伤。如图所示:

      于是有了第二种修补方法,称为:Locally constrained cutting这种修补方法的原理就更加简单粗暴了,对凹点先进行欧式分割(限制增长上限),之后再分割所得的子域里进行分割。

    展开全文
  • C++常用字符串分割方法

    万次阅读 2017-02-17 10:54:00
    C++常用字符串分割方法

    From:http://www.jb51.net/article/55954.htm



    1. 用strtok函数进行字符串分割


    原型:       char *strtok(char *str, const char *delim);
    功能:       分解字符串为一组字符串。
    参数说明:str为要分解的字符串,delim为分隔符字符串。
    返回值:    从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。
    其它:       strtok函数线程不安全,可以使用strtok_r替代。

    代码示例:

    //借助strtok实现split
    #include <string.h>
    #include <stdio.h>
    
    int main()
    {
        char chArry[] = "one two   three,four * five";
        const char *d = " ,*";
        char *p;
        p = strtok(s,d);
        while(p != NULL)
        {
            printf("%s\n", p);
            p=strtok(NULL, d);
        }
        return 0;
    }



    2. 用STL进行字符串的分割


    涉及到string类的两个函数find和substr:

    1、find函数
            原型:       size_t find ( const string& str, size_t pos = 0 ) const;
            功能:       查找子字符串第一次出现的位置。
            参数说明:str为子字符串,pos为初始查找位置。
            返回值:    找到的话返回第一次出现的位置,否则返回string::npos
    2、substr函数
            原型:       string substr ( size_t pos = 0, size_t n = npos ) const;
            功能:       获得子字符串。
            参数说明:pos为起始位置(默认为0),n为结束位置(默认为npos)
            返回值:    子字符串


    示例代码:

    #include <iostream>
    #include <string>
    #include <vector>
    
    //字符串分割函数
    std::vector<std::string> split(std::string str,std::string pattern)
    {
        std::string::size_type pos;
        std::vector<std::string> result;
        
        str+=pattern;//扩展字符串以方便操作
        int size=str.size();
        
        for(int i=0; i<size; i++)
        {
            pos=str.find(pattern,i);
            if(pos<size)
            {
                std::string s=str.substr(i,pos-i);
                result.push_back(s);
                i=pos+pattern.size()-1;
            }
        }
        return result;
    }
    
    int main()
    {
        std::string str;
        std::cout<<"Please input str:"<<std::endl;
        //std::cin>>str;
        getline(std::cin,str);
        std::string pattern;
        std::cout<<"Please input pattern:"<<std::endl;
        //std::cin>>pattern;
        getline(std::cin,pattern);//用于获取含空格的字符串
        std::vector<std::string> result=split(str,pattern);
        std::cout<<"The result:"<<std::endl;
        for(int i=0; i<result.size(); i++)
        {
            std::cout<<result[i]<<std::endl;
        }
        
        std::cin.get();
        std::cin.get();
        return 0;
    }


    find_first_not_of

    #include<string>
    #include<vector>
    #include<iostream>
    using namespace std;
    
    void Tokenize(const string& str, vector<string>& tokens, const string& delimiters)
    {
        // Skip delimiters at beginning.
        string::size_type lastPos = str.find_first_not_of(delimiters, 0);
        // Find first "non-delimiter".
        string::size_type pos = str.find_first_of(delimiters, lastPos);
        while (string::npos != pos || string::npos != lastPos)
        {
            // Found a token, add it to the vector.
            tokens.push_back(str.substr(lastPos, pos - lastPos));
            // Skip delimiters.  Note the "not_of"
            lastPos = str.find_first_not_of(delimiters, pos);
            // Find next "non-delimiter"
            pos = str.find_first_of(delimiters, lastPos);
        }
    }
    int main(int argc, char *argv[])
    {
        string str("====aaa==bbb=ccc=ddd====");
        vector<string>tokens;
        Tokenize(str, tokens, "=");
        for( int i = 0; i < tokens.size() ; i++ )
        {
            cout << tokens[i] << endl;
        }
        return 0;
    }



    3. 用Boost进行字符串的分割


    用boost库的正则表达式实现字符串分割

    示例代码:

    #include <iostream>
    #include <cassert>
    #include <vector>
    #include <string>
    #include "boost/regex.hpp"
     
    std::vector<std::string> split(std::string str,std::string s)
    {
        boost::regex reg(s.c_str());
        std::vector<std::string> vec;
        boost::sregex_token_iterator it(str.begin(),str.end(),reg,-1);
        boost::sregex_token_iterator end;
        while(it!=end)
        {
            vec.push_back(*it++);
        }
        return vec;
    }
    int main()
    {
        std::string str,s;
        str="sss/ddd/ggg/hh";
        s="/";
        std::vector<std::string> vec=split(str,s);
        for(int i=0,size=vec.size();i<size;i++)
        {
            std::cout<<vec[i]<<std::endl;
        }
        std::cin.get();
        std::cin.get();
        return 0;
    }


    boost里面有自带的split的函数,如果用boost的话,还是直接用split的好

    示例代码:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <boost/algorithm/string/classification.hpp>
    #include <boost/algorithm/string/split.hpp>
    
    using namespace std;
    
    int main()
    {
        string s = "sss/ddd,ggg";
        vector<string> vStr;
        boost::split( vStr, s, boost::is_any_of( ",/" ), boost::token_compress_on );
        for( vector<string>::iterator it = vStr.begin(); it != vStr.end(); ++ it )
            cout << *it << endl;
        return 0;
    }





    展开全文
  • Java中字符串String的常用分割方法

    千次阅读 2016-05-30 11:22:34
    本文主要介绍了三种方法进行字符串的分割,以后如果学到新的方法会进行更新。

    分割字符串的几种方法

    1. split()方法分割

    split参数为一个字符串,将目标字符串按照参数进行分割,得到一个数组,示例如下:

    //示例代码
    public class AA {
     public static void main(String[] args) {
     //示例字符串""
      String s="a,b,c";
      String a[]=s.split(",");
      for(int i=0;i<a.length;i++){
       System.out.println(a[i]);
      }
     }
    }
    /*运行结果:
    a
    b
    c
    */

    2.用StringTokenizer类分割

    public class A {
        public static void main(String[] args) {
            String ip = "192.168.1.1";
            StringTokenizer token=new StringTokenizer(ip,".");  
            while(token.hasMoreElements()){  
             System.out.print(token.nextToken()+" ");  
            } 
        }
    }
    //运行结果:192 168 1 1

    3.利用方法subString()分割

    用indexOf确定要分割字符串所在的位置,用subString进行分割

    public class A {
        public static void main(String[] args) {
            String str1 = "1234567890";
            int i = str1.indexOf("5");
            String left = str1.substring(0,i);
            String right = str1.substring(i+1,str1.length());
            System.out.println(left);
            System.out.println(right);
            }
    
    }
    /*运行结果:
    1234
    67890
    */
    展开全文
  • 常用数字图像分割方法

    千次阅读 2018-11-05 06:52:50
    图像分割是一种重要的图像处理技术。 人们在对图像的认知,理解和应用中,往往仅对其中的某些特定部分感兴趣,这些部分通常被称为目标或前景,它们一般对应图像中特定的,具有独特性质的区域。 这里所说的特定部分...

    图像分割是一种重要的图像处理技术。

    人们在对图像的认知,理解和应用中,往往仅对其中的某些特定部分感兴趣,这些部分通常被称为目标或前景,它们一般对应图像中特定的,具有独特性质的区域。

    这里所说的特定部分的独特性质可以是灰度值,目标的轮廓,图形的纹理,颜色等。

    在图像处理中有时候会需要对图像中的特定目标进行分析处理,这时候就需要首先将它们从图像中提取出来,在此基础上才能进一步对特定目标进行分析。

    图像分割是根据图像的应用需求或组成结构将图像划分成若干个互不相交的子区域的过程。

    这些子区域指的是某种意义下具有共同属性的像素的连通集合。

    例如图像中特定形状目标所占的连通区域、图像背景所占的连通区域等。

    在图像处理中,连通指的是集合中任意两点之间都存在完全属于该集合的连通路径。

    连通包含4连通和8连通两种情况,如下图所示。

    4连通是指从该区域内任一点出发,在不超过该区域的前提下,可以通过上、下、左、右4个方向移动的组合,从而到达该区域内的任意像素点;同理8连通是从区域内任意一点出发,在不超过该区域的前提下,通过8个方向,即上、下、左、右、左上、左下、右上、右下移动的组合,从而到达该区域内的任意像素点。

    四连通和八连通示意图

    根据上述连通基本概念,可以给出图像分割的一般定义,即图像分割是指将一幅离散数字图像信号f(m,n)进行分割,将f分割为若干连通的、非空的子区域f1,f2,…fn,并且要满足以下均一性准则。

    1) f1∪f2∪…∪fn =f .

    2) "i ,当i=1,2…n时,fi是连通的。

    3) "fi均一性准则都是满足的。

    4) 对于任意两个相连的fifj ,E(fifj)=f.

    上述条件(1)说明了分割得到的所有子区域的并集应该包含图像中所有像素,即图像分割不能漏掉任何像素;条件(2)说明了分割得到的子区域的连通性;条件(3)说明分割得到的子区域都有其本身的特性,即在各个子区域内像素性质是相似均一的;条件(4)指出任何两个子区域都不重叠,即同一个像素不会被分在两个不同的子区域中。

    根据以上图像分割的定义,人们已经研究出了上千种不同的图像分割方法,典型而传统的方法可以分为基于阈值的方法、基于边缘的方法和基于区域的分割方法等。

    灰度阈值法分割

    常用的阈值化分割方法是将图像的灰度分成不同的级别,然后设置灰度门限值,再基于这个门限值将图像分割为不同的区域。

    阈值化分割由于其直观性和易操作性成为最常见的图像分割方法之一。

    图像分割阈值化处理的公式如下:

    上式所反应的阈值化处理是一种阶梯函数,其变换曲线如下图所示。

    可以看见,它的功能是以一定方式指定一个门限值,如果图像中某个灰度值大于该门限值,则将其置为一,否则,置为零。

    由于基于灰度阈值的分割方法是一种“一刀切”的分割方式。

    阈值的合理选取就对图像处理的结果有相当大的影响,若阈值选取过大,则会出现提取了图像的多余部分的情况;若阈值过小,则又会出现丢失感兴趣部分的情况。

    对于合理的选取分割阈值目前已经有很多成熟的方法可以借鉴,如最小误差阈值法,最大方差阈值法,最佳阈值法,差别分析法等。

    边缘检测法分割

    物体的边缘是图像局部亮度变化最显著的部分。

    利用边缘检测来分割图像,其基本思想是先检测边缘点,再按照一定方法将边缘点连接成边缘线,从而分割图像区域。

    边缘检测技术是数字图像处理中的一项非常重要的技术。

    由于图像上边缘线邻域是图像中一个灰度级变化比较剧烈的地带,衡量这种变化最有效的两个特征就是变化率和变化方向。

    从数学上来讲就是梯度向量的幅值和方向。

    因此对于一幅图像f(x,y)来讲,求其梯度的局部最大值和方向即为边缘检测。

    已知f(x,y)q方向沿r的梯度定义如下:

    达到最大值的条件是,即

    得到,或者

    梯度最大值,一般称其为梯度模。

    梯度模算子具有各向同性和位移不变性,适用于边缘检测,而灰度变化的方向,

    即边界的方向则可由计算得到。

    在实际应用中,一般以微分算子的形式表示,以卷积函数来实现,常用的算子有Roberts 算子、Prewitt算子、 Sobel算子等。

    其外,还有利用拐点位置处的二阶导数为0来检测边缘线的方法,如Laplacian算子就是最为常用的二阶导数算子。

    Laplacian算子对灰度突变比一般的一阶导数算子更加敏感,它虽然可以检测出绝大部分的边缘,但也存在一些缺点,如边缘不够连续、容易丢失一些边缘、不能获得边缘方向信息、对噪声敏感等。

    在使用Laplacian算子之前需要对图像做平滑处理。

    还有一个重要的边缘检测算子Canny算子,从一定意义上讲,它对受白噪声影响的阶跃型边缘检测是最优的。

    Canny边缘检测的基本思想是:首先使用Gauss滤波器对图像进行平滑滤波,再求取一阶偏导,最后对求导后的图像进行非极大值抑制,得到最后的边缘图像。

    它是具有图像平滑功能的边缘检测算子。

    区域分割

    区域分割法利用同区域内像素灰度值的相似性,将相似的区域合并,不相似的区域分割开。

    该方法认为分割出来的同一区域的像素有着相同或相似的性质,最为常见的区域分割方法有区域生长法和分裂合并法。

    区域生长法的基本思想是将具有相似性质的像素集合起来生长成为特定区域。

    其具体步骤是:首先在每个需要分割的区域内找到一个像素点作为该区域的种子点;然后按照一定的连通规则将种子点周围与其有相似性质的像素,按照一定准则合并到种子点的区域中;最后将这些新像素当作新的种子点继续以上步骤。

    区域生长法要首先解决的三个问题是:

    1)选择一组正确代表所需区域数目的种子点;

    2)确定生长准则;

    3)确定生长过程停止的条件。

    根据所需邻域和生长准则的不同,区域生长法可分为简单生长法、质心生长法、混合生长法等。

    分裂合并法是在事先完全不了解区域形状和区域数目时可采用的方法。

    这种方法先将图像分解成互不重叠、任意大小的区域,再按相似准则进行合并。

    这种分裂合并方法有一个方便的表示方法—四叉树,即将整个图像表示成一棵树,树中的每个节点都有四个后代,树可以一层一层被细分开来。

    如下图所示,设R0代表整个图像区域,从最高层开始,按照一定的相似性准则,将图像一层一层分裂,直到不能分为止。

    仅仅使用分裂是不够的,最后很有可能出现相邻的两个区域属于同一个目标的情况。

    为解决这一问题,在分裂后需要对图像进一步合并。

    合并过程只是合并相邻的区域,且经过合并组成的新区域需要满足一定的一致性测度准则。

    图像区域及四叉树

    可以将分裂合并算法总结为如下的步骤:

    1)给定一定相似性准则P,若对图像中的任一区域Ri,有P(Ri)=false,即不满足相似性准则,则将Ri 区域等分为四份子区域Ri1,Ri2,Ri3,Ri4 。

    2)对于相邻的区域Ri,Rj 若P(Ri ∪Ri)=true,则合并这两个区域。

    3)继续以上步骤直到分裂合并都不能进行时。

    最大类间方差阈值分割

    最大类间方差算法也叫大津算法,是1980年有日本学者大津提出的。

    最大类间方差法的原理是按照灰度特性将待分割图像分为背景和目标两部分,将背景和目标看作是两类,这两类间的方差越大,则说明其差别就越大,也就是说将目标类错分为背景或是将背景类错分为目标的概率就越小,因此使类间方差达到最大的分割就意味着此时的分割效果最好,错分概率最小。

    设一幅图像的灰度值为1~m级,灰度值i的像素数为ni,这时可以得到:

    像素总数为:

    各个灰度值的概率为:

    再用阈值T将其分为两组C0={1~T}和C1={T+1~m},各组产生的概率由下式给出。

    C0 产生的概率为:

    C1 产生的概率为:

    C0 的平均值为:

    C1的平均值为:

    其中,是整个图像的灰度平均值;指灰度为T的灰度均值,

    因此全部采样的灰度均值为:

    下式给出两组之间的方差:

    实际运用时,我们在1~m范围内改变T,求方差为最大时的T值,此时确定的T* 便是最大类间方差算法的阈值。

    此方法被公认为是阈值自动选择的最优方法。

    展开全文
  • Nginx常用日志分割方法

    千次阅读 2016-04-04 10:26:07
    nginx cronolog日志分割配置文档,根据下面方法,每分钟分割一次NGINX访问日志。 1.nginx日志配置 access_log access_log /data/access_log_pipe main; 2.先创建一个命名管道 mkfifo /www/log/access_log_pipe 3....
  • 几种常用的图像分割方法

    千次阅读 2018-11-20 16:43:26
    图像分割有很多各种各样的方法:1)基于数学统计的方法(灰度直方图)2)基于纹理的方法3)基于阈值的方法4)基于深度学习的方法5)基于几何数学的方法。当然这五种方法也可以交叉使用,总之,挑选适用的方法效率...
  • C++常用字符串分割方法实例汇总

    千次阅读 2016-09-07 14:01:06
    C++常用字符串分割方法实例汇总
  • 图像分割常用方法

    千次阅读 2017-04-14 17:01:47
    图像分割(Segmentation)指的是将数字图像细分为多个图像子区域(像素的集合)(也被称作超像素)的过程,就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析...
  • 图像处理——常用阈值分割方法及源码

    万次阅读 多人点赞 2018-07-18 20:37:18
    1、Otsu阈值分割 2、自适应阈值分割 3、 最大熵阈值分割法 4、 迭代阈值分割  5、测验   1、Otsu阈值分割  Otsu(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,...
  • 承接上一期描述的话题分割的任务定义和评估方法,在本文中,我们将去了解5个话题分割常用的语料库,以及4大类常用的话题分割的模型和方法,供大家学习和参考。
  • js常用分割取字符串的方法

    万次阅读 2017-10-31 10:24:41
    lastIndexOf()方法返回从右向左出现某个字符或字符串的首个字符索引值(与indexOf相反) var src= "images/off_1.png" ; alert(src .lastIndexOf ( '/' )) ; alert(src .lastIndexOf ( 'g' )) ; 弹出值...
  • iOS字符串分割常用方法

    万次阅读 多人点赞 2015-10-21 10:35:46
    1.字符串的替换: NSString *str=@"12334dllggg33dlrt "; str=[str stringByReplacingOccurrencesOfString:@"33" withString:@"hh"]; NSLog(@"%@",str); ...2.通过range分割字符串
  • 图像分割常用方法介绍

    千次阅读 2017-04-14 17:12:06
    图像分割(Segmentation)指的是将数字图像细分为多个图像子区域(像素的集合)(也被称作超像素)的过程,就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析...
  • 图像语义分割原理及常用方法

    千次阅读 2020-04-17 11:03:50
    1图像语义分割的概念 1.1图像语义分割的概念与原理 图像语义分割可以说是图像理解的基石性技术,在自动驾驶系统(具体为街景识别与理解)、无人机应用(着陆点判断)以及穿戴式设备应用中举足轻重。我们都知道,...
  • MFC中几种常用的字符串分割方法

    万次阅读 多人点赞 2016-01-05 20:29:01
    本文总结了几种常用的MFC字符串分割方法,以方便自己以后查阅,也希望能帮助到需要帮助的人。 1、CString 自带的函数Tokenize 1 CStringT Tokenize( _In_ PCXSTR pszTokens,...
  • 常见的图像分割方法有以下几种

    万次阅读 多人点赞 2018-04-19 18:33:08
    常见的图像分割方法有以下几种:1.基于阈值的分割方法 灰度阈值分割法是一种最常用的并行区域技术,它是图像分割中应用数量最多的一类。阈值分割方法实际上是输入图像f到输出图像g的如下变换: 其中,T为阈值;...
  • JS分割字符串常用方法总结

    千次阅读 2018-10-10 20:39:06
    定义:lastIndexOf()方法返回从右向左出现某个字符或字符串的首个字符索引值(与indexOf相反) 功能:返回字符串索引值 例子: var src="images/off_1.png"; alert(src.lastIndexOf('/')); alert...
  • 1图像语义分割的概念1.1图像语义分割的概念与原理图像语义分割可以说是图像理解的基石性技术,在自动驾驶系统(具体为街景识别与理解)、无人机应用(着陆点判断)以及穿戴式设备应用中举足轻重。我们都知道,图像...
  • 纹理图像分割常用方法概述

    千次阅读 2017-06-23 11:52:07
    纹理图像在局部区域内呈现了不规则性,而在整体上表现出某种规律性。纹理基元的排列可能是随机的,也可能是相互之间互相依赖,这种依赖性可能是结构的,也可能是按某种概率分布排列...
  • 一个月中多少天 is_month_start 是否月初第一天 is_month_end 是否月末最后一天 is_quarter_start 是否季度的最开始 is_quarter_end 是否季度的最后一个 is_year_start ...
  • 图像分割与视频分割方法

    千次阅读 2019-05-12 12:15:54
    图像分割传统的图像分割方法1、基于阈值的图像分割单阈值分割局部阈值分割阈值的选取2、基于区域的图像分割区域生长区域分裂合并四叉树分解法3、基于边缘检测的图像分割结合特定工具的图像分割算法1、基于小波分析和...
  • 语义分割分割常用网络

    千次阅读 2020-04-26 16:25:30
    语义分割 图像的语义分割是将输入图像中的每个像素分配一个语义类别,以得到像素化的密集分类。 一般的语义分割架构可以被认为是一个编码器-解码器网络。编码器通常是一个预训练的分类网络,像 VGG、ResNet,然后...
  • 4 深度学习图像分割常用方法 深度学习在多种高级计算机视觉任务中的成功—特别是监督CNNs(Convolutional Neural Networks,卷积神经网络)在图像分类、对象检测方面的成功—鼓舞着研究人员探索此类网络对于像素...
  • 数字图像处理中常用图像分割算法哪些? 1.多数的图像分割算法 2.图像边缘分割 3.图像阈值分割 4.基于区域的分割 5.形态学分水岭算法 多数的图像分割算法 均是基于灰度值的不连续和相似的性质。在前者中,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 219,463
精华内容 87,785
关键字:

常用的分割方法有