多边形近似轮廓-多边形简化

1.原理

多边形近似将物体的轮廓转为一系列的直线段,在此使用基于弦算法得到近似轮廓的多边形。就复杂度和所用内存空间而言,该算法不是最有效的,但具有易于实现和提供精确的逼近阈值控制的优点。弦算法通过迭代细分过程减少多边形轮廓的点数。分段[AB]表示A是起点,B是离A距离最远的弦,在A和B之间的轮廓上,寻找离弦最远的点M。如果M与弦之间的欧氏距离小于近似阈值,则停止对端[AB]的迭代过程,否则继续对段[AM]和[MB]的迭代过程。
在这里插入图片描述
备注来两个公式:
在这里插入图片描述

2.算法实现

多边形近似算法原理源自Douglas-Peucker算法,使用点-边距离作为误差衡量标准。该算法从连接原始Polyline的第一个和最后一个顶点的边开始,计算所有中间顶点到边的距离,距离该边最远的顶点,如果其距离大于指定的公差,将被标记为Key并添加到简化结果中。这个过程将对当前简化中的每条边进行递归,直到原始Polyline的所有顶点与当前考察的边的距离都在允许误差范围内。
在这里插入图片描述

//点到直线距离
float getDist_P2L(Point pointP,Point pointA,Point pointB)
{
    //求直线方程
    int A = 0,B = 0, C = 0;
    A = pointA.y - pointB.y;
    B = pointB.x - pointB.x;
    C = pointA.x * pointB.y - pointA.y * pointB.x;
    float distance = 0;
    distance = abs(A * pointP.x + B*pointP.y + C)/aqrt(A*A+B*B);
    return distance;
}
  
void PolygonFitting(vector<vector<Point>&contours,vector<vector<Point>>&contours1)
{
    int T = 10;
    Point E;
    vector<Point>ResultContours;//近似结果轮廓
    for(int j = 0;j < contours[0].size() / (4 * T);j++)
    {
        float H = 0;
        for(int i=2*T+4*T*j;i<=3*T+4*T*j;i++)
        {
            float Distance = getDist_P2L(contours[0][i],contours[0][0+4*T*j],contours[0][4*T+4*T*j]);
            if(Distance>H)
            {
                H = Distance;
                E = contours[0][i];
            }
        }
        if(H>1)  //参考论文此处应为H>T
        {
            ResultContours.push_back(E);
        }
    }
    //vector<vector<Point>>constours1;
    contours1.push_back(ResultContours);
}

3.迭代端点拟合法

//top:在步长范围内,距离最大点的序号
//sum:参与计算的点的个数
//j:  步数*步长
void func(int top,int sum,int j,vector<vector<Point>>&contours)
{
    Point LeftE,RightE;     //左右两侧点与直线距离最大的点坐标
    float LeftH=0,RightH=0;   //左右两侧点与直线距离的最大值
    int MaxValueIndexLeft,MaxValueIndexRight; //左右两侧点与直线最大距离的点的索引
    for(int i=0;i<=top;i++)
    {
        //左侧距离计算
		float DistanceLeft = getDist_P2L(contours[0][i + j], contours[0][0 + j], contours[0][top + j]);
		if (DistanceLeft>LeftH)
		{
			LeftH = DistanceLeft;
			LeftE = contours[0][i + j];
			MaxValueIndexLeft = i;
		}
 
		//右侧距离计算
		if (sum != top && i <= (sum - top))
		{
			float DistanceRight = getDist_P2L(contours[0][i + j + top], contours[0][top + j], contours[0][sum + j]);
			if (DistanceRight>RightH)
			{
				RightH = DistanceRight;
				RightE = contours[0][i + j + top];
				MaxValueIndexRight = i;
			}
		}
    }
    if (LeftH>T)
	{
		ResultContours.push_back(LeftE);
		fun(MaxValueIndexLeft, top, j, contours);
	}
	if (RightH>T && sum != top)
	{
		ResultContours.push_back(RightE);
		fun(MaxValueIndexRight, top, j, contours);
	}
}

void IterativeEndpointFitting(vector<vector<Point>>&contours)
{
    for(int j=0;j<contours[0].size()-10;j+j+step)
    {
        func(step,step,j contours);
    }
    vector<vector<Point>>contours1;
    contours1.push_back(ResultContours);
}

4.opencv近似

void OpencvFitting(vector<vector<Point>>&contours)
{
    //逼近多边形曲线
    vector<vector<Point>>poly(contours.size());
    for(size_t t=0;t<contours.size();t++)
    {
        approxPolyDP(contours[t],poly[t],5,true);
    }
}

附上主函数main

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
 
using namespace cv;
using namespace std;
 
Mat src, binary, src_gray;
TickMeter tm;
 
 
/***** Opencv自带方法*****/
void OpencvFitting(vector<vector<Point>>& contours);
 
/***** 迭代端点拟合法*****/
float T = 0.9;    //距离阈值
int step = 20;    //步长
vector<Point>ResultContours;
void IterativeEndpointFitting(vector<vector<Point>>& contours);
void fun(int top, int sum, int j, vector<vector<Point>>& contours);
float getDist_P2L(Point pointP, Point pointA, Point pointB);
 
/***** 多边形拟合法*****/
void PolygonFitting(vector<vector<Point>>& contours);
 
 
int main(int argc,char** argv )
{
	//读取图片
	src = imread("3.jpg");
	if (src.empty()){
		printf("读取图像失败\n");
		return -1;
	}
	imshow("输入图片",src);
 
	//二值化
	cvtColor(src,src_gray,COLOR_BGR2GRAY);
	threshold(src_gray,binary,0,255,THRESH_BINARY|THRESH_OTSU);
 
	//寻找轮廓,并获取坐标点集
	vector<Vec4i>hireachy;
	vector<vector<Point>> contours;
	findContours(binary,contours,hireachy,RETR_TREE,CHAIN_APPROX_NONE,Point());
 
	//Opencv自带方法
	tm.start();
	OpencvFitting(contours);
	tm.stop();
	cout << "Opencv自带方法运行时间:" << tm.getTimeMilli() << endl;
 
	//迭代端点拟合法
	tm.start();
	IterativeEndpointFitting(contours);
	tm.stop();
	cout << "迭代端点拟合法运行时间:" << tm.getTimeMilli() << endl;
 
	//多边形拟合法
	tm.start();
	PolygonFitting(contours);
	tm.stop();
	cout << "多边形拟合法运行时间:" << tm.getTimeMilli() << endl;
 
	waitKey(0);
	return 0;
}

参考:https://blog.csdn.net/jgj123321/article/details/93718088

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值