Python 计算两个旋转椭圆的交点/并集?

Python 计算两个旋转椭圆的交点/并集?,python,opencv,geometry,object-detection,Python,Opencv,Geometry,Object Detection,我在SE和其他地方看到了很多关于计算两个矩形的交集和并集的帖子,但是我有两个任意的椭圆:旋转的,平移的,不同的半长轴和半短轴 有没有人建议计算它们在并集值上的交集 我正在使用OpenCV和Python 如果我/我们不能想出任何聪明和快速的方法,那么我将使用一种基于掩码的方法,我只定义一个零数组,在第一个椭圆定义的区域上用1填充它,在第二个椭圆上加1,然后我将知道并集在数组非零的任何地方,交点将位于数组为2的任何位置。但这听起来有点慢 编辑:Re。“听起来有点慢”:如中所述,我想每秒计算这个“千分

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

有没有人建议计算它们在并集值上的交集

我正在使用OpenCV和Python

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


编辑:Re。“听起来有点慢”:如中所述,我想每秒计算这个“千分之一秒”,所以我更喜欢用解析方程来计算(例如,像非旋转矩形),而不仅仅是基于像素的掩模实现

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

然后你们可以只在方程满足的情况下给像素上色。下面我附上C++示例(我应该很容易将它转换成Python):

bool-ifInEllipse(cv::Size\u轴、浮动角度、cv::Point\u中心、cv::Point\u点)
{
_角度=CV_PI/180*_角度;
浮动余弦=余弦(_角);
浮动正弦=正弦(_角);
float res1=(_point.x-_center.x)*余弦+(_point.y-_center.y)*正弦;
res1=res1*res1;
float res2=(_point.x-_center.x)*正弦-(_point.y-_center.y)*余弦;
res2=res2*res2;
浮动a=_轴宽度;
浮动b=_轴高度;
返回((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;
            }
        }
    }
}
cv::材料A1、A2、B1、B2、AA、BB;
A1=cv::Mat::零(500500,cv_8UC1);
A2=cv::Mat::零(500500,cv_8UC1);
cv::点中心1(200200);
cv::尺寸axes1(100,50);
浮动角度1=30;
cv::椭圆(A1,中心1,轴1,角度1,0,360,cv::标量(255255),-1);
B1=cv::Mat::零(500500,cv_8UC1);
B2=cv::Mat::零(500500,cv_8UC1);

对于(int i=0;我真的不明白你怎么能比你的计划做得更快。我唯一能想到的是,你不需要在整个图像上计算遮罩,而只需要在椭圆绑定的矩形中计算遮罩……我会使用布尔遮罩/逻辑,而不是使用0,1,2值。你可能应该使用这种方法,但如果你愿意的话您可以重载
运算符,这样您就可以使用
&
@0TTT0
&
运算符,这两种运算符已经适用于布尔掩码了……只考虑两个椭圆的边界矩形区域(甚至可能只考虑它们的并集/交集)@JulienMy ellipse类中的一个好主意是用椭圆的边界框表示椭圆。椭圆的并集和交点本身不是椭圆,因此不能表示为椭圆。像素/坐标的掩码是一个更好的主意。
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;
            }
        }
    }
}