c++ - 给定点到给定椭圆的距离

标签 c++ opencv math ellipse

我有一个椭圆,由中心点、radiusX 和 radiusY 定义,并且我有一个点。我想在椭圆上找到最接近给定点的点。在下图中,这将是 S1。

graph1

现在我已经有了代码,但是其中的某个地方出现了逻辑错误,我似乎无法找到它。我将问题分解为以下代码示例:

#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>

using namespace std;

void dostuff();

int main()
{
    dostuff();
    return 0;
}

typedef std::vector<cv::Point> vectorOfCvPoints;

void dostuff()
{

    const double ellipseCenterX = 250;
    const double ellipseCenterY = 250;
    const double ellipseRadiusX = 150;
    const double ellipseRadiusY = 100;

    vectorOfCvPoints datapoints;

    for (int i = 0; i < 360; i+=5)
    {
        double angle = i / 180.0 * CV_PI;
        double x = ellipseRadiusX * cos(angle);
        double y = ellipseRadiusY * sin(angle);
        x *= 1.4;
        y *= 1.4;
        x += ellipseCenterX;
        y += ellipseCenterY;
        datapoints.push_back(cv::Point(x,y));
    }

    cv::Mat drawing = cv::Mat::zeros( 500, 500, CV_8UC1 );

    for (int i = 0; i < datapoints.size(); i++)
    {
        const cv::Point & curPoint = datapoints[i];
        const double curPointX = curPoint.x;
        const double curPointY = curPoint.y * -1; //transform from image coordinates to geometric coordinates

        double angleToEllipseCenter = atan2(curPointY - ellipseCenterY * -1, curPointX - ellipseCenterX); //ellipseCenterY * -1 for transformation to geometric coords (from image coords)

        double nearestEllipseX = ellipseCenterX + ellipseRadiusX * cos(angleToEllipseCenter);
        double nearestEllipseY = ellipseCenterY * -1 + ellipseRadiusY * sin(angleToEllipseCenter); //ellipseCenterY * -1 for transformation to geometric coords (from image coords)


        cv::Point center(ellipseCenterX, ellipseCenterY);
        cv::Size axes(ellipseRadiusX, ellipseRadiusY);
        cv::ellipse(drawing, center, axes, 0, 0, 360, cv::Scalar(255));
        cv::line(drawing, curPoint, cv::Point(nearestEllipseX,nearestEllipseY*-1), cv::Scalar(180));

    }
    cv::namedWindow( "ellipse", CV_WINDOW_AUTOSIZE );
    cv::imshow( "ellipse", drawing );
    cv::waitKey(0);
}

它会生成以下图像:

snapshot1

您可以看到它实际上在椭圆上找到了“最近”点,但不是“最近”点。我故意想要的是这样的:(原谅我画得不好)

snapshot2

你会扩展上一张图片中的线条吗,它们会穿过椭圆的中心,但上一张图片中的线条不是这种情况。
我希望你能得到这张照片。谁能告诉我我做错了什么?

最佳答案

考虑一个围绕给定点 (c, d) 的边界圆,它通过椭圆上最近的点。从图中可以清楚地看出,最近点是这样的,即从它到给定点的线必须垂直于椭圆和圆的共享切线。任何其他点都将在圆外,因此必须离给定点更远。

enter image description here

所以你要找的点不是直线和椭圆的交点,而是图中的点(x,y)。

切线梯度:

enter image description here

线的渐变:

enter image description here

垂直线的条件 - 梯度乘积 = -1:

enter image description here

enter image description here

enter image description here

当重新排列并代入椭圆方程时...

enter image description here

...这将给出两个关于 x 或 y 的讨厌的四次(4 次多项式)方程。 AFAIK 没有通用分析(精确代数)方法来解决它们。您可以尝试一种迭代方法 - 查找 Newton-Raphson 迭代求根算法。

看看这篇关于这个主题的非常好的论文: http://www.spaceroots.org/documents/distance/distance-to-ellipse.pdf

对不起,答案不完整-我完全归咎于数学和自然规律......

编辑:哎呀,我似乎在图表 xD 中有 a 和 b 错误的方式

关于c++ - 给定点到给定椭圆的距离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22959698/

相关文章:

javascript - 在 Javascript 中根据步长分割整数数组

c++ - 关于 Connect 之前我应该​​拥有什么的问题

c++ - Qt moc 失败且没有错误消息

java - 在树莓派上使用OpenCV进行视觉追踪FRC

c++ - 从 HDR 图像中选择亮度(曝光)

c++ - 通过从每一行中选择1个元素来查找2d数组中的最低和

c# - 四舍五入到下一个更高的数字

c++ - 打印指针变量的地址

c# - 在使用 C# protobuf-net 生成的 objective-c 中反序列化 “Serialized Protobuf” 的最佳方法是什么

ios - 从灰色 UIImage 创建灰色 IplImage