- #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();
- }
来源: http://www.bubuko.com/infodetail-3101370.html