Ориентация несимметричной формы в Emgu или OpenCv

Я пытаюсь получить ориентацию формы (двоичной или контурной). Форма в основном прямоугольная, но с большим отверстием на одной стороне. Я хочу, чтобы моя ориентация соответствовала этой асимметрии в объекте.

Я просматривал несколько статей, в которых для этого используются пространственные и центральные моменты. Например. Ориентация двоичного изображения, но кажется, что ориентация, которую я получаю при этом, иногда отличается от кратной 90 градусам .

В следующем документе говорится о некоторой двусмысленности: http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf

Если я реализую это с помощью

private void GetCenterAndOrientationViaMoments(Contour<Point> cont, Size imageSize)
{
    // obtain the orientation of the found object
    // first draw the binary blob in a separate image 
    // I do this for the hole(s) in the image, but I'm not sure if it is needed. 
    // Possibly I can tak the moments directly from the contour
    Image<Gray, byte> instanceImage = new Image<Gray, byte>(imageSize);
    instanceImage.FillConvexPoly(cont.ToArray(), new Gray(255));
    for (Contour<Point> hole = cont.VNext;
        hole != null;
        hole = hole.HNext)
            instanceImage.FillConvexPoly(hole.ToArray(), new Gray(0));

    // calculate the moments
    MCvMoments m = instanceImage.GetMoments(true);
//  MCvMoments m = cont.GetMoments();

    double m00 = m.GetSpatialMoment(0, 0);
    double m10 = m.GetSpatialMoment(1, 0);
    double m01 = m.GetSpatialMoment(0, 1);

    double mu11 = m.GetCentralMoment(1, 1);
    double mu20 = m.GetCentralMoment(2, 0);
    double mu02 = m.GetCentralMoment(0, 2);

    // calculate the center
    PointF center = new PointF((float)(m10 / m00), (float)(m01 / m00));

    // calculate the orientation
    // http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf
    double theta = 0;
    double mu20_mu02 = (mu20 - mu02);
    if ((mu20_mu02 == 0) & (mu11 == 0))
        theta = 0;
    else if ((mu20_mu02 == 0) & (mu11 > 0))
        theta = Math.PI / 4;
    else if ((mu20_mu02 == 0) & (mu11 < 0))
        theta = -Math.PI / 4;
    else if ((mu20_mu02 > 0) & (mu11 == 0))
        theta = 0;
    else if ((mu20_mu02 < 0) & (mu11 == 0))
        theta = -Math.PI / 2;
    else if ((mu20_mu02 > 0) & (mu11 > 0))
        theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02);
    else if ((mu20_mu02 > 0) & (mu11 < 0))
        theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02);
    else if ((mu20_mu02 < 0) & (mu11 > 0))
        theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) + Math.PI / 2;
    else if ((mu20_mu02 < 0) & (mu11 < 0))
        theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) - Math.PI / 2;

#if DEBUG
    int radius = 25;
    instanceImage.Draw(new CircleF(center, radius), new Gray(100), 2);
    instanceImage.Draw(
        new LineSegment2DF(
            center, 
            new PointF(
                (float)(center.X + radius * Math.Cos(theta)), 
                (float)(center.Y + radius * Math.Sin(theta)))), 
        new Gray(100), 
        2);
    ImageViewer.Show(instanceImage, string.Format("Center and orientation"));
#endif
}

Моя ориентация правильная, но не всегда указывает на один и тот же конец объекта. Другими словами, иногда я разворачиваюсь на 180 градусов.

Я предполагаю, что метод не может предоставить именно то, что я хочу, потому что он использует ковариацию распределения (http://en.wikipedia.org/wiki/Image_moments#Examples_2), который дает, не учитывает асимметрию, вызванную отверстием, я прав?

Есть ли способ разрешить двусмысленность на 180 градусов?

С уважением, Том


person Goosebumps    schedule 05.06.2013    source источник