美文网首页
OpenCV坐标计算辅助

OpenCV坐标计算辅助

作者: youlianchun | 来源:发表于2017-08-31 11:54 被阅读0次

    OpenCV坐标计算辅助,其它情况可修改数点(cv::Point)数据类型以适用。
    用于一些坐标计算的辅助类,算法来源于初高中数学老师和互联网,后期整理出处。

    头信息

    #include <vector>
    #include <opencv2/core/types.hpp>
    namespace CVG  {
    ...
    }
    

    角度(三点两线段角度计算)

    /**
     角度
    
     @param pt1 端点
     @param pt2 端点
     @param pt0 交点
     @return 角度
     */
    double CVG::angle(cv::Point pt1, cv::Point pt2, cv::Point pt0) {
        double dx1 = pt1.x - pt0.x;
        double dy1 = pt1.y - pt0.y;
        double dx2 = pt2.x - pt0.x;
        double dy2 = pt2.y - pt0.y;
        return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
    }
    

    中心点(线段中心点)

    /**
     中心点
    
     @param pt0 端点
     @param pt1 端点
     @return 端点
     */
    cv::Point CVG::center(cv::Point pt0, cv::Point pt1) {
        cv::Point pt;
        pt.x = (pt0.x+pt1.x)/2 + 0.5;
        pt.y = (pt0.y+pt1.y)/2 + 0.5;
        return pt;
    }
    

    距离(线段长度)

    /**
     距离长度
    
     @param pt0 端点
     @param pt1 端点
     @return 距离长度
     */
    double CVG::length( cv::Point pt0, cv::Point pt1) {
        double dist_x = pt0.x - pt1.x;
        double dist_y = pt0.y - pt1.y;
        return sqrt(pow(dist_x, 2)+pow(dist_y, 2));
    }
    

    多边形中心点(重心)

    /**
     多边形中心点
    
     @param pts 多边形坐标,环形分布
     @return 中心点
     */
    cv::Point CVG::center(std::vector<cv::Point> &pts) {
        long n = pts.size();
        cv::Point pt_c;
        if (n==0) {
            return pt_c;
        }
        long sum_x = 0, sum_y = 0;
        for (int i = 0; i < n; i ++) {
            cv::Point pt = pts[i];
            sum_x += pt.x;
            sum_y += pt.y;
        }
        pt_c.x = (int)(sum_x / n + 0.5);
        pt_c.y = (int)(sum_y / n + 0.5);
        return pt_c;
    }
    

    两线段交点(不存在返回极大值点)

    /**
     两线段交点
     
     @param l0p0 线段0端点
     @param l0p1 线段0端点
     @param l1p0 线段1端点
     @param l1p1 线段1端点
     @return 交点
     */
    cv::Point CVG::intersects(cv::Point l0p0, cv::Point l0p1, cv::Point l1p0, cv::Point l1p1) {
        int delta, r, u;
        cv::Point p;//交点
        delta = (l0p1.x - l0p0.x) * (l1p0.y - l1p1.y) - (l1p0.x - l1p1.x) * (l0p1.y - l0p0.y);
        if(delta == 0)  {
            p.x = INT_MAX;
            p.y = INT_MAX;
        }  else {
            r = ((l1p0.x - l0p0.x) * (l1p0.y - l1p1.y) - (l1p0.x - l1p1.x) * (l1p0.y - l0p0.y)) / delta;
            u = ((l0p1.x - l0p0.x) * (l1p0.y - l0p0.y) - (l1p0.x - l0p0.x) * (l0p1.y - l0p0.y)) / delta;
            if((r >= 0 && r <= 1) && (u >= 0 && u <= 1))   {
                p.x = l0p0.x + r*(l0p1.x - l0p0.x);
                p.y = l0p0.y + r*(l0p1.y - l0p0.y);
            } else {
                p.x = INT_MAX;
                p.y = INT_MAX;
            }
        }
        return p;
    }
    

    线段延长点(from 到 to方向上扩张dist距离,返回新的to坐标)

    /**
     线段延长点
     
     @param from 线段开始
     @param to 线段结束
     @param dist 延长距离
     @return 新的结束点
     */
    cv::Point CVG::lineExp(cv::Point from, cv::Point to, double dist) {
        double dist_x = to.x - from.x;
        double dist_y = to.y - from.y;
        double s = dist/sqrt(pow(dist_x, 2)+pow(dist_y, 2))+1;
        cv::Point p;
        p.x = s*(dist_x)+from.x;
        p.y = s*(dist_y)+from.y;
        return p;
    }
    

    多边形扩张(凹边形未验证)以重心为原点向各个顶点方向进行扩张

    /**
     多边形扩张
    
     @param pts 多边形坐标,环形分布
     @param dist 扩张距离(中心点方向)
     @return 新坐标
     */
    std::vector<cv::Point> CVG::shapeExp(std::vector<cv::Point> &pts, double dist) {
        cv::Point pt_c = CVG::center(pts);
        std::vector<cv::Point> pts_n;
        for (int i = 0; i < pts.size(); i ++) {
            cv::Point pt = cv::Point(pts[i].x, pts[i].y);
            double dist_x = pt.x - pt_c.x;
            double dist_y = pt.y - pt_c.y;
            double ratio = dist/sqrt(pow(dist_x, 2)+pow(dist_y, 2))+1;
            pt.x = ratio * (dist_x)+0.5 + pt_c.x;
            pt.y = ratio * (dist_y)+0.5 + pt_c.y;
            pts_n.push_back(pt);
        }
        return pts_n;
    }
    

    多边形平移(对于矫正前的平移处理可能需要进行多次)

    /**
     多边形平移
     
     @param pts 多边形坐标,环形分布
     @param offset 偏移量
     @return 新坐标
     */
    std::vector<cv::Point> CVG::shapeMove(std::vector<cv::Point> &pts, cv::Point offset) {
        std::vector<cv::Point> pts_n;
        for (int i = 0; i<pts.size(); i++) {
            cv::Point pt = pts[i];
            cv::Point pt_n;
            pt_n.x = pt.x+offset.x;
            pt_n.y = pt.y+offset.y;
            pts_n.push_back(pt_n);
        }
        return pts_n;
    }
    

    多边形旋转(以重心为原点对各个顶点坐标进行旋转,旋转角度:a/180.0*M_PI )

    /**
     多边形旋转
     
     @param pts 多边形坐标,环形分布
     @param angle 旋转角度(正逆时针,负顺时针)
     @return 新坐标
     
     点(x,y)绕(x0,y0)逆时针旋转a角后变成(x',y'),则
     x'-x0=(x-x0)cosa-(y-y0)sina
     y'-y0=(x-x0)sina+(y-y0)cosa
     */
    std::vector<cv::Point> CVG::shapeRotate(std::vector<cv::Point> &pts, double angle) {
        cv::Point pt_c = CVG::center(pts);
        std::vector<cv::Point> pts_n;
    
        double sa = sin(angle);
        double ca = cos(angle);
        for (int i = 0; i<pts.size(); i++) {
            cv::Point pt = pts[i];
            cv::Point pt_n;
            pt_n.x = pt_c.x + ((pt.x-pt_c.x)*ca - (pt.y-pt_c.y)*sa);
            pt_n.y = pt_c.y + ((pt.x-pt_c.x)*sa + (pt.y-pt_c.y)*ca);
            pts_n.push_back(pt_n);
        }
        return pts_n;
    }
    

    多边形凹凸性检查

    /**
     多边形凹凸性检查
    
     @param pts 多边形坐标,环形分布
     @return -1 凸集, 1凹集, 0 不合法
     */
    int CVG::shapeConvex(std::vector<cv::Point> &pts) {
        long i,j,k;
        int flag = 0;
        int z;
        long n = pts.size();
        if (n < 3)
            return 0;
        for (i=0;i<n;i++){
            j = (i + 1) % n;
            k = (i + 2) % n;
            z = (pts[j].x - pts[i].x) * (pts[k].y - pts[j].y);
            z -= (pts[j].y - pts[i].y) * (pts[k].x - pts[j].x);
            if(z<0)
                flag |= 1;
            else if (z > 0)
                flag |= 2;
            if (flag==3)
                return -1;//凸集
        }
        if (flag != 0) //凹集
            return 1;
        else
            return 0; //不合法
    }
    

    点与多边形关系,采用铅垂线法

    /**
     点与多边形关系
     
     @param pts 多边形坐标,环形分布
     @param pt 点
     @return true多边形上, fale多边形外
     */
    bool CVG::inside(std::vector<cv::Point> &pts, cv::Point pt) {
        int n = 0;
        int min_y = INT_MAX;
        for (int i = 0; i<pts.size(); i++) {
            min_y = cv::min(min_y, pts[i].y);
        }
        cv::Point pt_min = cv::Point(pt.x, min_y-10);
        
        for (int i = 0; i<pts.size(); i++) {
            cv::Point pt0 = pts[i];
            cv::Point pt1 = pts[(i+1)%pts.size()];
            if ((pt.x>=pt0.x && pt.x<=pt1.x) || (pt.x>=pt1.x && pt.x<=pt0.x)) {
                cv::Point pi = CVG::intersects(pt, pt_min, pt0, pt1);
                if (pi.x != INT_MAX && pi.y != INT_MAX) {
                    n++;
                }
            }
        }
        return n%2 != 0;
    }
    

    来一个今天新写的函数(有bug请留言)
    统计多边形凹点坐标

    /**
     多边形凹点下标
     
     @param pts 多边形坐标,环形分布
     @return 凹点下标
     */
    std::vector<long> CVG::pits(std::vector<cv::Point> &pts) {
        int min_y = INT_MAX;
        for (int i = 0; i<pts.size(); i++) {
            min_y = cv::min(min_y, pts[i].y);
        }
        min_y -= 10;
        
        std::vector<long> ipts;
        long ct = pts.size();
        for (long i = 0; i < ct; i++) {
            long i_2 = i+2;
            if (i_2 >= ct) {
                i_2 -= ct;
            }
            cv::Point pt = CVG::center(pts[i], pts[i_2]);
            CVG::inside(pts, pt);
            
            cv::Point pt_min = cv::Point(pt.x, min_y);
            int ipt_ct = 0;
            for (int i = 0; i<pts.size(); i++) {
                cv::Point pt0 = pts[i];
                cv::Point pt1 = pts[(i+1)%pts.size()];
                if ((pt.x>=pt0.x && pt.x<=pt1.x) || (pt.x>=pt1.x && pt.x<=pt0.x)) {
                    cv::Point pi = CVG::intersects(pt, pt_min, pt0, pt1);
                    if (pi.x != INT_MAX && pi.y != INT_MAX) {
                        ipt_ct++;
                    }
                }
            }
            if (ipt_ct%2 == 0) {
                long ipt_idx = i+1;
                if (ipt_idx >= ct) {
                    ipt_idx -= ct;
                }
                ipts.push_back(ipt_idx);
            }
        }
        return ipts;
    }
    

    其它常用计算发掘中,欢迎各位提供其它计算方式,一起整合资源。
    函数计算有误或精度误差的还请留言提醒,不胜感激!

    相关文章

      网友评论

          本文标题:OpenCV坐标计算辅助

          本文链接:https://www.haomeiwen.com/subject/gvqqjxtx.html