【问题标题】:Compute intersection / union of two rotated ellipses?计算两个旋转椭圆的交集/并集?
【发布时间】:2018-03-20 05:40:50
【问题描述】:

我在 SE 和其他地方看到了许多关于计算两个矩形的交集和并集的帖子,但我有两个任意椭圆:旋转、平移、不同的长半轴和短半轴。

有人对计算他们的交集比联合值有什么建议吗?

我正在使用 OpenCV 和 Python,物有所值。

如果我/我们不能想出任何聪明而快速的方法,那么我将使用基于掩码的方法,我只需定义一个零数组,在第一个椭圆定义的区域上用 1 填充它, 并为第二个椭圆添加 1,然后我会知道联合在数组非零的任何地方,交集将在数组为 2 的地方。但这听起来有点慢。

编辑:回复。 “听起来有点慢”:例如,我想评估每秒“数万亿次”的次数,所以我更喜欢用解析方程来计算这个(例如,就像非旋转矩形一样),而不仅仅是基于像素的掩码实现。

【问题讨论】:

  • 我真的不明白你怎么能比你的计划做得更快。我唯一能想到的是,您不需要在整个图像上计算掩码,而只需在椭圆绑定的矩形中计算掩码……而且我会使用布尔掩码/逻辑而不是使用 0, 1,2 个值。
  • 您可能应该使用该方法,但如果您愿意,可以重载 __and____or__ 运算符,以便使用 &|
  • @0TTT0 &| 已经适用于布尔掩码...
  • 只考虑两个椭圆的边界矩形区域(甚至可能只考虑它们的联合/交集)是@Julien 的一个好主意
  • 我的 ellipse 类表示带有边界框的椭圆。椭圆的并集和交集本身不是椭圆,因此不能表示为椭圆。像素/坐标的掩码会是一个更好的主意。

标签: python opencv geometry object-detection


【解决方案1】:

如果你不想做额外的掩码,你必须在椭圆中实现布尔函数(使用一般椭圆方程):

https://math.stackexchange.com/a/434482/

只有当方程满足时,你才能为像素着色。下面我附上了c++示例(我应该很容易将其转换为python):

bool ifInEllipse(cv::Size _axes, float _angle, cv::Point _center, cv::Point _point)
{

_angle =CV_PI/180*_angle;


float cosine = cos(_angle);
float sine = sin(_angle);


float res1 = (_point.x - _center.x)*cosine + (_point.y - _center.y)*sine;
res1 = res1*res1;
float res2 = (_point.x - _center.x)*sine - (_point.y - _center.y)*cosine;
res2 = res2*res2;

float a = _axes.width;
float b = _axes.height;
return ((res1 / (a*a)) + (res2 / (b*b))) < 1;
}

以及示例用法:

cv::Mat A1,A2, B1,B2, AA,BB;
A1 = cv::Mat::zeros(500, 500, CV_8UC1);
A2 = cv::Mat::zeros(500, 500, CV_8UC1);

cv::Point center1(200, 200);
cv::Size axes1(100, 50);
float angle1 =30;

cv::ellipse(A1, center1, axes1, angle1, 0, 360,cv::Scalar(255,255,255),-1);


B1 = cv::Mat::zeros(500, 500, CV_8UC1);
B2 = cv::Mat::zeros(500, 500, CV_8UC1);
for(int i=0;i<500;i++)
{
    for(int j=0;j<500;j++)
    {
        if(ifInEllipse(axes1,angle1,center1,cv::Point(i,j)))
        {
            B1.at<uchar>(j, i) = 255;
        }
    }
}

cv::Point center2(350, 300);
cv::Size axes2(60, 120);
float angle2 = -45; 


cv::ellipse(A2, center2, axes2, angle2, 0, 360, cv::Scalar(255, 255, 255), -1);


B2 = cv::Mat::zeros(500, 500, CV_8UC1);
for (int i = 0; i<500; i++)
{
    for (int j = 0; j<500; j++)
    {
        if (ifInEllipse(axes2, angle2, center2, cv::Point(i, j)))
        {
            B2.at<uchar>(j, i) = 255;
        }
    }
}


AA = cv::Mat::zeros(500, 500, CV_8UC1);
BB = cv::Mat::zeros(500, 500, CV_8UC1);

cv::bitwise_and(A1, A2,AA);



for (int i = 0; i<500; i++)
{
    for (int j = 0; j<500; j++)
    {
        if (ifInEllipse(axes1, angle1, center1, cv::Point(i, j)))
        {
            if (ifInEllipse(axes2, angle2, center2, cv::Point(i, j)))
            {
                BB.at<uchar>(j, i) = 255;
            }
        }
    }
}

结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    相关资源
    最近更新 更多