计算两个多边形的交集

2023-11-06

一、问题描述


已知两个多边形Polygon1和Polygon2,分别由点集C1={P1,P2,...,Pm}和C2={Q1,Q2,...,Qn}表示,求这两个多边形的交集。

二、算法思想


两个多边形相交后,其顶点要么是两个多边形边的交点,要么是在多边形内部的点。

三、算法步骤


  1. 计算两个多边形每条边之间的交点。

  1. 计算包含在多边形内部的点。

  1. 将交点和多边形内部的点,按逆时针(或顺时针)排序,得出最终的点集。

四、代码实现


代码基本实现如下:

4.1 头文件

PolygonIntersection.h

#pragma once
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

//点集排序
//若点a大于点b,即点a在点b顺时针方向,返回true,否则返回false
bool PointCompare(const cv::Point &a, const cv::Point &b, const cv::Point &center)
{
    if (a.x >= 0 && b.x < 0)
        return true;
    if (a.x == 0 && b.x == 0)
        return a.y > b.y;
    //向量OA和向量OB的叉积
    int det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
    if (det < 0)
        return true;
    if (det > 0)
        return false;
    //向量OA和向量OB共线,以距离判断大小
    int d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
    int d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);

    return d1 > d2;
}
// 顺时针方向排序
void ClockwiseSortPoints(std::vector<cv::Point> &vPoints)
{
    //计算重心
    cv::Point center;
    int count_size = vPoints.size();
    double x = 0, y = 0;
    for (int i = 0; i < count_size; i++)
    {
        x += vPoints[i].x;
        y += vPoints[i].y;
    }
    center.x = (int)x / count_size;
    center.y = (int)y / count_size;

    //冒泡排序
    for (int i = 0; i < count_size - 1; i++)
    {
        for (int j = 0; j < count_size - i - 1; j++)
        {
            if (PointCompare(vPoints[j], vPoints[j + 1], center))
            {
                cv::Point tmp = vPoints[j];
                vPoints[j] = vPoints[j + 1];
                vPoints[j + 1] = tmp;
            }
        }
    }

    return;
}

//判断点是否在多边形内部/
//  The function will return YES if the point x,y is inside the polygon, or
//  NO if it is not.  If the point is exactly on the edge of the polygon,
//  then the function may return YES or NO.
bool IsPointInPolygon(const std::vector<cv::Point> &poly, const cv::Point &pt)
{
    int i, j;
    bool c = false;
    int count = poly.size();
    for (i = 0, j = count - 1; i < count; j = i++)
    {
        if ((((poly[i].y <= pt.y) && (pt.y < poly[j].y)) ||
            ((poly[j].y <= pt.y) && (pt.y < poly[i].y)))
            && (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x))
        {
            c = !c;
        }
    }

    return c;
}

 ///线段相交判断//
//排斥实验
bool IsRectCross(const cv::Point &p1, const cv::Point &p2, const cv::Point &q1, const cv::Point &q2)
{
    bool ret = min(p1.x, p2.x) <= max(q1.x, q2.x) &&
        min(q1.x, q2.x) <= max(p1.x, p2.x) &&
        min(p1.y, p2.y) <= max(q1.y, q2.y) &&
        min(q1.y, q2.y) <= max(p1.y, p2.y);

    return ret;
}
//跨立判断
bool IsLineSegmentCross(const cv::Point &pFirst1, const cv::Point &pFirst2, const cv::Point &pSecond1, const cv::Point &pSecond2)
{
    long line1, line2;
    line1 = pFirst1.x * (pSecond1.y - pFirst2.y) +
        pFirst2.x * (pFirst1.y - pSecond1.y) +
        pSecond1.x * (pFirst2.y - pFirst1.y);
    line2 = pFirst1.x * (pSecond2.y - pFirst2.y) +
        pFirst2.x * (pFirst1.y - pSecond2.y) +
        pSecond2.x * (pFirst2.y - pFirst1.y);
    if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0))
        return false;

    line1 = pSecond1.x * (pFirst1.y - pSecond2.y) +
        pSecond2.x * (pSecond1.y - pFirst1.y) +
        pFirst1.x * (pSecond2.y - pSecond1.y);
    line2 = pSecond1.x * (pFirst2.y - pSecond2.y) +
        pSecond2.x * (pSecond1.y - pFirst2.y) +
        pFirst2.x * (pSecond2.y - pSecond1.y);
    if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0))
        return false;

    return true;
}

bool GetCrossPoint(const cv::Point &p1, const cv::Point &p2, const cv::Point &q1, const cv::Point &q2, long &x, long &y)
{
    if (IsRectCross(p1, p2, q1, q2))
    {
        if (IsLineSegmentCross(p1, p2, q1, q2))
        {
            //求交点
            long tmpLeft, tmpRight;
            tmpLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y);
            tmpRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x);

            x = (int)((double)tmpRight / (double)tmpLeft);

            tmpLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x);
            tmpRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x - p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y);
            y = (int)((double)tmpRight / (double)tmpLeft);
            return true;
        }
    }
    return false;
}
 ///线段相交结束//

 //多边形交集
bool PolygonClip(const std::vector<cv::Point> &poly1, const std::vector<cv::Point> &poly2, std::vector<cv::Point> &interPoly)
{
    if (poly1.size() < 3 || poly2.size() < 3)
    {
        return false;
    }

    long x, y;
    //计算多边形交点
    int count1 = poly1.size();
    int count2 = poly2.size();
    for (int i = 0; i < count1; i++)
    {
        int poly1_next_idx = (i + 1) % count1;
        for (int j = 0; j < count2; j++)
        {
            int poly2_next_idx = (j + 1) % count2;
            if (GetCrossPoint(poly1[i], poly1[poly1_next_idx],
                poly2[j], poly2[poly2_next_idx],
                x, y))
            {
                interPoly.push_back(cv::Point(x, y));
            }
        }
    }

    //计算多边形内部点
    for (int i = 0; i < count1; i++)
    {
        if ( IsPointInPolygon(poly2, poly1[i]) )
        {
            interPoly.push_back(poly1[i]);
        }
    }
    for (int i = 0; i < count2; i++)
    {
        if ( IsPointInPolygon(poly1, poly2[i]) )
        {
            interPoly.push_back(poly2[i]);
        }
    }

    if (interPoly.size() <= 0)
        return false;

    //点集排序
    ClockwiseSortPoints(interPoly);

    return true;
}

4.2 主函数调用实现

main.cpp

#include "PolygonIntersection.h"

int main()
{
    std::vector<cv::Point> poly1;
    std::vector<cv::Point> poly2;
    // 多边形1 点集赋值
    poly1.push_back(cv::Point(50,30));
    poly1.push_back(cv::Point(100, 30));
    poly1.push_back(cv::Point(100, 130));
    poly1.push_back(cv::Point(50, 130));
    // 多边形2 点集赋值
    poly2.push_back(cv::Point(75, 80));
    poly2.push_back(cv::Point(125, 80));
    poly2.push_back(cv::Point(125, 180));
    poly2.push_back(cv::Point(75, 180));

    std::vector<cv::Point> interPoly;
    bool status = PolygonClip(poly1, poly2, interPoly);

    cv::Mat result = cv::Mat::zeros(300, 300, CV_8UC3);

    int count1 = poly1.size();
    for (int i = 0; i<count1; i++)
    {
        cv::Point p1 = poly1[i];
        cv::Point p2 = poly1[(i + 1) % count1];
        cv::line(result, p1, p2, cv::Scalar(255, 0, 0), 2, 8, 0);
    }

    int count2 = poly2.size();
    for (int i = 0; i < count2; i++)
    {
        cv::Point p1 = poly2[i];
        cv::Point p2 = poly2[(i + 1) % count2];
        cv::line(result, p1, p2, cv::Scalar(0, 255, 0), 2, 8, 0);
    }

    int count3 = interPoly.size();
    for (int i = 0; i < count3; i++)
    {
        cv::Point p1 = interPoly[i];
        cv::Point p2 = interPoly[(i + 1) % count3];
        cv::line(result, p1, p2, cv::Scalar(0, 0, 255), 2, 8, 0);
    }


    return 0;
}

4.3 结果

红色矩形框的顶点就是两个多边形相交的点

五、参考资料


https://www.cnblogs.com/dwdxdy/p/3232110.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

计算两个多边形的交集 的相关文章

  • C++ OpenCV imread 无法在 Android 中工作

    我正在尝试读取 C 代码中的图像 LOGD Loading image s n inFile c str Mat img imread inFile CV LOAD IMAGE GRAYSCALE CV Assert img data 0
  • cv2.cv.BoxPoints(rect) 返回什么?

    rect cv2 minAreaRect largest contour rect rect 0 0 self scale down rect 0 1 self scale down rect 1 0 self scale down rec
  • 如何提取图像中的表格

    我想从图像中提取表格 这个 python 模块https pypi org project ExtractTable https pypi org project ExtractTable 与他们的网站https www extractta
  • 带有 OpenCV 的增强现实 SDK [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何使图像呈现出陈旧、布满灰尘、颜色褪色的外观?

    我有旧画的图像 这些画很旧 布满灰尘 颜色褪色 如图所示here https i stack imgur com xuoEF jpg 如何赋予任何图像这种 旧 外观 我找不到任何过滤器或 openCV 函数来实现这种类型的外观 EDIT 我
  • 在 Python 3.5 64 位上通过 pip 安装 OpenCV

    我尝试安装 OpenCV 但找不到任何合适的 pip 软件包 我决定上网查找有关如何安装它的官方文档 并发现this https opencv python tutroals readthedocs io en latest py tuto
  • 使用 opencv warpPerspective() 生成道路的自上而下视图

    我正在尝试实施逆透视映射计算与道路上另一辆车的距离 我知道在应用该函数之前我需要生成一个包含源点和目标点的变换矩阵warpPerspective 但我不知道如何计算目的地点 我在这个论坛和其他网站中搜索 但无法将第一张图片转换为第二张图片
  • 如何删除树莓派的相机预览

    我在我的 raspberryPi 上安装了 SimpleCv 并安装了用于使用相机板的驱动程序 uv4l 驱动程序 现在我想使用它 当我在 simpleCV shell Camera 0 getImage save foo jpg 上键入时
  • 如何使用 Python 将我的 GoPro Hero 4 相机直播连接到 openCV?

    我在尝试从我的新 GoPro Hero 4 相机捕获实时流并使用 openCV 对其进行一些图像处理时遇到麻烦 这是我的试用 创建的窗口上没有显示任何内容 import cv2 import argparse import time imp
  • 使用Python的工业视觉相机[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 多视图几何

    我从相距一定距离的两台相同品牌的相机捕获了两张图像 捕获了相同的场景 我想计算两个相机之间的现实世界旋转和平移 为了实现这一点 我首先提取了两张图像的 SIFT 特征并进行匹配 我现在有基本矩阵也单应性矩阵 然而无法进一步进行 有很多混乱
  • 如何将输出视频保存到 OpenCV 中的文件中

    我想将输出视频保存到文件中而不是显示它并尝试使用 cvcaptureimage 但仍然无法获得结果 include
  • opencv 2.3.* 读取不工作

    我无法让 imread 工作 与这个人有同样的问题 OpenCV imwrite 2 2 在 Windows 7 上导致异常 并显示消息 OpenCV 错误 未指定错误 无法找到指定扩展名的编写器 https stackoverflow c
  • OpenCV 2.3 与 VS 2008 - 鼠标事件

    强制性 我是新手 有一份涉及编程的工作 并且我一边工作一边自学 不用说 作为一名老师 我经常犯彻底的错误 我现在所处的位置 我创建了 Graph 类 它 令人惊讶的是 制作了图表 但现在我想通过单击鼠标来修改图形 但我似乎无法让鼠标处理程序
  • ffmpeg AVFrame 到 opencv Mat 转换

    我目前正在开发一个使用 ffmpeg 解码接收到的帧的项目 解码后 我想将 AVFrame 转换为 opencv Mat 帧 以便我可以在 imShow 函数上播放它 我拥有的是字节流 我将其读入缓冲区 解码为 AVFrame f fope
  • 如何使用 python、openCV 计算图像中的行数

    我想数纸张 所以我正在考虑使用线条检测 我尝试过一些方法 例如Canny HoughLines and FLD 但我只得到处理过的照片 我不知道如何计算 有一些小线段就是我们想要的线 我用过len lines or len contours
  • 如何去除给定图像中的噪声,使 ocr 输出完美?

    我已经对这个孟加拉文本图像进行了大津阈值处理 并使用 tesseract 进行 OCR 但输出非常糟糕 我应该应用什么预处理来消除噪音 我也想校正图像 因为它有轻微的倾斜 我的代码如下 import tesserocr from PIL i
  • opencv人脸检测示例

    当我在设备上运行应用程序时 应用程序崩溃并显示以下按摩 java lang UnsatisfiedLinkError 无法加载 detector based tracker findLibrary 返回 null 我正在使用 OpenCV
  • 如何使用 opencv python 计算乐高积木上的孔数?

    我正在开发我的 python 项目 我需要计算每个乐高积木组件中有多少个孔 我将从输入 json 文件中获取有关需要计算哪个程序集的信息 如下所示 img 001 red 0 blue 2 white 1 grey 1 yellow 1 r

随机推荐

  • 虚拟机VMware Tools安装步骤

    Vmware tools是虚拟机中一款超级增强工具 可以让我们更加方便使用虚拟机 能实现主机与虚拟机之间的文件共享 这篇文章主要介绍了虚拟机VMware Tools安装步骤 需要的朋友可以参考下 本人安装VMware Tools 的需求是
  • 多线程抽取数据库数据

    记录一次多线成抽取数据的方案 public void static main String args 每页大小 int pageSize 100 总记录数 int totalCount ProductDAO countAll 计算一共有多少
  • java中Date日期类型的大小比较

    1 通过Date提供的compareTo 进行比较 java util Date类实现了Comparable接口 可以直接调用Date的compareTo 方法来比较大小 String beginTime 2018 07 28 14 42
  • Vue框架--Ruoyi解析

    Ruoyi是一个基于Vue js和Spring Boot的开源企业级快速开发平台 它提供了一套完整的前后端分离的解决方案 下面对Ruoyi的主要特点和架构进行解析 8大流程 前端技术栈 Ruoyi使用了Vue js作为前端框架 采用了Ele
  • android组件悬浮,Android 滑动组件悬浮固定在顶部

    要想实现的效果是如下 场景 有些时候是内容中间的组件当滑动至顶部的时候固定显示在顶部 实现的思路 1 目标组件 button 有两套 放在顶部和内容中间 2 当内容中间的组件滑动至顶部栏位置时控制显示 隐藏顶部和中间的组件 涉及到组件获取在
  • c++json nlohmann 和 poco json 使用,boost

    C 使用nlohmann json 最好用的c json库是 nlohmann C 使用nlohmann json wphkadn的博客 CSDN博客 把变量写成json容易 可是把json变成变量就要复杂一点 不过对于nlohmann一点
  • adb devices 出现????

    1 ubantu下adb 的安装 1 安装 sudo apt get install android tools adb 2 查看是否安装成功 adb v 有信息表示成功 2 配置 2 1查找设备 1 看adb 是否识别安卓设备 插入usb
  • iOS设备自动登录汕大校园网认证 一次设置永久免登录

    介绍 本文将介绍如何在苹果设备 Mac iPad iPhone 上使用捷径 Shortcuts 来使设备每次连接校园网WiFi后自动使用校园网账号登录 以及一键查询流量情况 当然 你也可以创建快捷方式在桌面以便掉线时一键重连 无须再前往浏览
  • 八道练习题教你轻松学会运用Unity中的协程用法

    携程 协程是什么 协程有什么用 为什么要用携程 练习题与讲解 第一题 第二题 第三题 第四题 第五题 第六题 第七题 第八题 要点总结 协程是什么 简单来说 协程就是Unity官方提供的一个类似于C 中多线程的功能 可以在组件中使用 即继承
  • Java-钉钉订阅事件

    文章目录 背景 什么是钉钉订阅事件 钉钉订阅事件的应用场景 整体思路 查看钉钉文档 什么是钉钉回调 钉钉回调具体实操 创建自己的应用 钉钉回调 开发过程中遇到的问题 总结 背景 最近需要做一个业务 钉钉组织架构下添加人员之后 要对该人员的数
  • 班级排名

    import java util Arrays import java util LinkedList import java util List import java util Scanner public class Main pub
  • 【C++入门到精通】C++入门—缺省参数、函数重载

    目录 前言 一 缺省参数 1 缺省参数的概念 2 缺省参数分类 全缺省参数 半缺省参数 二 函数重载 1 函数重载的概念 2 函数重载类型 参数类型不同 参数个数不同 参数类型顺序不同 C 支持函数重载的原理 名字修饰 name Mangl
  • CDH 1、CDH简介

    1 Apache Hadoop 不足之处 版本管理混乱 部署过程繁琐 升级过程复杂 兼容性差 安全性低 2 Hadoop 发行版 Apache Hadoop Cloudera s Distribution Including Apache
  • 将单个字节数据读取到一个float类型的数据中---的几种方法

    从串口读取传感器值的时候总是一个一个字节 高八位低八位 需要拼接成一个float或者int的时候 这些方法有用处 1 联合体方式 union float f unsigned char x 4 data data x 0 0xA2 data
  • Eslint如何不忽略node_modules里检测(vue+webpack项目)

    背景 我们项目里的业务组件是以单独的仓库子模块的形式 通过安装包的形式install到主项目里node modules里的 主项目是开启了eslint检测的 但是发现对node modules里的内容是不起作用的 但因为公司的质量检测组要扫
  • Chrome利器之FireShot:网页长截图工具

    首先对于很多写博客写文章的笔友来说 难免少不了一些网页截图或者gif图之类的 现在这里讲的是一个便捷的谷歌浏览器长截图插件 FireShot FireShot功能特点 可以截取整个页面 可见部分和选定区域 并且支持拖动加载截图 非常方便 下
  • python logging 不输出控制台_解决Python logging模块无法正常输出日志的问题

    废话少说 先上代码 File logger conf formatters keys default formatter default format asctime s name s levelname s message s class
  • 解读JDK11新特性

    本文主要介绍JDK11的部分新特性和新的API 1 Local Var 在Lambda表达式中 可以使用var关键字来标识变量 变量类型由编译器自行推断 public class LocalVar public static void ma
  • c, c++函数名编译符号修饰符说明

    C 编译器的函数名修饰规则 函数名字修饰 Decorated Name 方式 函数的名字修饰 Decorated Name 就是编译器在编译期间创建的一个字符串 用来指明函数的定义或原型 LINK程序或其它工具有时须要指定函数的名字修饰来定
  • 计算两个多边形的交集

    一 问题描述 已知两个多边形Polygon1和Polygon2 分别由点集C1 P1 P2 Pm 和C2 Q1 Q2 Qn 表示 求这两个多边形的交集 二 算法思想 两个多边形相交后 其顶点要么是两个多边形边的交点 要么是在多边形内部的点