opencv形态学应用之边界提取与跟踪

来源:互联网 发布:ggplot python 编辑:程序博客网 时间:2024/05/20 11:51

边界提取:根据之前的博客就是用原图减去腐蚀后的图像;

边界跟踪:按照某种扫描规则找到目标边界上的像素直到回到原点;

本程序中,我采用从左到右从上到下的顺序查找边界,如下图所示,分别从左下、下、右下右、右上、上、左上、左方向搜索边界点,当搜索到原点时,边界搜索结束。


当图像中有多个连通域时,显然这种方法就不适用,所以改进的方法是:每搜索完一个边界,将改连通域设置为背景颜色(如:0),然后继续搜索

#include<opencv2\opencv.hpp>#include<iostream>using namespace std;using namespace cv;void erode(const Mat _src, Mat& dst, int se[3][3]);void dilate(const Mat _src, Mat& dst, int se[3][3]);/**************************************************功能:边界跟踪参数:src-二值图像***************************************************/void traceBoundary(Mat src, Mat& dst){//起始边界点和当前边界点Point ptStart;Point ptCur;//搜索方向数组{左下,下,右下,右,右上,上,左上,左}int Direction[8][2] = { { -1, 1 }, { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 } };int nCurDirect = 0;//当前探查的方向//搜索开始,区别ptCur==ptStart的两种情况(一种开始,一种结束)bool bAtStartPt;//算法不处理边界上的点,将图像的四周设置为白//for (int i = 0; i < src.rows; i++)//{//dst.at<uchar>(i, 0) = 255;//dst.at<uchar>(i, src.rows - 1) = 255;//}//for (int j = 0; j < src.cols; j++)//{//dst.at<uchar>(0, j) = 255;//dst.at<uchar>(src.rows - 1, j) = 255;//}int xPos, yPos;//逐行扫描for (int i = 0; i < src.rows; i++){for (int j = 0; j < src.cols; j++){if (src.at<uchar>(i, j) > 0){ptStart.x = j;ptStart.y = i;ptCur = ptStart;bAtStartPt = true;while ((ptCur.x != ptStart.x) || (ptCur.y != ptStart.y) || bAtStartPt){bAtStartPt = false;//下一个探查位置xPos = ptCur.x + Direction[nCurDirect][0];yPos = ptCur.y + Direction[nCurDirect][1];int nSearchTimes = 1;while (src.at<uchar>(yPos, xPos) ==0){nCurDirect++;//逆时针旋转45度if (nCurDirect >= 8)nCurDirect -= 8;xPos = ptCur.x + Direction[nCurDirect][0];yPos = ptCur.y + Direction[nCurDirect][1];//8领域中都没有边界点,说明是孤立点if (++nSearchTimes >= 8){xPos = ptCur.x;yPos = ptCur.y;break;}}//找到下一个边界点ptCur.x = xPos;ptCur.y = yPos;//在新像上标记边界dst.at<uchar>(ptCur.y, ptCur.x) = 255;/***********此处可以定义vector存储提取的边界点************///将当前探查方向顺时针回转90度作为下一次的探查初始方向nCurDirect -= 2;if (nCurDirect < 0){nCurDirect += 8;}}return;}//当存在多个边界时,在此处添加相应代码,并删除return(每跟踪完一个边界,删除相应的区域)}}}int main(){//读取二值图像(此步可以忽略)Mat src = imread("test1.jpg", 0);Mat src_binary;threshold(src, src_binary, 250, 255, THRESH_BINARY);imshow("原始图像", src_binary);//创建模板int se[3][3] = { { -1, 1, -1 }, { 1, 1, 1 }, { 1, 1, 1 } };//边界提取(原图-腐蚀后的图像)Mat dstImg;erode(src_binary, dstImg, se);dstImg = src_binary - dstImg;imshow("边界提取后的图像", dstImg);//边界跟踪Mat BoundaryImg = Mat::zeros(src_binary.size(), src_binary.type());traceBoundary(dstImg, BoundaryImg);imshow("边界图像", BoundaryImg);waitKey(0);return 0;}

原始图像:


边界提取的结果:


边界跟踪后的结果: