用孔收缩/扩展多边形的轮廓

Posted

技术标签:

【中文标题】用孔收缩/扩展多边形的轮廓【英文标题】:Shrink/Expand the outline of a polygon with holes 【发布时间】:2020-06-29 09:35:52 【问题描述】:

我想使用 boost::polygon 来扩展/收缩带孔的多边形。所以为了澄清一点,我有一个单一的数据结构

boost::polygon::polygon_with_holes_data<int> inPoly

其中 inPoly 包含描述矩形轮廓和在该矩形内形成孔的三角形的数据(在下图中,这是左侧的黑色绘图)。

现在我想

a) 扩展整个东西,使矩形变大而孔变小(导致下图中的红色多边形)或

b) 缩小它,使矩形变小而孔变大(导致下面的绿色图像)。

拐角不一定是直的,也可以是圆的或以某种方式“粗糙”。

我的问题:如何使用 boost::polygon 来做到这一点?

谢谢!

【问题讨论】:

也许是这个:boost.org/doc/libs/1_73_0/libs/geometry/doc/html/geometry/… 这是 boost::geometry,它不适用于 boost::polygon::polygon_with_holes_data - 这是我的数据可用的格式。或者是否有将它们转换为相关 boost:geometry 结构的函数? 【参考方案1】:

我回答了这个Expand polygons with boost::geometry?

是的,您可以教 Boost Geometry 对 Boost Polygon 类型起作用:

#include <boost/geometry/geometries/adapted/boost_polygon.hpp>

我想出了一个你描述的测试多边形:

boost::polygon::polygon_with_holes_data<int> inPoly;
bg::read_wkt("POLYGON ((0 0,0 1000,1000 1000,1000 0,0 0),(100 100,900 100,500 700,100 100))", inPoly);

现在,显然我们不能只在适应的多边形上buffer,也不能直接bg::assignbg::convert。所以,我想出了一个丑陋的解决方法,即转换为 WKT 并返回。然后你可以做缓冲,然后类似地转换回来。

它不是很优雅,但确实有效:

poly in;
bg::read_wkt(boost::lexical_cast<std::string>(bg::wkt(inPoly)), in);

完整演示

包括 SVG 输出:

Live On Coliru

#include <boost/polygon/polygon.hpp>
#include <boost/polygon/polygon_set_data.hpp>
#include <boost/polygon/polygon_with_holes_data.hpp>

#include <boost/geometry.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/buffer.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/adapted/boost_polygon.hpp>
#include <fstream>

namespace bp = boost::polygon;
namespace bg = boost::geometry;
using P = bp::polygon_with_holes_data<int>;
using PS = bp::polygon_set_data<int>;
using coordinate_type = bg::coordinate_type<P>::type;

int main() 
    P inPoly, grow, shrink;
    bg::read_wkt("POLYGON ((0 0,0 1000,1000 1000,1000 0,0 0),(100 100,900 100,500 700,100 100))", inPoly);

    
        // define our boost geometry types
        namespace bs = bg::strategy::buffer;
        namespace bgm = bg::model;
        using pt = bgm::d2::point_xy<coordinate_type>;
        using poly = bgm::polygon<pt>;
        using mpoly = bgm::multi_polygon<poly>;

        // define our buffering strategies
        using dist = bs::distance_symmetric<coordinate_type>;
        bs::side_straight  side_strategy;
        const int points_per_circle = 12;
        bs::join_round   join_strategy(points_per_circle);
        bs::end_round    end_strategy(points_per_circle);
        bs::point_circle point_strategy(points_per_circle);

        poly in;
        bg::read_wkt(boost::lexical_cast<std::string>(bg::wkt(inPoly)), in);

        for (auto [offset, output_p] :  std::tuple(+15, &grow), std::tuple(-15, &shrink) ) 
            mpoly out;
            bg::buffer(in, out, dist(offset), side_strategy, join_strategy, end_strategy, point_strategy);

            assert(out.size() == 1);
            bg::read_wkt(boost::lexical_cast<std::string>(bg::wkt(out.front())), *output_p);
        
    

    
        std::ofstream svg("output.svg");
        using pt = bg::model::d2::point_xy<coordinate_type>;
        boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
        mapper.add(inPoly);
        mapper.add(grow);
        mapper.add(shrink);

        mapper.map(inPoly, "fill-opacity:0.3;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
        mapper.map(grow, "fill-opacity:0.05;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
        mapper.map(shrink, "fill-opacity:0.05;fill:rgb(0,0,255);stroke:rgb(0,0,255);stroke-width:2");
    

output.svg 写道:

【讨论】:

对不起,我的另一个问题不知何故丢失了-谢谢您的详细回答!!!!【参考方案2】:

我或多或少偶然发现 boost::polygon 还提供了一个非常易于使用的函数: boost::polygon::polygon_set_data 提供了一个函数 resize() ,它完全按照上面描述的方式进行。使用附加的参数corner_fill_arc 和num_segments 可以创建圆角。

不知道为什么这个函数位于 boost::polygon::polygon_set_data 而不是 boost::polygon::polygon_with_holes_data 在我看来这将是这样一个函数更合乎逻辑的地方......

【讨论】:

可能与 Boost Geometry 中的算法返回多多边形的原因相同。感谢您发布此答案。我从来没有完全掌握 Boost Polygon 的窍门,而且这个功能隐藏得很好(我可能会说名字不好)

以上是关于用孔收缩/扩展多边形的轮廓的主要内容,如果未能解决你的问题,请参考以下文章

opencv 轮廓的外围多边形提取或者 删除最小最大轮廓

opencv 5 图像轮廓与图像分割修复 2 使用多边形将轮廓包围

opencv学习-物体轮廓-绘制轮廓外接多边形(凸包检测)

在R中相交轮廓和多边形

为多边形轮廓绘制圆的最有效方法

OpenCV——使用多边形包围轮廓