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

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

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

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


当图像中有多个连通域时,显然这种方法就不适用,所以改进的方法是:每搜索完一个边界,将改连通域设置为背景颜色(如: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;
}


原始图像:


边界提取的结果:


边界跟踪后的结果:


  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值