#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(); }
原圖:
處理之后