图像处理(五):八邻域边缘跟踪与区域生长算法

来源:互联网 发布:斗鱼裴语燕 知乎 编辑:程序博客网 时间:2024/06/05 05:38

通常在进行边缘检测之后,需要通过边缘跟踪来将离散的边缘串接起来,常使用的方法为:边缘跟踪和区域生长两种方法。边缘跟踪又分为八邻域和四邻域两种,具体原理可以参考残影、的博客:点击打开链接

实现步骤:

1、灰度化并进行Canny边缘检测

2、按照预先设定的跟踪方向(顺时针)进行边缘跟踪

3、每次跟踪的终止条件为:8邻域都不存在轮廓

代码如下:

#include <opencv2/opencv.hpp>#include <vector>#include <time.h>using namespace cv;using namespace std;// 8 neighborsconst Point directions[8] = { { 0, 1 }, {1,1}, { 1, 0 }, { 1, -1 }, { 0, -1 },  { -1, -1 }, { -1, 0 },{ -1, 1 } };int main(){// 生成随机数RNG rng(time(0));Mat src = imread("1.jpg");Mat gray;cvtColor(src, gray, CV_BGR2GRAY);Mat Edge;// Canny边缘检测Canny(gray, Edge, 50, 100);vector<Point> edge_t;vector<vector<Point>> edges;// 边缘跟踪int i, j, counts = 0, curr_d = 0;for (i = 1; i < Edge.rows - 1; i++)for (j = 1; j < Edge.cols - 1; j++){// 起始点及当前点//Point s_pt = Point(i, j);Point b_pt = Point(i, j);Point c_pt = Point(i, j);// 如果当前点为前景点if (255 == Edge.at<uchar>(c_pt.x, c_pt.y)){edge_t.clear();bool tra_flag = false;// 存入edge_t.push_back(c_pt);Edge.at<uchar>(c_pt.x, c_pt.y) = 0;    // 用过的点直接给设置为0// 进行跟踪while (!tra_flag){// 循环八次for (counts = 0; counts < 8; counts++){// 防止索引出界if (curr_d >= 8){curr_d -= 8;}if (curr_d < 0){curr_d += 8;}// 当前点坐标// 跟踪的过程,应该是个连续的过程,需要不停的更新搜索的root点c_pt = Point(b_pt.x + directions[curr_d].x, b_pt.y + directions[curr_d].y);// 边界判断if ((c_pt.x > 0) && (c_pt.x < Edge.cols - 1) &&(c_pt.y > 0) && (c_pt.y < Edge.rows - 1)){// 如果存在边缘if (255 == Edge.at<uchar>(c_pt.x, c_pt.y)){curr_d -= 2;   // 更新当前方向edge_t.push_back(c_pt);Edge.at<uchar>(c_pt.x, c_pt.y) = 0;// 更新b_pt:跟踪的root点b_pt.x = c_pt.x;b_pt.y = c_pt.y;//cout << c_pt.x << " " << c_pt.y << endl;break;   // 跳出for循环}}curr_d++;}   // end for// 跟踪的终止条件:如果8邻域都不存在边缘if (8 == counts ){// 清零curr_d = 0;tra_flag = true;edges.push_back(edge_t);break;}}  // end if}  // end while}// 显示一下Mat trace_edge = Mat::zeros(Edge.rows, Edge.cols, CV_8UC1);Mat trace_edge_color;cvtColor(trace_edge, trace_edge_color, CV_GRAY2BGR);for (i = 0; i < edges.size(); i++){Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//cout << edges[i].size() << endl;// 过滤掉较小的边缘if (edges[i].size() > 5){for (j = 0; j < edges[i].size(); j++){trace_edge_color.at<Vec3b>(edges[i][j].x, edges[i][j].y)[0] = color[0];trace_edge_color.at<Vec3b>(edges[i][j].x, edges[i][j].y)[1] = color[1];trace_edge_color.at<Vec3b>(edges[i][j].x, edges[i][j].y)[2] = color[2];}}}imshow("edge", trace_edge_color);waitKey();return 0;}

效果如下:


至于区域生长算法可以直接参考博文点击打开链接,代码写的很棒!

该勤快的时候不能懒,好吧,还是自己实现了一遍,代码如下:

#include <opencv2/opencv.hpp>#include <vector>#include <time.h>using namespace cv;using namespace std;// 8邻域const Point neighbors[8] = { { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, -1 },                              { 0, -1 }, { -1, -1 }, { -1, 0 }, {-1, 1} };int main(){// 生成随机数  RNG rng(time(0));Mat src = imread("1.jpg");Mat gray;cvtColor(src, gray, CV_BGR2GRAY);Mat edges;Canny(gray, edges, 30, 100);vector<Point> seeds;vector<Point> contour;vector<vector<Point>> contours;int i, j, k;for (i = 0; i < edges.rows; i++)for (j = 0; j < edges.cols; j++){Point c_pt = Point(i, j);//如果当前点为轮廓点if (edges.at<uchar>(c_pt.x, c_pt.y) == 255){contour.clear();// 当前点清零edges.at<uchar>(c_pt.x, c_pt.y) = 0;// 存入种子点及轮廓seeds.push_back(c_pt);contour.push_back(c_pt);// 区域生长while (seeds.size() > 0){// 遍历8邻域for (k = 0; k < 8; k++){// 更新当前点坐标c_pt.x = seeds[0].x + neighbors[k].x;c_pt.y = seeds[0].y + neighbors[k].y;// 边界界定if ((c_pt.x >= 0)  && (c_pt.x <= edges.rows - 1) &&(c_pt.y >= 0) && (c_pt.y <= edges.cols - 1)){if (edges.at<uchar>(c_pt.x, c_pt.y) == 255){// 当前点清零edges.at<uchar>(c_pt.x, c_pt.y) = 0;// 存入种子点及轮廓seeds.push_back(c_pt);contour.push_back(c_pt);}// end if}} // end for// 删除第一个元素seeds.erase(seeds.begin());}// end whilecontours.push_back(contour);}// end if}// 显示一下  Mat trace_edge = Mat::zeros(edges.rows, edges.cols, CV_8UC1);Mat trace_edge_color;cvtColor(trace_edge, trace_edge_color, CV_GRAY2BGR);for (i = 0; i < contours.size(); i++){Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//cout << edges[i].size() << endl;  // 过滤掉较小的边缘  if (contours[i].size() > 5){for (j = 0; j < contours[i].size(); j++){trace_edge_color.at<Vec3b>(contours[i][j].x, contours[i][j].y)[0] = color[0];trace_edge_color.at<Vec3b>(contours[i][j].x, contours[i][j].y)[1] = color[1];trace_edge_color.at<Vec3b>(contours[i][j].x, contours[i][j].y)[2] = color[2];}}}imshow("edge", trace_edge_color);waitKey();return 0;}

效果如下: