1 算法介绍
区域成长算法:将依照当时定义的成长准则讲一个像素或子区域逐渐聚合成一个残缺独立的区域的过程。对于图像上某个区域 R,p 为区域 R 上指定的一个像素点,称作种子点,依照规定的成长准则逐渐将与种子点 z 肯定邻域内合乎相似性判据的像素合并成一个种子群以备下一阶段的成长,这样一直的进行循环成长直到满足成长进行条件为止,从而实现了对感兴趣区域由一个种子点成长为一个独立连通区域的过程。
实现步骤
1、在图像区域中选取一个像素点作为一个种子点(x,y)。
2、依据成长规定,判断种子点四周八邻域的哪几个像素点能够作为下次成长的点,判断完后将该点存入生长点 Vector,并将以后已用的种子点标记为已应用。
3、依照规定判断下一个生长点。
4、判断生长点 vector 容器中是否还有生长点,容器为空时完结。
Halcon 中区域成长算子
regiongrowing(Image:Regions : Row, Column, Tolerance, MinSize :)
Row:被测试的区域的垂直距离
Column:被测试的区域的程度间隔
Tolerance:能忍耐的最大的灰度差距
MinSize:最小的输入区域
regiongrowing (Image111, Regions, 2, 2, 4, 100)
2 终点坐标种子点实现区域成长
在区域成长的算法中,咱们须要输出一个已知的坐标点(x,y),以这个点作为终点,这里咱们不应用 Halcon 自带的区域成长算子,而是通过算法的步骤去实现这一性能。
首先获取点击点的像素点灰度值,以这一点为起始点,向八畛域依照灰度差值去计算生长点。
HTuple Row,Col,Button;
GetMbutton(m_hHalconID,&Row,&Col,&Button);
if(Button == 1)
{
HObject ResultRegion;
// HTuple posGray,GrayRows,GrayCols;
GetGrayval(CurTestImg,Row, Col,&SelectGray);
qDebug()<<"Gray"<<SelectGray.I();
int curGray = SelectGray.I();
ui->spb_gray->setValue(curGray);
int index = ui->spb_growIndex->value();
int posY = Row.I();
int posX = Col.I();
QPoint pos(posX,posY);
RegionGrowing(CurTestImg,ResultRegion,pos,index);
FillUp(ResultRegion,&ResultRegion);
UpdateImgWindow();
ui->PicShow->Region_ShowBuf.clear();
region_Info h_RegionInfo;
h_RegionInfo.region = ResultRegion;
h_RegionInfo.color = "#ff0000c0";
h_RegionInfo.size = 1;
ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo);
ui->PicShow->updateShowInfoOnWindow();}
// 区域成长算法
void RegionGrowDlg::RegionGrowing(HObject img, HObject ®ion, QPoint pt,int th)
{
QPoint ptGrowing; // 待生长点地位
HTuple nGrowLable = 0; // 标记是否成长过
int nSrcValue = 0; // 成长终点灰度值
int nCurValue = 0; // 以后生长点灰度值
// matDst = cv::Mat::zeros(src.size(), CV_8UC1); // 创立一个空白区域,填充为彩色
// 成长方向程序数据
int DIR[8][2] = {{ -1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0} };
std::vector<QPoint> vcGrowPt; // 生长点栈
vcGrowPt.push_back(pt); // 将生长点压入栈中
// 首先设置区域为空
GenEmptyRegion(®ion);
// matDst.at<uchar>(pt.y, pt.x) = 255; // 标记生长点
HTuple posGray;
GetGrayval(img,pt.y(), pt.x(),&posGray);
nSrcValue = posGray.I(); // 记录生长点的灰度值
qDebug()<<"抉择点灰度"<<nSrcValue;
while (!vcGrowPt.empty()) // 成长栈不为空则成长
{pt = vcGrowPt.back(); // 取出一个生长点
vcGrowPt.pop_back();
// 别离对八个方向上的点进行成长
for (int i = 0; i < 8; ++i)
{int ppx = (pt.x() + DIR[i][0]);
int ppy = (pt.y() + DIR[i][1]);
ptGrowing = QPoint(ppx,ppy);
// 查看是否是边缘点
if (ptGrowing.x() < 0 || ptGrowing.y() < 0 || ptGrowing.x() >(hv_Width - 1) || ptGrowing.y() > (hv_Height - 1))
continue;
// 判断该点是否在 region 内
// int nGrowLable;
TestRegionPoint(region,ptGrowing.y(), ptGrowing.x(),&nGrowLable);
// HTuple curGray;
// GetGrayval(img,ptGrowing.y, ptGrowing.x,&curGray);
// nGrowLable = matDst.at<uchar>(ptGrowing.y, ptGrowing.x); // 以后待生长点的灰度值
if (nGrowLable == 0) // 如果标记点还没有被成长
{
HTuple curGray;
GetGrayval(img,ptGrowing.y(), ptGrowing.x(),&curGray);
nCurValue = curGray.I();
// nCurValue = src.at<uchar>(ptGrowing.y, ptGrowing.x);
// if (abs(nSrcValue - nCurValue) < th)
// 在阈值范畴内则成长, 这里抉择灰度在以后灰度值左右 th 个灰度内
if (nCurValue >nSrcValue || abs(nSrcValue - nCurValue) < th)
{
HObject PointRegion;
GenRegionPoints(&PointRegion,ptGrowing.y(), ptGrowing.x());
Union2(PointRegion,region,®ion);
// matDst.at<uchar>(ptGrowing.y, ptGrowing.x) = 255; // 标记为红色
vcGrowPt.push_back(ptGrowing); // 将下一个生长点压入栈中
}
}
}
}
}
从函数中能够看出,区域成长算法的输出是图像、坐标点、灰度断定值,输入为成长进去的 Region 区域。
3 以灰度值作为种子点进行区域成长
相当于将图像中某个灰度值的像素点挑出来作为坐标种子点,而后再进行区域成长算法。这种的成果跟 Halcon 中部分阈值的 var_threshold 的成果相似。
void RegionGrowDlg::on_spb_growIndex_valueChanged(int arg1)
{
HObject Region,ResultRegion;
HTuple GrayRows,GrayCols;
int curGray = ui->spb_gray->value();
Threshold(CurTestImg,&Region,curGray,curGray);
GetRegionPoints(Region,&GrayRows,&GrayCols);
GenEmptyRegion(&ResultRegion);
for(int i=0;i<GrayRows.Length();i++)
{
HTuple isInside;
int posY = GrayRows[i].I();
int posX = GrayCols[i].I();
TestRegionPoint(ResultRegion,posY,posX,&isInside);
if(isInside == 1){continue;}
else
{
HObject GrowRegion;
QPoint pos(posX,posY);
RegionGrowing(CurTestImg,GrowRegion,pos,arg1);
Union2(GrowRegion,ResultRegion,&ResultRegion);
}
}
FillUp(ResultRegion,&ResultRegion);
UpdateImgWindow();
ui->PicShow->Region_ShowBuf.clear();
region_Info h_RegionInfo;
h_RegionInfo.region = ResultRegion;
h_RegionInfo.color = "#ff0000c0";
h_RegionInfo.size = 1;
ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo);
ui->PicShow->updateShowInfoOnWindow();}
void RegionGrowDlg::on_spb_gray_valueChanged(int arg1)
{
HObject Region,ResultRegion;
HTuple GrayRows,GrayCols;
Threshold(CurTestImg,&Region,arg1,arg1);
GetRegionPoints(Region,&GrayRows,&GrayCols);
GenEmptyRegion(&ResultRegion);
int index = ui->spb_growIndex->value();
for(int i=0;i<GrayRows.Length();i++)
{
HTuple isInside;
int posY = GrayRows[i].I();
int posX = GrayCols[i].I();
TestRegionPoint(ResultRegion,posY,posX,&isInside);
if(isInside == 1){continue;}
else
{
HObject GrowRegion;
QPoint pos(posX,posY);
RegionGrowing(CurTestImg,GrowRegion,pos,index);
Union2(GrowRegion,ResultRegion,&ResultRegion);
}
}
FillUp(ResultRegion,&ResultRegion);
UpdateImgWindow();
ui->PicShow->Region_ShowBuf.clear();
region_Info h_RegionInfo;
h_RegionInfo.region = ResultRegion;
h_RegionInfo.color = "#ff0000c0";
h_RegionInfo.size = 1;
ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo);
ui->PicShow->updateShowInfoOnWindow();}
4 总结
区域成长算法的核心思想是将由类似性质的像素点合并到一个 region 区域,对于宰割简单的图像具备比拟好的性能和成果,但其算法的迭代性,导致其在运算时的工夫和内存的开销比拟大,当噪声和灰度不均一的时候可能会呈现适度宰割,而且不太适宜较大图像的运算场景。
我的项目代码下载