OpenCV二值图求最大连通区域算法(广度优先算法 BFS)
标签:坐标 svi 入栈 main each 字体 gui std char
#include
#include
#include
#include
#include
#include
#include
#include using namespace std;using namespace cv;
#define WHITE 1
#define GRAY 2
#define BLACK 3
#define INFINITE 255
typedef CvPoint ElemType;
typedef struct
{
bool vSign;//像素点是否被访问过的标记,ture已访问,false表示未访问,给图片添加的一个属性
int pixelValue;//像素值
}isVisit;
typedef struct
{
CvPoint regionPoint;//该连通区域起点的坐标
int regionId;//第i个连通区域的标号
int pointNum;//第i个连通区域的像素点的总个数
}connectRegionNumSet;
int calConnectRegionNumsBfs(IplImage *srcGray, vector>& validPicture, vector ®ionSet);
int main() {
IplImage * src = cvLoadImage("ff.jpg");
IplImage * srcGray = NULL;
if (src->nChannels == 1)
goto next;
srcGray = cvCreateImage(cvSize(src->width, src->height), 8, 1);
cvCvtColor(src, srcGray, CV_RGB2GRAY);
next:
if (!srcGray)
cvThreshold(src, srcGray, 66, 255, CV_THRESH_BINARY);
else
cvThreshold(srcGray, srcGray, 66, 255, CV_THRESH_BINARY);
cvNamedWindow("srcBinaryGray");
cvShowImage("srcBinaryGray", srcGray);
vector >validPoint;
validPoint.resize(srcGray->height);
for (int i = 0; i)
validPoint[i].resize(srcGray->width);
vectorregionSet;//存放找到的各个连通区域 regionSet.size()为连通区域的个数。
cout "连通区域的数目:" //计算连通区域数目
char text[3];//设置连通区域的编号,最小标号为0,最大编号为99
CvFont font;
cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX, 0.6, 0.6, 0, 1, 8);//设置字体//参数从左到右:字体初始化,字体格式,字体宽度,字体高度,字体倾斜度,字体粗细,字体笔画类型
int max_pointNum = 0; //最大连通区域的像素点个数
int max_regionId = 0;
for (int i = 0; i)
{
cout "第" "个连通区域的起点坐标 =(" "," ")" ",像素总点数=" endl;
cout "ID:" endl;
if (i 10)
{//连通区域的个数为个位数
text[0] = ‘0‘;
text[1] = ‘0‘ + i;
}
else
{//连通区域的个数为十位数
text[0] = ‘0‘ + (i) / 10;
text[1] = ‘0‘ + (i) % 10;
}
text[2] = ‘\0‘;
cvPutText(src, text, regionSet[i].regionPoint, &font, cvScalar(0, 0, 255));
//找到最大连通区域,并标记----------------------------------------------
if (max_pointNum regionSet[i].pointNum)
{
max_regionId = i;
max_pointNum = regionSet[i].pointNum;
}
}
cout "第" "个连通区域最大" "像素总点数=" endl;
cvNamedWindow("src");
cvShowImage("src", src);
//cvShowImage("srcGray", srcGray);
cvWaitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&srcGray);
cvDestroyAllWindows();
}
int calConnectRegionNumsBfs(IplImage *srcGray, vector>& validPicture, vector ®ionSet)
{
int regionId = 0;//管理连通区域标号的变量
connectRegionNumSet regionSetTemp;//临时用到的regionSetTemp类型中间变量
uchar * ptr = (uchar*)(srcGray->imageData);
for (int y = 0; y height; y++)
{//给图片加上一个是否已访问的属性
ptr = (uchar*)(srcGray->imageData + y*srcGray->widthStep);
for (int x = 0; x width; x++)
{
validPicture[y][x].pixelValue = (int)ptr[x];
validPicture[y][x].vSign = false;//开始时默认都未访问
}
}
queue q;
CvPoint foundValidPoint;
for (int y = 0; y height; y++) {//给图片加上一个是否已访问的属性
for (int x = 0; x width; x++) {
if (validPicture[y][x].pixelValue && !validPicture[y][x].vSign) {//找到下一个连通区域的起点,即像素值非零且未被访问过的点
int eachRegionAcc = 1;//表示即将要寻找的连通区域的总像素点个数;//将validPicture[y][x]点默认为即将生成的连通区域的起点
regionSetTemp.regionPoint = cvPoint(x, y);//x表示列,y表示行
regionSetTemp.regionId = regionId++;
regionSetTemp.pointNum = 1;
regionSet.push_back(regionSetTemp);//将该点设置为已访问,并对其执行入栈操作
validPicture[y][x].vSign = true;
q.push(cvPoint(x, y));
while (!q.empty())
{
foundValidPoint = q.front();
q.pop();
int i = foundValidPoint.x;//t
int j = foundValidPoint.y;//k
int minY = (j - 1 0 ? 0 : j - 1);
int maxY = ((j + 1 > srcGray->height - 1 ? srcGray->height - 1 : j + 1));
int minX = (i - 1 0 ? 0 : i - 1);
int maxX = (i + 1 > srcGray->width - 1 ? srcGray->width - 1 : i + 1);
for (int k = minY; k )
{//在八连通范围内(两点之间距离小于根号2的点),表示其相邻点,入栈c
for (int t = minX; t )
{
if (validPicture[k][t].pixelValue && !validPicture[k][t].vSign)//validPicture[k][t]如果没有访问过
{
validPicture[k][t].vSign = true;//标志为已访问,防止死循环
q.push(cvPoint(t, k));
eachRegionAcc++;//相邻点的数目加1
}
}
}
}
if (eachRegionAcc > 1) //要求:连通区域的点数至少要有两个
regionSet[regionSet.size() - 1].pointNum = eachRegionAcc;
else
{//单个像素点不算,如果单个像素点也算,去掉该else语句即可
regionSet.pop_back();//上述默认的即将生成的连通区域不符合要求,出栈
regionId--;
}
}
}
}
return regionSet.size();
}
OpenCV二值图求最大连通区域算法(广度优先算法 BFS)
标签:坐标 svi 入栈 main each 字体 gui std char
原文地址:https://www.cnblogs.com/jxLuTech/p/11072845.html
评论