图像分割_区域分裂合并

2024-09-05 10:48

本文主要是介绍图像分割_区域分裂合并,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://blog.csdn.net/cay22/article/details/5666109

区域分裂合并算法的基本思想是先确定一个分裂合并的准则,即区域特征一致性的测度,当图像中某个区域的特征不一致时就将该区域分裂成4 个相等的子区域,当相邻的子区域满足一致性特征时则将它们合成一个大区域,直至所有区域不再满足分裂合并的条件为止.   当分裂到不能再分的情况时,分裂结束,然后它将查找相邻区域有没有相似的特征,如果有就将相似区域进行合并,最后达到分割的作用。   在一定程度上区域生长和区域分裂合并算法有异曲同工之妙,互相促进相辅相成的,区域分裂到极致就是分割成单一像素点,然后按照一定的测量准则进行合并,在一定程度上可以认为是单一像素点的区域生长方法。   区域生长比区域分裂合并的方法节省了分裂的过程,而区域分裂合并的方法可以在较大的一个相似区域基础上再进行相似合并,而区域生长只能从单一像素点出发进行生长(合并)。

 

反复进行拆分和聚合以满足限制条件的算法。

令R表示整幅图像区域并选择一个谓词P。对R进行分割的一种方法是反复将分割得到的结果图像再次分为四个区域,直到对任何区域Ri,有P(Ri)=TRUE。这里是从整幅图像开始。如果P(R)=FALSE,就将图像分割为4个区域。对任何区域如果P的值是FALSE.就将这4个区域的每个区域再次分别分为4个区域,如此不断继续下去。这种特殊的分割技术用所谓的四叉树形式表示最为方便(就是说,每个非叶子节点正好有4个子树),这正如图10.42中说明的树那样。注意,树的根对应于整幅图像,每个节点对应于划分的子部分。此时,只有R4进行了进一步的再细分。

如果只使用拆分,最后的分区可能会包含具有相同性质的相邻区域。这种缺陷可以通过进行拆分的同时也允许进行区域聚合来得到矫正。就是说,只有在P(Rj∪Rk)=TRUE时,两个相邻的区域Rj和Rk才能聚合。

前面的讨论可以总结为如下过程。在反复操作的每一步,我们需要做:

l.对于任何区域Ri,如果P(Ri)=FALSE,就将每个区域都拆分为4个相连的象限区域。

2.将P(Rj∪Rk)=TRUE的任意两个相邻区域Rj和Rk进行聚合。

3.当再无法进行聚合或拆分时操作停止。

可以对前面讲述的基本思想进行几种变化。例如,一种可能的变化是开始时将图像拆分为一组图象块。然后对每个块进一步进行上述拆分,但聚合操作开始时受只能将4个块并为一组的限制。这4个块是四叉树表示法中节点的后代且都满足谓词P。当不能再进行此类聚合时,这个过程终止于满足步骤2的最后的区域聚合。在这种情况下,聚合的区域可能会大小不同。这种方法的主要优点是对于拆分和聚合都使用同样的四叉树,直到聚合的最后一步。

 

例10.17 拆分和聚合

图10.43(a)显示了一幅简单的图像。如果在区域Ri内至少有80%的像素具有zj-mi≤2σi的性质,就定义P(Ri)=TRUE,这里zj是Ri内第j个像素的灰度级,mi是区域Ri的灰度级均值,σi是区域Ri内的灰度级的标准差。如果在此条件下,P(Ri)=TRUE,则设置Ri内的所有像素的值等于mi。拆分和聚合使用前速算法的要点完成。将这种技术应用于图10.43(a)所得结果示于图10.43(b)。请注意,图像分割效果相当好。示于图10.43(c)中的图像是通过对图10.43(a)进行门限处理得到的,门限值选在直方图中两个主要的尖峰之间的中点。经过门限处理,图像中生成的阴影(和叶子的茎)被错误地消除了。

 

如前面的例子中所使用的属性那样,我们试图使用基于区域中像素的均值和标准差的某些特性对区域的纹理进行量化(见11.3.3节中关于纹理的讨论)。纹理分割的概念是以在谓词P(Ri)中使用有关纹理的量度为基础的。就是说,通过指定基于纹理内容的谓词,我们可以使用本节中讨论的任何方法进行纹理分割。

 

 

 

1.       把一幅图像分成4份,计算每一份图像的最大灰度值与最小灰度值的差, 如果差在误差范围值外,则该份图像继续分裂。

2.       对于那些不需要分裂的那些份图像可以对其进行阈值切割了,例如某一块图像的最大灰度大于某个值,则该块图像变成255,否则变为0。

 

// 代码

// 区域分裂合并的图像分割

// nOffSetLne是行偏移量

 

// 由于分裂的层数太多了, 使用递归将使内存空间堆栈溢出

// 解决方法是使用一个堆栈对要分裂的块入栈

// 使用堆栈的方法类似在"区域生长"的实现方法

#include <stack>

struct SplitStruct

{

     unsigned int nWidth;                 // 这一块图像的宽度

     unsigned int nHeigh;                 // 这一块图像的高度

     unsigned int nOffSetWidth;           // 相对源图像数据的偏移宽度

     unsigned int nOffSetHeigh;           // 相对源图像数据的偏移高度

};

void AreaSplitCombineEx(BYTE* image0,              // 源图像数据

                         unsigned int nAllWidth,        // 源图像的宽度

                         unsigned int nAllHeigh,        // 源图像的高度

                         unsigned int w,                // 这一块图像的宽度

                         unsigned int h,                // 这一块图像的高度

                         unsigned int nOffSetWidth,     // 相对源图像数据的偏移宽度

                         unsigned int nOffSetHeigh)     // 相对源图像数据的偏移高度

{

 

     std::stack<SplitStruct> nMyStack;

 

     SplitStruct splitStruct, splitStructTemp;

     splitStruct.nWidth          = w;

     splitStruct.nHeigh          = h;

     splitStruct.nOffSetWidth    = nOffSetWidth;

     splitStruct.nOffSetHeigh    = nOffSetHeigh;

 

     nMyStack.push(splitStruct);

    

     int i, j;

     int nValueS[2][2];     // 用于存储块图像的属性值(该属性值= 该块图像的所有像素灰度值之和除以该块图像所有像素点的数量)

     int nAV;

     int nWidthTemp[3], nHeightTemp[3], nTemp;

     int nWidth, nHeigh;

     int n, m, l;

     double dOver;

 

 

     while(!nMyStack.empty())

     {

         splitStruct = nMyStack.top();

         nMyStack.pop();

 

 

         n = (splitStruct.nOffSetHeigh * nAllWidth + splitStruct.nOffSetWidth);     // 该块图像的左上角

         // 1. 把图像分成2 * 2 块,

         nWidthTemp[0] = 0;

         nWidthTemp[2] = (splitStruct.nWidth + 1) / 2;

         nWidthTemp[1] = splitStruct.nWidth - nWidthTemp[2];

 

         nHeightTemp[0] = 0;

         nHeightTemp[2] = (splitStruct.nHeigh + 1) / 2;

         nHeightTemp[1] = splitStruct.nHeigh - nHeightTemp[2];

 

         // 计算每一块图像的属性值

         int nValue;

         int nValueTemp;

         nAV = 0;

         for(i = 1; i < 3; ++i)

         {

              for(j = 1; j < 3; ++j)

              {

                   nValue = 0;

                   m = (n + nAllWidth * nHeightTemp[i - 1] + nWidthTemp[j - 1]);

                   for(nHeigh = 0; nHeigh < nHeightTemp[i]; ++nHeigh)

                   {

                       for(nWidth = 0; nWidth < nWidthTemp[j]; ++nWidth)

                       {

                            l = (m + nAllWidth * nHeigh + nWidth) * 4;

                            nValueTemp = (0.299 * image0[l] + 0.587 * image0[l + 1] + 0.114 * image0[l + 2]);

                            // 灰度值之和

                            nValue += nValueTemp;

                       }

                   }

 

                   if(nHeightTemp[i] * nWidthTemp[j] == 0)

                   {

                       continue;

                   }

                   if(nHeightTemp[i] * nWidthTemp[j] == 1)

                   {

                       l = m * 4;

                       if((0.299 * image0[l] + 0.587 * image0[l + 1] + 0.114 * image0[l + 2]) < 125)

// 这个值可以动态设定

                       {

                            image0[l] = image0[l + 1] = image0[l + 2] = 0;

                            image0[l + 3] = 255;

                       }

                       else

                       {

                            image0[l] = image0[l + 1] = image0[l + 2] = 255;

                            image0[l + 3] = 255;

                       }

                       continue;

                   }

 

                   // 各块图像的灰度平均值(每一块图像的属性值)

                   nValueS[i - 1][j - 1] = nValue / (nHeightTemp[i] * nWidthTemp[j]);

                   // 2. 对每一块进行判断是否继续分裂(注意分裂的原则)

                   // 我这里的分裂原则是: 图像的属性值在属性值平均值的误差范围之内就不分裂

                   if(nValueS[i - 1][j - 1]  < 220)     // 灰度平均值少于200 需要继续分裂 // 这里就是分裂准则了

                   {

                       splitStructTemp.nWidth           = nWidthTemp[j];

                       splitStructTemp.nHeigh           = nHeightTemp[i];

                       splitStructTemp.nOffSetWidth     = splitStruct.nOffSetWidth + nWidthTemp[j - 1];

                       splitStructTemp.nOffSetHeigh     = splitStruct.nOffSetHeigh + nHeightTemp[i - 1];

                       nMyStack.push(splitStructTemp);

                   }

                   else                                      // 合并(直接填充该块图像为黑色)

                   {

                       // 3. 如果不需要分裂, 则进行合并

                       for(nHeigh = 0; nHeigh < nHeightTemp[i]; ++nHeigh)

                       {

                            for(nWidth = 0; nWidth < nWidthTemp[j]; ++nWidth)

                            {

                                 l = (m + nAllWidth * nHeigh + nWidth) * 4;

                                 image0[l] = image0[l + 1] = image0[l + 2] = 255;

                                 image0[l + 3] = 255;

                            }

                       }

                   }

              }

         }

     }

 

     return;

}

 

该代码的效果也不是太好,主要是分裂准则不好确定

 

区域分裂合并中 最初使用每块图像区域中极大与极小灰度值之差是否在允许的偏差范围来作为均匀性测试准则。 后来均匀性测试准则又被不断的发展。目前,统计检验,如均方误差最小, F检测等都是最常用的均匀性测试准侧方法。

 

看均方误差最小的情况

 

 

其中C是区域R中N个点的平均值。

 

相对于区域生长而言,区域分割于合并技术不再依赖于种子点的选择与生长顺序。但选用合适的均匀性测试准则P对于提高图像分割质量十分重要,当均匀性测试准则P选择不当时,很容易会引起“方块效应”

这篇关于图像分割_区域分裂合并的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138747

相关文章

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

【Python从入门到进阶】64、Pandas如何实现数据的Concat合并

接上篇《63.Pandas如何实现数据的Merge》 上一篇我们学习了Pandas如何实现数据的Merge,本篇我们来继续学习Pandas如何实现数据的Concat合并。 一、引言 在数据处理过程中,经常需要将多个数据集合并为一个统一的数据集,以便进行进一步的分析或建模。这种需求在多种场景下都非常常见,比如合并不同来源的数据集以获取更全面的信息、将时间序列数据按时间顺序拼接起来以观察长期趋势等

【python计算机视觉编程——7.图像搜索】

python计算机视觉编程——7.图像搜索 7.图像搜索7.1 基于内容的图像检索(CBIR)从文本挖掘中获取灵感——矢量空间模型(BOW表示模型)7.2 视觉单词**思想****特征提取**: 创建词汇7.3 图像索引7.3.1 建立数据库7.3.2 添加图像 7.4 在数据库中搜索图像7.4.1 利用索引获取获选图像7.4.2 用一幅图像进行查询7.4.3 确定对比基准并绘制结果 7.

【python计算机视觉编程——8.图像内容分类】

python计算机视觉编程——8.图像内容分类 8.图像内容分类8.1 K邻近分类法(KNN)8.1.1 一个简单的二维示例8.1.2 用稠密SIFT作为图像特征8.1.3 图像分类:手势识别 8.2贝叶斯分类器用PCA降维 8.3 支持向量机8.3.2 再论手势识别 8.4 光学字符识别8.4.2 选取特征8.4.3 多类支持向量机8.4.4 提取单元格并识别字符8.4.5 图像校正

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户