OpenCV - 对一组点拟合曲线

5
这篇文章是我之前发布的帖子的续篇:OpenCV - Remove "white" artifacts from image and fit a curve
在图像中,我通过对角线上的点来消除多余的白点。现在我的结果看起来像这样:

remove diag

我想将曲线适配到图像中剩下的点上。我一直在查阅OpenCV以前的帖子,有些人建议使用approxPolyDP。是否有更简单的方法在OpenCV中拟合曲线并显示它呢?
使用Hough曲线的想法对我来说有点太复杂了,因为我的图像本质上是二进制的:http://homepages.inf.ed.ac.uk/rbf/BOOKS/BANDB/LIB/bandb4_3.pdf
最终的图像是一个(0-255)灰度图,大小为w256 x h1024编辑 我刚刚使用线段连接了图像中的点。然而,我想要通过将平滑曲线连接到所有点上来连接它们。我已经在SO上搜索了这样的方法,但找不到一种方法。

connect


1
查看approxPolyDP可能会有所帮助。 - Haris
“平滑性”意味着(a)对生成这些点的过程有一些假设 - 您是否有物理模型?以及与它们相关的“噪声”/“误差”(它们与假定模型的偏差)?(b)为曲线考虑一些应用 - 产生漂亮的图片是一种应用,但也许您需要从样本和模型进行插值/外推的特定需求?要取得进展,您需要回答(a)和(b)两个问题。 - Francesco Callari
@Haris 我尝试在我的代码中使用findContours和approxPolyDP。但是,由于访问冲突错误,我无法使其工作。 - Eagle
@FrancescoCallari a. 不需要。 b. 不需要。我只需要将曲线拟合到这些点上。 - Eagle
1个回答

2

我认为Catmull-Rom样条曲线是您任务的一个不错选择。

您可以在此处找到实现代码: http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio

AHF评论的回答(根据Qix的建议放在这里):

此代码草图允许您使用鼠标编辑样条曲线,它使用此链接中的文件(附加到您的项目:overhauser.cpp、overhauser.hpp和vec3.hpp):

左键添加/移动点,右键删除。

代码并不是很难,所以我做了1通道修改(为了紧凑)。

我想你会理解的。

enter image description here

#include <iostream>
#include <vector>
#include <stdio.h>
#include <functional>
#include <algorithm>
#include <numeric>
#include <cstddef>
#include "opencv2/opencv.hpp"
#include <iostream>
#include <fstream>
#include "overhauser.hpp"

using namespace std;
using namespace cv;

Mat result;
Mat Img;

vector<cv::Point2f> pts;
Mat curvesImg;
int selectedPt=-1;
CRSpline* spline = 0;

unsigned char LUT_RED[256];

// a case-insensitive comparison function:
bool mycomp (Point2f p1, Point2f p2)
{
    return p1.x<p2.x;
}

float dist(Point2f p1,Point2f p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

int findNEarestPt(Point2f pt, float maxDist)
{
    float minDist=FLT_MAX;
    int ind=-1;
    for(int i=0;i<pts.size();++i)
    {
        float d=dist(pt,pts[i]);
        if(minDist>d)
        {
            ind=i;
            minDist=d;
        }
    }
    if(minDist>maxDist)
    {
        ind=-1;
    }
    return ind;
}

float F(float t,float x)
{
  vec3 rv = spline->GetInterpolatedSplinePoint(t);
  return x-rv.x;
}

float solveForX(float x)
{
    float a=0,b=1.0,c,e=1e-5;
    c=(a+b)/2;
    while( (fabs(b-a)>e) && (F(c,x)!=0) )
    {
        if (F(a,x)*F(c,x)<0)
        {
            b=c;
        }
        else
        {
            a=c;
        }
        c=(a+b)/2;
    }
return c;
}


int ind=-1;

void mouseHandler(int event, int x, int y, int flags, void* param)
{
    Point2f m;
    m.x=x;
    m.y=y;
    curvesImg=Scalar(0,0,0);

    switch (event)
    {
    case cv::EVENT_RBUTTONDOWN:
        ind=findNEarestPt(m,5);
        if (ind==-1)
        {

        }else
        {
            pts.erase(pts.begin()+ind);
            ind=-1;
        }
        break;
    case cv::EVENT_LBUTTONDOWN:
        ind=findNEarestPt(m,5);
        if (ind==-1)
        {
            pts.push_back(m);
            selectedPt=pts.size()-1;
        }else
        {
            selectedPt=ind;
        }
        break;
    case cv::EVENT_MOUSEMOVE:
        if(ind!=-1)
        {
            pts[selectedPt].x=m.x;
            pts[selectedPt].y=m.y;
        }
        break;
    case cv::EVENT_LBUTTONUP:
        ind=-1;
        break;
    }

    std::sort(pts.begin(),pts.end(),mycomp);
    if(pts.size()>0)
    {
        pts[pts.size()-1].x=curvesImg.cols;
        pts[0].x=0;
    }

    for(int i=0;i<pts.size();++i)
    {
        circle(curvesImg,pts[i],5,Scalar(0,255,255),-1,CV_AA);
    }

    if (spline) {delete spline;}
    spline = new CRSpline();

    for (int i=0;i<pts.size();++i)
    {
        vec3 v(pts[i].x,pts[i].y,0);
        spline->AddSplinePoint(v);
    }

    vec3 rv_last(0,0,0);
    if(pts.size()>2)
    {
        for(int i=0;i<256;++i)
        {
            float t=solveForX(i);
            vec3 rv = spline->GetInterpolatedSplinePoint(t);
            unsigned char I=(unsigned char)(rv.y);
            LUT_RED[i]=255-I;
            if(i>1)
            {
                line(curvesImg,Point(rv.x,rv.y),Point(rv_last.x,rv_last.y),Scalar(0,0,255),1);
            }
            rv_last=rv;
        }
    }

    line(curvesImg,Point(0,m.y),Point(curvesImg.cols,m.y),Scalar(0,255,0),1);
    line(curvesImg,Point(m.x,0),Point(m.x,curvesImg.rows),Scalar(0,255,0),1);

    imshow("Result",curvesImg); 

    vector<Mat> ch;
    cv::split(Img,ch);

    LUT(ch[2],Mat(256,1,CV_8UC1,LUT_RED),ch[2]);

    cv::merge(ch,result);

    imshow("Transformed",result);   
}
// ---------------------------------
// 
// ---------------------------------
//==============================================================================

int main( int argc, char** argv )
{

    for (int i=0;i<256;++i)
    {
        LUT_RED[i]=i;
    }

    namedWindow("Image",cv::WINDOW_NORMAL);
    namedWindow("Result");
    namedWindow("Transformed");

    Img=imread("D:\\ImagesForTest\\lena.jpg",1);

    imshow("Image",Img);

    curvesImg=Mat::zeros(256,256,CV_8UC3);
    setMouseCallback("Result", mouseHandler, NULL);
    waitKey(0);

    getchar();
}

但是当我们完成代码后,是否有任何函数可以移动BGR曲线? - AHF
我不理解你的问题,请你重新表达一下。 - Andrey Smorodov
你给了我相同的建议,所以我在谈论这个场景:https://dev59.com/C3_aa4cB1Zd3GeqP6Kk1 - AHF
主要的困难是什么?是鼠标控制的曲线吗? - Andrey Smorodov
是的,它是由鼠标控制的曲线,我希望我们可以通过鼠标改变曲线形状。 - AHF
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接