OpenCV二值图求最大连通区域算法(广度优先算法 BFS)
Posted jxlutech
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV二值图求最大连通区域算法(广度优先算法 BFS)相关的知识,希望对你有一定的参考价值。
#include <iostream> #include <opencv2\opencv.hpp> #include <vector> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <windows.h> #include <math.h> #include <queue> 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<vector<isVisit>>& validPicture, vector<connectRegionNumSet> ®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<vector<isVisit> >validPoint; validPoint.resize(srcGray->height); for (int i = 0; i<validPoint.size(); i++) validPoint[i].resize(srcGray->width); vector<connectRegionNumSet>regionSet;//存放找到的各个连通区域 regionSet.size()为连通区域的个数。 cout << "连通区域的数目:" << calConnectRegionNumsBfs(srcGray, validPoint, regionSet) << endl << endl;//计算连通区域数目 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<regionSet.size(); i++) cout << "第" << i << "个连通区域的起点坐标 =(" << regionSet[i].regionPoint.x << "," << regionSet[i].regionPoint.y << ")" << ",像素总点数=" << regionSet[i].pointNum << endl; cout << "ID:"<<regionSet[i].regionId << 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 << "第" << max_regionId << "个连通区域最大" <<"像素总点数=" << regionSet[max_regionId].pointNum << endl; cvNamedWindow("src"); cvShowImage("src", src); //cvShowImage("srcGray", srcGray); cvWaitKey(0); cvReleaseImage(&src); cvReleaseImage(&srcGray); cvDestroyAllWindows(); int calConnectRegionNumsBfs(IplImage *srcGray, vector<vector<isVisit>>& validPicture, vector<connectRegionNumSet> ®ionSet) int regionId = 0;//管理连通区域标号的变量 connectRegionNumSet regionSetTemp;//临时用到的regionSetTemp类型中间变量 uchar * ptr = (uchar*)(srcGray->imageData); for (int y = 0; y < srcGray->height; y++) //给图片加上一个是否已访问的属性 ptr = (uchar*)(srcGray->imageData + y*srcGray->widthStep); for (int x = 0; x < srcGray->width; x++) validPicture[y][x].pixelValue = (int)ptr[x]; validPicture[y][x].vSign = false;//开始时默认都未访问 queue<CvPoint> q; CvPoint foundValidPoint; for (int y = 0; y < srcGray->height; y++) //给图片加上一个是否已访问的属性 for (int x = 0; x < srcGray->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 <= maxY; k++) //在八连通范围内(两点之间距离小于根号2的点),表示其相邻点,入栈c for (int t = minX; t <= maxX; 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)的主要内容,如果未能解决你的问题,请参考以下文章