区域分裂合并

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

区域分裂合并
区域分裂合并算法的基本思想是先确定⼀个分裂合并的准则,即区域特征⼀致性的测度,当图像中某个区域的特征不⼀致时就将该区域分裂成4个相等的⼦区域,当相邻的⼦区域满⾜⼀致性特征时则将它们合成⼀个⼤区域,直⾄所有区域不再满⾜分裂合并的条件为⽌. 当分裂到不能再分的情况时,分裂结束,然后它将查找相邻区域有没有相似的特征,如果有就将相似区域进⾏合并,最后达到分割的作⽤。

在⼀定程度上区域⽣长和区域分裂合并算法有异曲同⼯之妙,互相促进相辅相成的,区域分裂到极致就是分割成单⼀像素点,然后按照⼀定的测量准则进⾏合并,在⼀定程度上可以认为是单⼀像素点的区域⽣长⽅法。

区域⽣长⽐区域分裂合并的⽅法节省了分裂的过程,⽽区域分裂合并的⽅法可以在较⼤的⼀个相似区域基础上再进⾏相似合并,⽽区域⽣长只能从单⼀像素点出发进⾏⽣长(合并)。

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

令R表⽰整幅图像区域并选择⼀个谓词P。

对R进⾏分割的⼀种⽅法是反复将分割得到的结果图像再次分为四个区域,直到对任何区域R i,有P(R i)=TRUE。

这⾥是从整幅图像开始。

如果P(R)=FALSE,就将图像分割为4个区域。

对任何区域如果P的值是FALSE.就将这4个区域的每个区域再次分别分为4个区域,如此不断继续下去。

这种特殊的分割技术⽤所谓的四叉树形式表⽰最为⽅便(就是说,每个⾮叶⼦节点正好有4个⼦树),这正如图10.42中说明的树那样。

注意,树的根对应于整幅图像,每个节点对应于划分的⼦部分。

此时,只有R4进⾏了进⼀步的再细分。

如果只使⽤拆分,最后的分区可能会包含具有相同性质的相邻区域。

这种缺陷可以通过进⾏拆分的同时也允许进⾏区域聚合来得到矫正。

就是说,只有在P(R j∪R k)=TRUE时,两个相邻的区域R j和R k才能聚合。

前⾯的讨论可以总结为如下过程。

在反复操作的每⼀步,我们需要做:
l.对于任何区域R i,如果P(R i)=FALSE,就将每个区域都拆分为4个相连的象限区域。

2.将P(R j∪R k)=TRUE的任意两个相邻区域R j和R k进⾏聚合。

3.当再⽆法进⾏聚合或拆分时操作停⽌。

可以对前⾯讲述的基本思想进⾏⼏种变化。

例如,⼀种可能的变化是开始时将图像拆分为⼀组图象块。

然后对每个块进⼀步进⾏上述拆分,但聚合操作开始时受只能将4个块并为⼀组的限制。

这4个块是四叉树表⽰法中节点的后代且都满⾜谓词P。

当不能再进⾏此类聚合时,这个过程终⽌于满⾜步骤2的最后的区域聚合。

在这种情况下,聚合的区域可能会⼤⼩不同。

这种⽅法的主要优点是对于拆分和聚合都使⽤同样的四叉树,直到聚合的最后⼀步。

例10.17 拆分和聚合
图10.43(a)显⽰了⼀幅简单的图像。

如果在区域R i内⾄少有80%的像素具有z j-m i≤2σi的性质,就定义P(R i)=TRUE,这⾥z j是R i内第j个像素的灰度级,m i是区域R i的灰度级均值,σi是区域R i内的灰度级的标准差。

如果在此条件下,P(R i)=TRUE,则设置R i内的所有像素的值等于
m i。

拆分和聚合使⽤前速算法的要点完成。

将这种技术应⽤于图10.43(a)所得结果⽰于图10.43(b)。

请注意,图像分割效果相当好。

⽰于图10.43(c)中的图像是通过对图10.43(a)进⾏门限处理得到的,门限值选在直⽅图中两个主要的尖峰之间的中点。

经过门限处理,图像中⽣成的阴影(和叶⼦的茎)被错误地消除了。

如前⾯的例⼦中所使⽤的属性那样,我们试图使⽤基于区域中像素的均值和标准差的某些特性对区域的纹理进⾏量化(见11.3.3节中关于纹理的讨论)。

纹理分割的概念是以在谓词P(R i)中使⽤有关纹理的量度为基础的。

就是说,通过指定基于纹理内容的谓词,我们可以使⽤本节中讨论的任何⽅法进⾏纹理分割。

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;
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选择不当时,很容易会引起“⽅块效应”
转:。

相关文档
最新文档