不记得代码是从哪里来的了,代码功能:使用BFS标记连通域个数
想了一下bfs和dfs实现时的区别在于使用的数据结构不一样,BFS使用Queue,先入先出(FIFO)便于广度优先遍历,DFS使用stack,后入先出(LIFO)便于深度优先遍历。
#include <opencv2/opencv.hpp> #include <math.h> using namespace std; using namespace cv; typedef unsigned long uint32; typedef unsigned int uint16; typedef unsigned char uint8; #define WHITE 1 #define GRAY 2 #define BLACK 3 #define NIL 0 #define INFINITE 255 typedef Point ElemType; typedef struct Queue { ElemType* data; int front; int rear; int Qsize; }Queue; bool initQueue(Queue* q, int size) { q->front = 0; q->rear = 0; q->Qsize = size; q->data = (ElemType*)malloc(q->Qsize * sizeof(ElemType)); if (NULL == q->data) return false; return true; } //销毁队列,释放内存 void destroyQueue(Queue* q) { q->front = 0; q->rear = 0; q->Qsize = 0; free((q->data)); q->data = NULL; } //清空队列 void clearQueue(Queue* q) { q->front = 0; q->rear = 0; } //判断队列是否为空 bool isQueueEmpty(Queue *q) { if (q->front == q->rear) { printf("the queue is empty! \n"); return true; } else { return false; } } //返回队首元素 bool getHead(Queue *q, ElemType *e) { if (isQueueEmpty(q)) { printf("can not get the head element! \n"); return false; } else { *e = q->data[q->front]; return true; } } //返回队列长度:在循环队列中 int Qlength(Queue *q) { return (q->rear - q->front + q->Qsize) % q->Qsize; } //入队 bool enQueue(Queue *q, ElemType e) { //如果队列已满,重新分配内存 if (q->rear == q->Qsize - 1) { q->data = (ElemType*)realloc(q->data, 2 * q->Qsize * sizeof(ElemType)); if (q->data == NULL) return false; else q->Qsize *= 2; } //先赋值,然后队尾循环加1 q->data[q->rear] = e; q->rear = (q->rear + 1) % q->Qsize; return true; } //出队 bool deQueue(Queue *q, ElemType *e) { if (isQueueEmpty(q)) return false; else { *e = q->data[q->front]; //队首标记循环加1 q->front = (q->front + 1 + q->Qsize) % q->Qsize; } return true; } void BFS(Mat& G, Mat& Label_Image, int x, int y, uint8 num) { Mat Color_src(G.size(), CV_8UC1);//白色表示未被搜索过,黑色表示搜索完毕,灰色表示正在搜索 Point *u = &Point(0, 0); int i, j, m, n; Queue Q; initQueue(&Q, 10); //给所有点标记为白色 Color_src.setTo(Scalar(WHITE)); Color_src.at<unsigned char>(y, x) = GRAY; enQueue(&Q, Point(x, y)); while (!isQueueEmpty(&Q)) { if (deQueue(&Q, u)) { Label_Image.at<unsigned char>(u->y, u->x) = num; if (u->x == 0 || u->x == G.cols || u->y == 0 || u->y == G.rows)//不处理边界点 continue; else { for (n = u->y - 1; n <= u->y + 1; n++)//八邻域 { for (m = u->x - 1; m <= u->x + 1; m++) { if (m == u->x && n == u->y) {} else if (G.at<unsigned char>(n, m) == 0) {} else { if (WHITE == Color_src.at<unsigned char>(n, m)) { Label_Image.at<unsigned char>(n, m) = num; Color_src.at<unsigned char>(n, m) = GRAY; enQueue(&Q, Point(m, n)); } } } } Color_src.at<unsigned char>(u->y, u->x) = BLACK; } } else break; } clearQueue(&Q); } void bwLabel(Mat img, Mat L_src, Mat dst) { int i, j; char s[5]; uint8 Label_value = 0; for (j = 0; j < img.rows; j++) { for (i = 0; i < img.cols; i++) { uint8 Label = L_src.at<unsigned char>(j, i); uint8 value = img.at<unsigned char>(j, i); if (Label == 0 && value != 0) { Label_value++; itoa(Label_value, s, 10); putText(dst, s, Point(i, j), FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255)); BFS(img, L_src, i, j, Label_value);//以i,j为种子点标记同一目标 } } } } int main() { Mat src, src_gray, L_src; int i, j, w, h; src = imread("1.bmp");//读取原图 L_src.create(src.size(), CV_8UC1); L_src.setTo(0); w = src.cols; h = src.rows; cvtColor(src, src_gray, CV_BGR2GRAY); long long t = getTickCount(); bwLabel(src_gray, L_src, src);//对图像进行标记 cout << "time: " << (getTickCount() - t) / getTickFrequency(); namedWindow("1", CV_WINDOW_AUTOSIZE); imshow("1", src);//标记后的图像 namedWindow("2", CV_WINDOW_AUTOSIZE); imshow("2", src_gray);//原图 cvWaitKey(0); return 0; }
参考输入图片如下:
程序执行输出: