Point in Polygon 问题 opencv3.2 demo

一、Background

最近做相关项目检测某一点是否在划定的一个区域内,百度之后发现了这类问题属于Point in Polygon。主要有两种方法解决:

1、Crossing Number (cn) 方法
测试点作为起点画一条射线穿过不规则区域,与区域相交的点为奇数则此点在区域内,为偶数则在区域外,此种情况不准确(射线穿过不规则矩形框顶点时)。


2、Winding Number (wn)方法
这种方法是一种环绕算法,可参考
#include "opencv2\highgui\highgui_c.h"
#include "opencv2\imgproc\imgproc_c.h"
#include "opencv2\core\core_c.h"
#include "opencv2\imgcodecs\imgcodecs_c.h"
#include "opencv2\core\types_c.h"
#include <stdio.h>
#define POINT_NUM 6//不规则矩形顶点数
int wn_PnPoly(CvPoint P, CvPoint* V, int n);
CvPoint vertex_point[POINT_NUM],testpoint;
IplImage *org;
void on_mouse(int EVENT, int x, int y, int flags, void* userdata)
    static int i = 0,ii=1;
    CvScalar color_b = CV_RGB(0, 0, 255);
    CvScalar color_r = CV_RGB(255, 0, 0);
    switch (EVENT)
    case CV_EVENT_LBUTTONDOWN:
        if (ii)
            vertex_point[i] = cvPoint(x, y);
            cvCircle(org, vertex_point[i], 1, color_r,2,4,0);
            printf("vertex_point[%d]->(%d,%d)\n", i, vertex_point[i].x, vertex_point[i].y);
            if (i >= 1)
                cvLine(org, vertex_point[i - 1], vertex_point[i], color_r, 3, 4, 0);
                if (i == POINT_NUM - 1)
                    cvLine(org, vertex_point[i], vertex_point[0], color_r, 3, 4, 0);
                    vertex_point[POINT_NUM] = vertex_point[0];
                    ii = 0;
            testpoint=cvPoint(x, y);    
            int out_in=wn_PnPoly(testpoint, vertex_point, POINT_NUM);
            if (out_in==0)//outside
                cvCircle(org, testpoint, 2, color_b, 2, 4, 0);  
                printf("outside!\n");
            else//inside
                cvCircle(org, testpoint, 2, color_r, 2, 4, 0);
                printf("inside!\n");
        //  printf("result:%d", out_in);    
        break;
    default:
        break;
inline int isLeft(CvPoint P0, CvPoint P1, CvPoint P2)
    return ((P1.x - P0.x) * (P2.y - P0.y)
        - (P2.x - P0.x) * (P1.y - P0.y));
int cn_PnPoly(CvPoint P, CvPoint* V, int n)
    int    cn = 0;    // the  crossing number counter
                      // loop through all edges of the polygon
    for (int i = 0; i<n; i++) {    // edge from V[i]  to V[i+1]
        if (((V[i].y <= P.y) && (V[i + 1].y > P.y))     // an upward crossing
            || ((V[i].y > P.y) && (V[i + 1].y <= P.y))) { // a downward crossing
                                                          // compute  the actual edge-ray intersect x-coordinate
            float vt = (float)(P.y - V[i].y) / (V[i + 1].y - V[i].y);
            if (P.x <  V[i].x + vt * (V[i + 1].x - V[i].x)) // P.x < intersect
                ++cn;   // a valid crossing of y=P.y right of P.x
    return (cn & 1);    // 0 if even (out), and 1 if  odd (in)
int wn_PnPoly(CvPoint P, CvPoint* V, int n)
    int    wn = 0;    // the  winding number counter
                      // loop through all edges of the polygon
    for (int i = 0; i<n; i++) {   // edge from V[i] to  V[i+1]
        if (V[i].y <= P.y) {          // start y <= P.y
            if (V[i + 1].y  > P.y)      // an upward crossing
                if (isLeft(V[i], V[i + 1], P) > 0)  // P left of  edge
                    ++wn;            // have  a valid up intersect
        else {                        // start y > P.y (no test needed)
            if (V[i + 1].y <= P.y)     // a downward crossing
                if (isLeft(V[i], V[i + 1], P) < 0)  // P right of  edge
                    --wn;            // have  a valid down intersect
    return wn;
int main()
    org = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_COLOR);
    cvNamedWindow("lena", CV_WINDOW_AUTOSIZE);
    cvSetMouseCallback("lena", on_mouse, 0);
    while (true)
        cvShowImage("lena", org);
        if (cvWaitKey(20) ==13)break;
    cvReleaseImage(&org);
    cvDestroyAllWindows();

四、References

1.https://www.zhihu.com/question/26551754
2.http://geomalgorithms.com/a03-_inclusion.html

1.接口说明 #include "opencv2/imgproc/imgproc.hpp" double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist) 参数说明: contour – 输入区域的各个,围成一个区域。 pt – 需要判断的像素。 measureDist – 如果为false的话,返回值:在区域外部为-1,在区域内为1,在区域上为0。 如果为ture,则计算实际的像素符号距离,在区域外的像素距离为负值 实例来源于OpenCV自带历程,这里以OpenCV4.2为例,路径为:F:\opencv4.2_release\opencv\sources\samples\python\squares.py本文稍作修改,做简要说明。目标是找到下图中的矩形轮廓和四边形轮廓:矩形的检测包含检测轮廓是四个,同时两条边的夹角接近90°,代码和效果如下:import numpy as npi... 首先,我们知道OpenCV中有一个函数:pointPolygonTest()。它的作用是判断一个是否在轮廓中,基本用法如下: C++: double pointPolygonTest(InputArray contour, Point2f p... OPENCV C++ 判断一个是否一个矩形内(RECT) 在这里,线上的也算在矩形内; 如果不算线上的,将isPointInRect中判断<= 和>= 都改为< 和>; // A code C++ // An highlighted block bool isPointInRect(Point P, Rect rect) { Point A = rec... 信息指出错误可能出在两个方面 1、total >= 0 表示contour需要存在且数大于等于02、contour 中数据深度要是 32位int(int) 或者32位float(float)复现 项目中遇到的问题 排查了很久 函数说明total >= 0 但是为什么还是报错 我判断空vector是内容为空的 并不是total==0 所以才报错...