pyclipper和ClipperLib操作多边型

目录

1. 等距离缩放多边形

1.1 python

1.2 c++


1. 等距离缩放多边形

1.1 python

环境配置

pip install opencv-python opencv-contrib-python
pip install pyclipper
pip install numpy
import cv2
import numpy as np
import pyclipper


def equidistant_zoom_contour(contour, margin):
    """
    等"距离"缩放多边形轮廓点
    :param contour: 一个图形的轮廓格式[[[x1, x2]],...],shape是(-1, 1, 2)
    :param margin: 轮廓外扩的像素距离,margin正数是外扩,负数是缩小
    :return: 外扩后的轮廓点
    """
    pco = pyclipper.PyclipperOffset()
    #  参数限制,默认成2,这里设置大一些,主要是用于多边形的尖角是否用圆角代替
    pco.MiterLimit = 10  # 2是圆角,10是尖角
    contour = contour[:, 0, :]
    pco.AddPath(contour, pyclipper.JT_MITER, pyclipper.ET_CLOSEDPOLYGON)
    solution = pco.Execute(margin)
    solution = np.array(solution).reshape(-1, 1, 2).astype(int)
    return solution


if __name__ == '__main__':
    poly = np.array([[[200, 200]], [[200, 300]], [[400, 350]], [[350, 200]], [[300, 200]], [[200, 100]]])
    contour1 = equidistant_zoom_contour(poly, 20)  # 等距离
    img = np.zeros((500, 500, 3))
    cv2.polylines(img, [contour1], True, (0, 255, 0), 3)
    cv2.polylines(img, [poly], True, (0, 0, 255), 3)

    cv2.namedWindow("img", cv2.WINDOW_NORMAL), cv2.imshow("img", img), cv2.waitKey()

参数MiterLimit=10是尖角(左图),默认值是2,圆角(右图) 

 

1.2 c++

第一版clipper: Download Clipper

最新版clipper2: https://github.com/AngusJohnson/Clipper2

官方介绍:https://angusj.com/clipper2/Docs/Overview.htm 

 (1)这里使用旧版clipper,下载后解压

(2)vs2019配置clipper环境,只需要添加包含目录即可。

(3) 添加现有clipper头文件和源码 clipper.cpp和clipper.hpp

#include <iostream>
#include <vector>
#include <clipper.hpp>

using namespace ClipperLib;

std::vector<IntPoint> equidistant_zoom_contour(const std::vector<std::vector<IntPoint>>& contours, double margin) {
    ClipperOffset co;
    co.MiterLimit = 10;  // 默认2圆角,10尖角
    co.AddPaths(contours, jtMiter, etClosedPolygon);
    Paths solution;
    co.Execute(solution, margin);

    std::vector<IntPoint> result;
    for (const auto& path : solution) {
        result.insert(result.end(), path.begin(), path.end());
    }

    return result;
}

int main() {
    Paths poly = {
        {{200, 200}, {200, 300}, {400, 350}, {350, 200}, {300, 200}, {200, 100}}
    };

    double margin = 20.0;

    std::vector<IntPoint> contour1 = equidistant_zoom_contour(poly, margin);

    cv::Mat img = cv::Mat::zeros(500, 500, CV_8UC3);
    std::vector<std::vector<cv::Point>> contours_cv(1);
    for (const auto& point : contour1) {
        contours_cv[0].emplace_back(point.X, point.Y);
    }

    cv::polylines(img, contours_cv, true, cv::Scalar(0, 255, 0), 3);

    contours_cv.clear();
    for (const auto& path : poly) {
        std::vector<cv::Point> contour_cv;
        for (const auto& point : path) {
            contour_cv.emplace_back(point.X, point.Y);
        }
        contours_cv.push_back(contour_cv);
    }

    cv::polylines(img, contours_cv, true, cv::Scalar(0, 0, 255), 3);

    cv::namedWindow("img", cv::WINDOW_NORMAL);
    cv::imshow("img", img);
    cv::waitKey(0);

    return 0;
}

MiterLimit默认2圆角(左图),10尖角 (右图)

 

小操作

1 轮廓点集合相互转换

ClipperLib::Paths cnts2Paths(std::vector<std::vector<cv::Point>>& cnts)
{
    ClipperLib::Paths paths(cnts.size());
    for (int i = 0; i < cnts.size(); i++)
    {
        std::vector< ClipperLib::IntPoint > path(cnts[i].size());
        for (int pt_i = 0; pt_i < cnts[i].size(); pt_i++)
        {
            path[pt_i] = ClipperLib::IntPoint(cnts[i][pt_i].x, cnts[i][pt_i].y);
        }
        paths[i] = path;
    }
    return paths;
}

std::vector<cv::Point> Path2cnt(ClipperLib::Path& path)
{
    std::vector<cv::Point> cnt(path.size());
    for (int pti = 0; pti < path.size(); pti++)
    {
        cnt[pti] = cv::Point(path[pti].X, path[pti].Y);
    }
    return cnt;
}

std::vector<std::vector<cv::Point>> Paths2cnts(ClipperLib::Paths& paths)
{
    std::vector<std::vector<cv::Point>> cnts(paths.size());
    for (int i = 0; i < paths.size(); i++)
        cnts[i] = Path2cnt(paths[i]);

    return cnts;
}

待续。。。

参考:https://www.cnblogs.com/01black-white/p/15292193.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mr.Q

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

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

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

打赏作者

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

抵扣说明:

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

余额充值