不记得代码是从哪里来的了,代码功能:使用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;
}
参考输入图片如下:
程序执行输出: