多边形或轮廓等距离外扩或收缩

在障碍物(如建筑物)轮廓提取之后,为了防止机器人运行过程中与障碍物碰撞,一般将障碍物轮廓外扩指定的距离(即安全缓冲距离)。用cv::findContours()可以轮廓提取,然后对轮廓进行cv::approxPolyDP()多边形近似,用尽可能少的顶点构成的多边形来近似描述轮廓。

参考:折线平行线的计算方法
https://blog.csdn.net/happy__888/article/details/315762

给定一个简单多边形,多边形按照顺时针或者逆时针的数许排列
内部等距离缩小或者外部放大的多边形,实际上是由距离一系列平行已知多边形的边,并且距离为L的线段所构成的。

效果指示图

外围的是原多边形,内侧是新的多边形

算法构造

多边形的相邻两条边,L1和L2,交于Pi点

做平行于L1和L2,平行线间距是L的,并且位于多边形内部的两条边,交于Qi

我们要计算出Qi的坐标

如图,
算法原理图

PiQi向量,显然是等于平行四边形的两个相邻边的向量v1和v2的和的

而v1和v2向量的方向,就是组成多边形的边的方向,可以用顶点差来表示

v1和v2向量的长度是相同的,等于平行线间距L与两个线段夹角的sin值的除法。

即: Qi = Pi + (v1 + v2)

    Qi = Pi + L/sinθ * ( Normalize(v2) + Normalize(v1))
    sin θ = |v1 × v2 | /(|v1|*|v2|) = |v1 × v2 |

计算步骤:

⑴、获取多边形顶点数组PList;

⑵、计算DPList[Vi+1-Vi];

⑶、单位化NormalizeDPList,得到NDP[DPi];(用同一个数组存储)

⑷、sinα = Dp(i+1) X DP(i);

⑸、Qi = Pi + d/sinα (NDPi+1-NDPi)

⑹、这样一次性可以把所有顶点计算完。

注意,交换Qi表达式当中NDPi+1-NDPi的顺序就可以得到外部多边形顶点数组。

用Swift实现的代码如下,在playground可直接运行

import Foundation

class Point2D  {
    var x:Double =0
    var y:Double =0
    init(_ x:Double,_ y:Double){self.x=x;self.y=y}
    init( point:Point2D){x=point.x;y=point.y}
}


func +  (left:Point2D, right:Point2D)->Point2D   {return Point2D(left.x+right.x, left.y+right.y)}
func -  (left:Point2D, right:Point2D)->Point2D   {return Point2D(left.x-right.x, left.y-right.y)}
func *  (left:Point2D, right:Point2D)->Double    {return left.x*right.x + left.y*right.y}
func *  (left:Point2D, value:Double )->Point2D   {return Point2D(left.x*value, left.y*value)}

// 自定义的向量差乘运算符号,
infix operator ** {}
func ** (left:Point2D, right:Point2D)->Double {return left.x*right.y - left.y*right.x}
var pList   = [Point2D]()  // 原始顶点坐标, 在initPList函数当中初始化赋值
var dpL
  • 12
    点赞
  • 122
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值