19,469
社区成员
发帖
与我相关
我的任务
分享
CovBorderToObj(vector<POINT>* vecObjInner, vector<POINT>& vecObjBorder)
{
}
//==================================================================================
//功能说明:设置两个POINT排序的判定准则,按照y从小到大,y值相等(x值从小到大排序)
//==================================================================================
bool SetSortRule(const POINT pt1, const POINT pt2)
{
if (pt1.y < pt2.y)
{
return true;
}
else if (pt1.y == pt2.y)
{
return (pt1.x < pt2.x);
}
else
{
return false;
}
}
//==================================================================================
//功能说明:设置两个POINT的相等准则
//==================================================================================
bool PointIsEqual(POINT ptFirst, POINT ptSecond)
{
return (ptFirst.x == ptSecond.x && ptFirst.y == ptSecond.y);
}
//==================================================================================
//功能说明:对象边界点坐标转换为对象点坐标,对象边界点坐标为内边界
// 支持单连通,边界点>0,边界点被包括在了区域中
//入 口: vecObjBorder 对象边界点坐标
//
//出 口: vecObjInner 对象点(内部)坐标
//==================================================================================
bool CSegmentDataSet::CovBorderToObj(vector<POINT>* vecObjInner, vector<POINT>& vecObjBorder)
{
if (vecObjBorder.size() == 1)
{
vecObjInner->push_back(vecObjBorder.front());
return true;
}
// 区域内的点
POINT pt;
// 边界链码表
vector<int> vecCode;
// 区域线段表
vector<POINT> vecLineTable;
vector<POINT>::iterator iter;
// 排序
sort(vecObjBorder.begin(),vecObjBorder.end(),SetSortRule);
// 闭合的单连通区域边界点生成链码表
if (!BorderToCode(&vecCode,vecObjBorder))
{
return false;
}
// 链码表(4连通或者8连通)转换成线段表
if (!CodeToLineTable(&vecLineTable,vecCode))
{
return false;
}
// 根据线段表统计区域内点的坐标
for (iter = vecLineTable.begin();iter != vecLineTable.end();iter += 2)
{
int xStart =(*iter).x;
int xEnd = (*(iter+1)).x;
for (int x=xStart;x<=xEnd;x++)
{
pt.x = x;
pt.y = (*iter).y;
vecObjInner->push_back(pt);
}
}
return true;
}
/*****************************************************************************************************
* 3 2 1
* 4__|__0 8连通示意图
* |
* 5 6 7
*
* 跟踪采用“向右看”的准则,即在跟踪过程中对象区域内部总是在边界前进方向的右侧
*
* 顺时针方向跟踪边界
*
************************************************************************************************ */
//==================================================================================
//功能说明:闭合的单连通区域边界点生成链码表
//入 口: vecObjBorder 对象边界点坐标
//
//出 口: vecCode 对象边界点链码表
//==================================================================================
bool CSegmentDataSet::BorderToCode(vector<int>* vecCode, vector<POINT>& vecBorder)
{
if (vecBorder.empty())
{
return false;
}
vecCode->clear();
//逆时针定义中心像素点的8邻域坐标,注意:图像原点位于左上角
//第一列为x方向的偏移,第二列为y方向的偏移
int direction[8][2] = { {1, 0},{1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1},{1, 1}};
//边界起始点,待处理的当前点,当前点的邻域点
POINT startP;
POINT currentP;
POINT neighborP;
startP = vecBorder[0];
//为链码表填充头两个单元,存储边界起始点的X,Y坐标
vecCode->push_back(startP.x);
vecCode->push_back(startP.y);
//边界跟踪
//从初始边界点开始跟踪
currentP = startP;
//邻域点是否是边界点的标识变量
bool isContourP;
//定义中心象元点的左方为开始方向,共有8个方向(取值0--7)
int startDirection = 4;
//表示还没有找到最初边界点的标识变量
bool findStartPointAgain = false;
while (!findStartPointAgain)
{
isContourP = false;
while (!isContourP)
{
neighborP.x = currentP.x + direction[startDirection][0];
neighborP.y = currentP.y + direction[startDirection][1];
vector<POINT>::iterator ite;
ite = find_if(vecBorder.begin(),vecBorder.end(),bind1st(ptr_fun(PointIsEqual), neighborP));
//判断该邻域点是否是边界点
if (ite != vecBorder.end())
{
//从链码标的第三个单元开始填充链码序列
vecCode->push_back(startDirection);
isContourP = true;
currentP.x = neighborP.x;
currentP.y = neighborP.y;
//判断该邻域点是否已经回到边界起始点
if (currentP.x==startP.x&¤tP.y==startP.y)
{
findStartPointAgain = true;
}
if (startDirection % 2 == 0)
{
startDirection++;
}
else
{
startDirection = (startDirection + 2) % 8;
}
}
else
{
startDirection--;
if (startDirection < 0)
{
startDirection += 8;
}
}
}
}
//为链码表的第三个单元插入一个元素以记录边界的总点数
vecCode->insert(vecCode->begin()+2,vecCode->size()-2);
return true;
}
//==================================================================================
//功能说明:链码表(4连通或者8连通)转换成线段表
//入 口: vecCode 对象边界点链码表
//
//出 口: vecLineTable 对象的线段表
//==================================================================================
bool CSegmentDataSet::CodeToLineTable(vector<POINT>* vecLineTable, vector<int>& vecCode)
{
if (vecCode.empty())
{
return false;
}
// 清空线段表
vecLineTable->clear();
// 在已经存储好的链码表末尾再插入一个点,用来存储第一个边界点的链码值,构成循环,作为离开第一个边界点的的链码
vecCode.push_back(-1000);
// 逆时针定义中心像素点的8邻域坐标,注意:图像原点位于左上角
// 第一列为x方向的偏移,第二列为y方向的偏移
int direction[8][2] = { {1, 0},{1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1},{1, 1}};
// 链码表转换线段表的参数表
int tab[8][8] = {
//0 1 2 3 4 5 6 7
{0,0,0,0,2,2,2,2}, // 0 // 0为中间点,1为左端点
{1,1,1,1,0,3,3,3}, // 1 // 2为右端点,3为奇异点
{1,1,1,1,0,0,3,3}, // 2 // 行是进入的链码
{1,1,1,1,0,0,0,3}, // 3 // 列是离开时的链码
{1,1,1,1,0,0,0,0}, // 4
{0,3,3,3,2,2,2,2}, // 5
{0,0,3,3,2,2,2,2}, // 6
{0,0,0,3,2,2,2,2}, // 7
};
int codeIn, codeOut;
int pointType;
int endPointCount = 0; //线段表端点数初始化
int codeCount = vecCode[2];
vecCode[codeCount+3] = vecCode[3];
//取得边界起始点坐标
int startX = vecCode[0];
int startY = vecCode[1];
//先把边界起始点当作当前点
int currentX = startX;
int currentY = startY;
for (int i = 3; i < codeCount + 3;i++) //沿整个链码序列处理一次
{
codeIn = vecCode[i]; //取进入当前点的链码,第一次循环时当前点为链码表中的第二个边界点
codeOut = vecCode[i + 1]; //取离开当前点的链码
pointType = tab[codeIn][codeOut];
//计算得到当前点坐标
currentX += direction[codeIn][0];
currentY += direction[codeIn][1];
POINT pt;
pt.x = currentX;
pt.y = currentY;
if (pointType!=0) //中间点不填入临时表 不管是左端点还是右端点填入一次
{
vecLineTable->push_back(pt);
}
if (pointType==3) //奇异点再添一次,保证总端点数为偶数
{
vecLineTable->push_back(pt);
}
}
// 对初始线段表按照y从小到大排序,y值相等的,按照x值从小到大排序
sort(vecLineTable->begin(),vecLineTable->end(),SetSortRule);
vecCode.erase(vecCode.end()-1); //从链码表中删除开始添加的点
return true;
}