三次贝塞尔曲线平滑多边形

#pragma once

#include "opencv.hpp"
#include "StdStrFile.h"

void CurvePoly(const std::vector<cv::Point>& vPtsInput, std::vector<cv::Point> &curvePoint);
#include "CurvePoly.h"

//三次贝塞尔曲线  
float bezier3funcX(float uu, cv::Point *controlP){
    float part0 = controlP[0].x * uu * uu * uu;
    float part1 = 3 * controlP[1].x * uu * uu * (1 - uu);
    float part2 = 3 * controlP[2].x * uu * (1 - uu) * (1 - uu);
    float part3 = controlP[3].x * (1 - uu) * (1 - uu) * (1 - uu);
    return part0 + part1 + part2 + part3;
}
float bezier3funcY(float uu, cv::Point *controlP){
    float part0 = controlP[0].y * uu * uu * uu;
    float part1 = 3 * controlP[1].y * uu * uu * (1 - uu);
    float part2 = 3 * controlP[2].y * uu * (1 - uu) * (1 - uu);
    float part3 = controlP[3].y * (1 - uu) * (1 - uu) * (1 - uu);
    return part0 + part1 + part2 + part3;
}

void CurvePoly(const std::vector<cv::Point>& vPtsInput, std::vector<cv::Point> &curvePoint)
{
    //控制点收缩系数 ,经调试0.6较好,cv::Point是opencv的,可自行定义结构体(x,y)
    int originCount = vPtsInput.size();
    float scale = 0.6;
    cv::Point* midpoints = new cv::Point[originCount];
    //生成中点       
    for (int i = 0; i < originCount; i++){
        int nexti = (i + 1) % originCount;
        midpoints[i].x = (vPtsInput[i].x + vPtsInput[nexti].x) / 2.0;
        midpoints[i].y = (vPtsInput[i].y + vPtsInput[nexti].y) / 2.0;
    }

    //平移中点  
    cv::Point* extrapoints = new cv::Point[2 * originCount];
    for (int i = 0; i < originCount; i++){
        int nexti = (i + 1) % originCount;
        int backi = (i + originCount - 1) % originCount;
        cv::Point midinmid;
        midinmid.x = (midpoints[i].x + midpoints[backi].x) / 2.0;
        midinmid.y = (midpoints[i].y + midpoints[backi].y) / 2.0;
        int offsetx = vPtsInput[i].x - midinmid.x;
        int offsety = vPtsInput[i].y - midinmid.y;
        int extraindex = 2 * i;
        extrapoints[extraindex].x = midpoints[backi].x + offsetx;
        extrapoints[extraindex].y = midpoints[backi].y + offsety;
        //朝 originPoint[i]方向收缩   
        int addx = (extrapoints[extraindex].x - vPtsInput[i].x) * scale;
        int addy = (extrapoints[extraindex].y - vPtsInput[i].y) * scale;
        extrapoints[extraindex].x = vPtsInput[i].x + addx;
        extrapoints[extraindex].y = vPtsInput[i].y + addy;

        int extranexti = (extraindex + 1) % (2 * originCount);
        extrapoints[extranexti].x = midpoints[i].x + offsetx;
        extrapoints[extranexti].y = midpoints[i].y + offsety;
        //朝 originPoint[i]方向收缩   
        addx = (extrapoints[extranexti].x - vPtsInput[i].x) * scale;
        addy = (extrapoints[extranexti].y - vPtsInput[i].y) * scale;
        extrapoints[extranexti].x = vPtsInput[i].x + addx;
        extrapoints[extranexti].y = vPtsInput[i].y + addy;
    }

    CStdStrFile ssf;
    std::vector<cv::Point> vResPts;

    cv::Point controlPoint[4];
    //生成4控制点,产生贝塞尔曲线
    for (int i = 0; i < originCount; i++)
    {
        controlPoint[0] = vPtsInput[i];
        int extraindex = 2 * i;
        controlPoint[1] = extrapoints[extraindex + 1];
        int extranexti = (extraindex + 2) % (2 * originCount);
        controlPoint[2] = extrapoints[extranexti];
        int nexti = (i + 1) % originCount;
        controlPoint[3] = vPtsInput[nexti];
        float u = 1;
        while (u >= 0){
            int px = bezier3funcX(u, controlPoint);
            int py = bezier3funcY(u, controlPoint);
            //u的步长决定曲线的疏密  
            u -= 0.05;
            cv::Point tempP = cv::Point(px, py);
            //存入曲线点   
            if (!ssf.VectorContains(vResPts, tempP))
            {
                vResPts.push_back(tempP);
            }
        }
    }

    //这样做是为了让函数输入和输出可以使用同一个参数
    curvePoint = vResPts;

    delete[] midpoints;
    midpoints = nullptr;
    delete[] extrapoints;
    extrapoints = nullptr;
}

 

posted @ 2017-10-20 16:21  秋月的私语  阅读(1518)  评论(0编辑  收藏  举报