提取图片中的连通部分

elysium1984 2009-09-02 05:11:25
有一张二值图片,图片内容为一些不规则的连通区域(像素点连通),有什么好的办法,将这些连通区域分别提取出来?
那位大侠帮忙给个好的建议或方法!
图片如下面这个,要实现单独提取每一个连通的小区域

...全文
186 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
Huer 2011-10-08
  • 打赏
  • 举报
回复
连通区域标记用轮廓提取的方法不行吗。轮廓提取方法的思想很简单:查看输入图像的每一个黑色像素点,若该点周围8邻域像素点的灰度值之和为0,则该点是内部点,输出图像相应位置置白色。
icansaymyabc 2009-09-03
  • 打赏
  • 举报
回复
有一个求边界的算法,叫爬虫算法,规则很简单:

1 从起点开始,向直指区域的任意方向行进。像素颜色不变,方向就不变。
2 发现像素颜色由0变1,表示找到了边界点,记录下此点。并将方向改为右转,以后每前进1步方向右转90度。
3 发现像素颜色由1变0,表示又找到了边界点,记录下此点。并将方向改为左转,以后每前进1步方向左转90度。

4 循环 2,3 直到回到第一个边界点。这个连通区域的边界点就被完全记录了。

像你的那个例图,上面有很多个区域。你也可以使用这个方法,但是每次要把已经记录下来的区域抹成空白,
才能接着找下一块区域。



  • 打赏
  • 举报
回复
直接搜索。
根据4连通,或者8连通来做就可以啦。

数据结构队列比较好,也可以用递归方法。

核心的思想

while(队列!=空)
{
吐出一个像素
if(pixel==黑颜色)
{
如果旁边的点是黑颜色&&没有Visit过{
队列.push()
}
}
}
everysports 2009-09-03
  • 打赏
  • 举报
回复
自己写算法还是用现成的?自己写的话也就是照着现成的写而已,追求速度再改成汇编的。呵呵
fire_woods 2009-09-03
  • 打赏
  • 举报
回复
连通域标记啊,有现成的算法的.
elysium1984 2009-09-03
  • 打赏
  • 举报
回复
有更好的方法吗?
donkey301 2009-09-03
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 icansaymyabc 的回复:]
有一个求边界的算法,叫爬虫算法,规则很简单:

1 从起点开始,向直指区域的任意方向行进。像素颜色不变,方向就不变。
2 发现像素颜色由0变1,表示找到了边界点,记录下此点。并将方向改为右转,以后每前进1步方向右转90度。
3 发现像素颜色由1变0,表示又找到了边界点,记录下此点。并将方向改为左转,以后每前进1步方向左转90度。

4 循环 2,3 直到回到第一个边界点。这个连通区域的边界点就被完全记录了。

像你的那个例图,上面有很多个区域。你也可以使用这个方法,但是每次要把已经记录下来的区域抹成空白,
才能接着找下一块区域。



[/Quote]
这个方法很有意思,也很巧妙。
丈八涯 2009-09-03
  • 打赏
  • 举报
回复
简单的连通算法
// Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"#include <list>
#include <vector>
#include <stack>
using namespace std;
//using namespace stdext;

typedef struct Point
{
public:
int x;
int y;
int value;
}Point;

void GetParts( list<Point> &partResult, vector<vector<int> > &a ,stack<Point> &StackP)
{
partResult.push_back(StackP.top());
a[StackP.top().x][StackP.top().y] = 0;
while( !StackP.empty() )
{
Point pt;
int row = StackP.top().x;
int col = StackP.top().y;
StackP.pop();
if( row > 0 )//上
{
if( a[row-1][col] > 0 )
{
pt.x = row-1;
pt.y = col;
StackP.push(pt);
partResult.push_back(pt);
a[row-1][col] = 0;
}
}
if( col > 0 )//左
{
if( a[row][col-1] > 0 )
{
pt.x = row;
pt.y = col-1;
StackP.push(pt);
partResult.push_back(pt);
a[row][col-1] = 0;
}
}
if( col < int(a[0].size() - 1) )//右
{
if( a[row][col+1] > 0 )
{
pt.x = row;
pt.y = col+1;
StackP.push(pt);
partResult.push_back(pt);
a[row][col+1] = 0;
}
}
if( row < int(a.size() - 1) )//下
{
if( a[row+1][col] > 0 )
{
pt.x = row + 1;
pt.y = col;
StackP.push(pt);
partResult.push_back(pt);
a[row+1][col] = 0;
}
}
}
};

int _tmain(int argc, _TCHAR* argv[])
{
Point nowP;
int a[6][6] =
{
{ 0,1,0,1,0,0 },
{ 1,1,0,1,1,0 },
{ 0,1,1,1,0,1 },
{ 0,0,0,0,0,0 },
{ 1,1,0,1,1,1 },
{ 1,1,0,1,0,0 }
};
vector<vector<int> > arr = vector<vector<int> >(6,vector<int>(6));
for( int i = 0 ; i < 6; i++ )
{
for( int j = 0; j < 6; j++ )
{
arr[i][j] = a[i][j];
}
}
list<list<Point> > AllPart;
list<Point> nowPart;
stack<Point> PointStack;

for( int i = 0; i < int(arr.size()); i ++ )
{
for( int j = 0 ; j < int(arr[0].size()); j++ )
{
if( arr[i][j] > 0 )
{
nowPart.clear();
nowP.x = i;
nowP.y = j;
PointStack.push( nowP );
GetParts( nowPart, arr, PointStack);
AllPart.push_back(nowPart);
}
}
}
return 0;
}

LPR_Pro 2009-09-03
  • 打赏
  • 举报
回复
八邻域搜索算法
http://blog.csdn.net/LPR_Pro/archive/2009/08/20/4465193.aspx
/***********************************************************************************

**********

********** 如果此代码对您有帮助的话,请多来踩我的Blog

**********

************************************************************************************/

int i, j, nHeight, nWidth; // 图像的高度和宽度
bool pbFlag[nHeight][nWidth]; // 声明一个大小为nHeight*nWidth的矩形
int xStart, xEnd, yStart, yEnd;
/////////////////////////////////////////////////////////////////////////////////
typedef struct __XYPOSITION // 定义一个图像中坐标的数据类型
{
int xPos; // x方向的坐标
int yPos; // y方向的坐标
}XYPOSITION, *PXYPOSITION;

XYPOSITION *pPosBottom, *pPosTop;
XYPOSITION pXYPos[nWidth*nHeight]; // 声明一个堆栈

// 初始化,根据二维数据的地图初始化
for(i=0; i <nHeight; i++ ) // 列扫描
{
for(j=0; j <nWidth; j++ ) // 行扫描
{
// 如果地图数据为障碍物1,则pbFlag[i][j]=false
// 否则pbFlag[i][j] = true
}
}

// 第一次搜索
for(i=0; i <nHeight; i++ ) // 列扫描
{
for(j=0; j <nWidth; j++ ) // 行扫描
{
if( pbFlag[i][j] )
{
// 初始化图像区域的位置
xStart = j;
xEnd = j;
yStart = i;
yEnd = i;

pPosBottom = pXYPos;
pPosTop = pXYPos+1;
// 记录白色点的坐标
(*pPosBottom).xPos = j;
(*pPosBottom).yPos = i;
(*pPosBottom).pbCurrentPos = pbFlag+i*nWidth+j;
pbFlag[i][j] = false;

while( pPosBottom != pPosTop )
{
// 提取出搜索列表中的象素点
X = (*pPosBottom).xPos;
Y = (*pPosBottom).yPos;

/*****************************
八邻域处理过程
*****************************/
/************************************
处理第一行的情况
**********************************/
// 搜索第一行的情况
if( Y>0 )
{
Y1 = (Y-1);
// 处理左上角的点
if( X>0 )
{
if( pbFlag[Y1][X-1] )
{
X1 = (X-1);
(*pPosTop).xPos = X1;
(*pPosTop).yPos = Y1;
// 记录区域的大小
xStart = min(xStart, X1);
yStart = min(yStart, Y1);
// 标识为已经搜索过
pbFlag[Y1][X1] = false;
}
}
// 处理正上边的点
if( pbFlag[Y1][X])
{
(*pPosTop).xPos = X;
(*pPosTop).yPos = Y1;
// 记录区域的大小
yStart = min(yStart, Y1);
// 标识为已经搜索过
pbFlag[Y1][X] = false;
}
// 处理右上角的点
X1 = (X+1);
if( X1 <nWidth )
{
if( pbFlag[Y1][X1] )
{
(*pPosTop).xPos = X1;
(*pPosTop).yPos = Y1;
// 记录区域的大小
xEnd = max(xEnd, X1);
yStart = min(yStart, Y1);
// 标识为已经搜索过
pbFlag[Y1][X1] = false;
}
}
}
/******************************************************************
处理第二行的情况
*****************************************************************/
// 搜索第二行的情况
// 处理正左边的点
if( X>0 )
{
if( pbFlag[Y][X-1] )
{
X1 = (X-1);
(*pPosTop).xPos = X1;
(*pPosTop).yPos = Y;
// 记录区域的大小
xStart = min(xStart, X1);
// 标识为已经搜索过
pbFlag[Y][X1] = false;
}
}
// 处理正右边的点
X1 = (X+1);
if( X1 <nWidth )
{
if( pbFlag[Y][X1])
{
(*pPosTop).xPos = X1;
(*pPosTop).yPos = Y;
// 记录区域的大小
xEnd = max(xEnd, X1);
// 标识为已经搜索过
pbFlag[Y][X1] = false;
}
}
/*******************************************************************
处理第三行的情况
******************************************************************/
// 搜索第三行的情况
if( (Y+1) <nHeight )
{
Y1 = (Y+1);
// 处理左下角的点
if( X>0 )
{
if( pbFlag[Y1][X-1])
{
X1 = (X-1);
(*pPosTop).xPos = X1;
(*pPosTop).yPos = Y1;
// 记录区域的大小
xStart = min(xStart, X1);
yEnd = max(yEnd, Y1);
// 标识为已经搜索过
pbFlag[Y1][X1] = false;
}
}
// 处理正下边的点
if( pbFlag[Y1][X])
{
(*pPosTop).xPos = X;
(*pPosTop).yPos = Y1;
// 记录区域的大小
yEnd = max(yEnd, Y1);
// 标识为已经搜索过
pbFlag[Y1][X] = false;
}
// 处理右下角的点
X1 = (X+1);
if( X1 <nWidth )
{
if( pbFlag[Y1][X+1])
{
(*pPosTop).xPos = X1;
(*pPosTop).yPos = Y1;
// 记录区域的大小
xEnd = max(xEnd, X1);
yEnd = max(yEnd, Y1);
// 标识为已经搜索过
pbFlag[Y1][X1] = false;
}
}
}
} // while

/*******************************************************************
输出搜索到的子区域块
******************************************************************/
if( xStart != 0 // 去除左边
&& xEnd != (nWidth-1) // 去除右边
&& yStart != 0 // 去除上边
&& yEnd != (nHeight-1) // 去除下边
)
{
pPosBottom = pXYPos;

while( pPosBottom != pPosTop )
{
// 输出图形中被障碍物包围的所有点的坐标X,Y
X = (*pPosBottom).xPos;
Y = (*pPosBottom ++).yPos;
}
}
}
} // for j
} // for i
PeacefulBY 2009-09-02
  • 打赏
  • 举报
回复
k-mean或k近邻,定义一个k值,递归地把k范围内的聚合到一起
或者去查阅下其他的聚类方法

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧