문제

는 경우의 주요 축의 타원은 수직 또는 수평,그것은 쉽게 계산하고 경계 상자이지만,무엇 때 타원은 회전나요?

유일한 방법은 나의 생각할 수 있는 그래서 지금까지 계산하는 모든 포인트 주변을 찾을 수 있 max/min x 와 y 값이다.그것은 수 간단한 방법입니다.

이 있는 경우에는 함수(수학적 의미에서)설명하는 타원에서 임의의 각,다음 사용할 수 있는 그 유도체를 찾는 포인트는 기울기가 없거나 정의되지 않지만,나를 찾을 수 없습니다.

편집:을 명확히 하기 위해,필요 축 정렬되어 경계 상자,즉그것은 회전 타원하지만,숙박을 맞추 x 축도록 변환하는 경계 상자에 작동하지 않습니다.

도움이 되었습니까?

해결책

당신이 시도할 수 있었을 사용하여 매개변수화 방정식에 대한 회전 타원에서 임의의 각:

x = h + a*cos(t)*cos(phi) - b*sin(t)*sin(phi)  [1]
y = k + b*sin(t)*cos(phi) + a*cos(t)*sin(phi)  [2]

...는 타원가 센터(h,k)semimajor 축고 semiminor 축 b,고 회전각이 마련되어 있습니다.

할 수 있습니다 다음을 차별화 및 해결을 위해 그=0:

0 = dx/dt = -a*sin(t)*cos(phi) - b*cos(t)*sin(phi)

=>

tan(t) = -b*tan(phi)/a   [3]

을 제공해야 하는 당신은 많은에 대한 솔루션 t(두에 관심이 있다),플러그는 것으로 다시[1]을 얻을 최대 및 최소 x.

반복해[2]:

0 = dy/dt = b*cos(t)*cos(phi) - a*sin(t)*sin(phi)

=>

tan(t) = b*cot(phi)/a  [4]

수도 예를 들어:

을 고려하는 타원서(0,0)에=2,b=1,회전 PI/4:

[1] =>

x = 2*cos(t)*cos(PI/4) - sin(t)*sin(PI/4)

[3] =>

tan(t) = -tan(PI/4)/2 = -1/2

=>

t = -0.4636 + n*PI

우리가 관심에 t=-0.4636t=-3.6052

그래서 우리가 얻을:

x = 2*cos(-0.4636)*cos(PI/4) - sin(-0.4636)*sin(PI/4) = 1.5811

x = 2*cos(-3.6052)*cos(PI/4) - sin(-3.6052)*sin(PI/4) = -1.5811

다른 팁

내가 찾는 간단한 공식에서 http://www.iquilezles.org/www/articles/ellipses/ellipses.htm (고 무시 z 축).

내가 구현한 그것은 대략 다음과 같습니다:

num ux = ellipse.r1 * cos(ellipse.phi);
num uy = ellipse.r1 * sin(ellipse.phi);
num vx = ellipse.r2 * cos(ellipse.phi+PI/2);
num vy = ellipse.r2 * sin(ellipse.phi+PI/2);

num bbox_halfwidth = sqrt(ux*ux + vx*vx);
num bbox_halfheight = sqrt(uy*uy + vy*vy); 

Point bbox_ul_corner = new Point(ellipse.center.x - bbox_halfwidth, 
                                 ellipse.center.y - bbox_halfheight);

Point bbox_br_corner = new Point(ellipse.center.x + bbox_halfwidth, 
                                 ellipse.center.y + bbox_halfheight);

이것은 친척 간단하지만 비트를 설명하기 어렵기 때문하지 않은 우리에게 주신을 나타내는 방식으로 귀하의 타원입니다.그래서 많은 가지 방법으로 할 수..

어쨌든,일반적인 원칙은 다음과 같습니다.당신은 계산할 수 없습 축 정렬 경계 상자의 직접 있습니다.할 수 있습 그러나 계산 극값의 타원형에서의 x,y 에서 지점으로 2D 공간입니다.

이를 위해 그의 충분 방정식 x(t)=ellipse_equation(t)와 y(t)=ellipse_equation(t).첫 번째 순서 유도체의 및 해결을 위해 그것은 그것의 뿌리입니다.를 처리하고 있으므로 타원하는 삼각법을 기반으로 하는직하고 있습니다.당신이해야 끝낼 방정식 중 하나가 얻을 뿌리를 통해 atan,acos 또는 asin.

힌트:을 확인하는 코드 그것을 시도와 함께 회전하지 않은 타원:을 얻어야 한 뿌리에 0,Pi/2,Pi3*Pi/2.

는 각 축(x,y).당신을 얻을 것이 대부분에서 네 개의 뿌리(덜하는 경우 타원은 퇴화,예를 들어,하나의 반경이 zero).Evalulate 위치에 뿌리고 당신은 모든 극단적인 포인트의 타원입니다.

지금 당신은 거의가 있습니다.을 받고 경계 상자의 타원은 간단한 스캔 이러한 네 가지 포인트 xmin,xmax,ymin 및 표준을 사용하여 인터넷을.

Btw-이 있는 경우 문제를 찾는 것의 방정식의 타원:을 줄이기 위해 노력하는 경우 당신은 축 정렬 타원 센터,두 개의 반지름과 회전 각도의 주위에 센터도 있습니다.

그렇게 할 경우 방정식을 사용할 수 있습니다.

  // the ellipse unrotated:
  temp_x (t) = radius.x * cos(t);
  temp_y (t) = radius.y = sin(t);

  // the ellipse with rotation applied:
  x(t) = temp_x(t) * cos(angle) - temp_y(t) * sin(angle) + center.x;
  y(t) = temp_x(t) * sin(angle) + temp_y(t) * cos(angle) + center.y;

Brilian Johan 닐슨.나는 전사 코드는 c#-ellipseAngle 은 지금에도:

private static RectangleF EllipseBoundingBox(int ellipseCenterX, int ellipseCenterY, int ellipseRadiusX, int ellipseRadiusY, double ellipseAngle)
{
    double angle = ellipseAngle * Math.PI / 180;
    double a = ellipseRadiusX * Math.Cos(angle);
    double b = ellipseRadiusY * Math.Sin(angle);
    double c = ellipseRadiusX * Math.Sin(angle);
    double d = ellipseRadiusY * Math.Cos(angle);
    double width = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2)) * 2;
    double height = Math.Sqrt(Math.Pow(c, 2) + Math.Pow(d, 2)) * 2;
    var x= ellipseCenterX - width * 0.5;
    var y= ellipseCenterY + height * 0.5;
    return new Rectangle((int)x, (int)y, (int)width, (int)height);
}

제가 생각하는 가장 유용한 수식이 하나입니다.임 회전 각도에서 피부터의 원산지고 있으로 방정식:

alt text

alt text

치(h,k)이 센터,그리고 b 의 크기는 중요하고 작은 축 t 에 따라 다릅-pi pi.

에서는,당신이 할 수 있어야 파생되는 t dx/dt 또는 dy/dt 간 0.

여기에 대한 공식 경우 타원에 의해 주어진 그 초점과 편심 (경우에는 그에 의해 주어진 축 길이터와 각 참조하십시오 e.g.대답하여 user1789690).

즉는 경우에,초점은(x0,y0)및(x1,y1)과 편심 e,다음

bbox_halfwidth  = sqrt(k2*dx2 + (k2-1)*dy2)/2
bbox_halfheight = sqrt((k2-1)*dx2 + k2*dy2)/2

dx = x1-x0
dy = y1-y0
dx2 = dx*dx
dy2 = dy*dy
k2 = 1.0/(e*e)

나는 파생되는 수식에서 대답하여 user1789690 와 요한 닐슨.

과 함께 작업하는 경우 OpenCV/C++및 사용 cv::fitEllipse(..) 기능,필요할 수 있는 경계 직사각형의 타원입니다.여기에서 내가 만든 솔루션을 사용하여 마이크 대답:

// tau = 2 * pi, see tau manifest
const double TAU = 2 * std::acos(-1);

cv::Rect calcEllipseBoundingBox(const cv::RotatedRect &anEllipse)
{
    if (std::fmod(std::abs(anEllipse.angle), 90.0) <= 0.01) {
        return anEllipse.boundingRect();
    }

    double phi   = anEllipse.angle * TAU / 360;
    double major = anEllipse.size.width  / 2.0;
    double minor = anEllipse.size.height / 2.0;

    if (minor > major) {
        std::swap(minor, major);
        phi += TAU / 4;
    }

    double cosPhi = std::cos(phi), sinPhi = std::sin(phi);
    double tanPhi = sinPhi / cosPhi;

    double tx = std::atan(-minor * tanPhi / major);
    cv::Vec2d eqx{ major * cosPhi, - minor * sinPhi };
    double x1 = eqx.dot({ std::cos(tx),           std::sin(tx)           });
    double x2 = eqx.dot({ std::cos(tx + TAU / 2), std::sin(tx + TAU / 2) });

    double ty = std::atan(minor / (major * tanPhi));
    cv::Vec2d eqy{ major * sinPhi, minor * cosPhi };
    double y1 = eqy.dot({ std::cos(ty),           std::sin(ty)           });
    double y2 = eqy.dot({ std::cos(ty + TAU / 2), std::sin(ty + TAU / 2) });

    cv::Rect_<float> bb{
        cv::Point2f(std::min(x1, x2), std::min(y1, y2)),
        cv::Point2f(std::max(x1, x2), std::max(y1, y2))
    };

    return bb + anEllipse.center;
}

이 코드를 기반으로 코드 user1789690 에 기여했지만,상에서 구현 Delphi.내가 이것을 테스트하고 멀리로 말할 수 있는 완벽하게 작동합니다.나는 하루 종일 보냈을 찾는 알고리즘이나 일부 코드 테스트는 몇 가지 작동하지 않았고,나는 매우 행복했을 마지막으로 코드를 찾을 수 있다.나는 누군가가 발견한 이 유용합니다.이 코드를 계산하고 경계 상자의 회전 타원입니다.경계 상자 축 정렬하지 않을 회전 타원입니다.의 반경이 있는 타원 그 전에 회전되었습니다.

type

  TSingleRect = record
    X:      Single;
    Y:      Single;
    Width:  Single;
    Height: Single;
  end;

function GetBoundingBoxForRotatedEllipse(EllipseCenterX, EllipseCenterY, EllipseRadiusX,  EllipseRadiusY, EllipseAngle: Single): TSingleRect;
var
  a: Single;
  b: Single;
  c: Single;
  d: Single;
begin
  a := EllipseRadiusX * Cos(EllipseAngle);
  b := EllipseRadiusY * Sin(EllipseAngle);
  c := EllipseRadiusX * Sin(EllipseAngle);
  d := EllipseRadiusY * Cos(EllipseAngle);
  Result.Width  := Hypot(a, b) * 2;
  Result.Height := Hypot(c, d) * 2;
  Result.X      := EllipseCenterX - Result.Width * 0.5;
  Result.Y      := EllipseCenterY - Result.Height * 0.5;
end;

이 기능을 찾기 위한 단단한 적합 사각형을 타원형으로 임의의 방향

가 opencv rect 및점 구현에 대한:

cg-센터의 타원

크기,주요 작은 축의 타원

각도 방향의 타원

cv::Rect ellipse_bounding_box(const cv::Point2f &cg, const cv::Size2f &size, const float angle) {

    float a = size.width / 2;
    float b = size.height / 2;
    cv::Point pts[4];

    float phi = angle * (CV_PI / 180);
    float tan_angle = tan(phi);
    float t = atan((-b*tan_angle) / a);
    float x = cg.x + a*cos(t)*cos(phi) - b*sin(t)*sin(phi);
    float y = cg.y + b*sin(t)*cos(phi) + a*cos(t)*sin(phi);
    pts[0] = cv::Point(cvRound(x), cvRound(y));

    t = atan((b*(1 / tan(phi))) / a);
    x = cg.x + a*cos(t)*cos(phi) - b*sin(t)*sin(phi);
    y = cg.y + b*sin(t)*cos(phi) + a*cos(t)*sin(phi);
    pts[1] = cv::Point(cvRound(x), cvRound(y));

    phi += CV_PI;
    tan_angle = tan(phi);
    t = atan((-b*tan_angle) / a);
    x = cg.x + a*cos(t)*cos(phi) - b*sin(t)*sin(phi);
    y = cg.y + b*sin(t)*cos(phi) + a*cos(t)*sin(phi);
    pts[2] = cv::Point(cvRound(x), cvRound(y));

    t = atan((b*(1 / tan(phi))) / a);
    x = cg.x + a*cos(t)*cos(phi) - b*sin(t)*sin(phi);
    y = cg.y + b*sin(t)*cos(phi) + a*cos(t)*sin(phi);
    pts[3] = cv::Point(cvRound(x), cvRound(y));

    long left = 0xfffffff, top = 0xfffffff, right = 0, bottom = 0;
    for (int i = 0; i < 4; i++) {
        left = left < pts[i].x ? left : pts[i].x;
        top = top < pts[i].y ? top : pts[i].y;
        right = right > pts[i].x ? right : pts[i].x;
        bottom = bottom > pts[i].y ? bottom : pts[i].y;
    }
    cv::Rect fit_rect(left, top, (right - left) + 1, (bottom - top) + 1);
    return fit_rect;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top