OpenCV и описание координат фигур - PullRequest
0 голосов
/ 06 августа 2020

Задание:

  • Камера сфокусирована на стене
  • Считывается информация с камеры в реальном времени
  • Фигурки висят на белой стене
  • Необходимо обнаружить фигуры и перенести их на их контуры для дальнейшей обработки

Проблемы:

  • Не могу создать маску, которая не деформирует фигуру:

    Я использовал для создания маски: Cv2.Canny, Cv2.Threshold. Найти параметр сложно, поэтому на каждом изображении я вычисляю меридиан и использую доверительный интервал , который охватывает 66% (если вам интересно, я использовал трекбар, но все равно потребовалось время, чтобы настроить папаметры). Я использовал много способов создать подходящую маску, поэтому у меня есть непристойное количество кода. Поэтому я просто оставлю код для поиска меридиана.

     public static double Median(Mat imgMat)
     {
         double m = (imgMat.Rows * imgMat.Cols) / 2;
         int bin = 0;
         double med = -1.0;
    
         Mat hist = new Mat();
         int[] hdims = { 256 };
         Rangef[] ranges = { new Rangef(0, 256), };
         Cv2.CalcHist(
             new Mat[] { imgMat },
             new int[] { 0 },
             null,
             hist,
             1,
             hdims,
             ranges);
    
         for (int i = 0; i < hdims[0] && med < 0.0; ++i)
         {
             bin += (int)hist.At<float>(i);
    
             if (bin > m && med < 0.0)
             {
                 med = i;
             }
         }
    
         return med;
     }
    
  • Необходимо найти только важные точки формы, поэтому я использую приближение. точки, описывающие фигуры, перемещаются, сам контур фигуры также перемещается (если я использую другой аппроксиматор, то результаты также будут неверными). Мои наблюдения:

    Cv2.ApproxPolyDP - слишком много перемещается
    Cv2.ConvexHull - хорошо описывает всю площадь, занимаемую точками, но плохо описывает форму

public class ConvexHull : IApproxPoints
{
    private double perimeterLimit;

    public ConvexHull(double perimeterLimit)
    {
        this.perimeterLimit = perimeterLimit;
    }
    public Point[][] ApproxPoints(Point[][] points)
    {
        LinkedList<Point[]> vectorApproxPoints = new LinkedList<Point[]>();
        for (int i = 0; i < points.Length; i++)
        {
            double perimeter = Cv2.ArcLength(points[i], true);
            if (perimeter > perimeterLimit)
            {
                Point[] approxPoints = Cv2.ConvexHull(points[i], false);
                vectorApproxPoints.AddLast(approxPoints);
            }
        }
        return vectorApproxPoints.ToArray();
    }
}

Напишите, пожалуйста, любые ваши решения или идеи.

1 Ответ

0 голосов
/ 09 августа 2020

Я решил рассчитать общие элементы на нескольких масках. Так я могу избавиться от шума и ненужных движений при приближении

public class CleanFrame
{
    private Queue<Mat> frames = new Queue<Mat>();
    private int limitOfFrame;

    public CleanFrame(int limitOfFrame = 25)
    {
        this.limitOfFrame = limitOfFrame;
    }

    /// <summary>
    /// put a frame mask in the queue for processing
    /// </summary>
    /// <param name="frame">frame mask</param>
    /// <returns>common elements on all frame masks</returns>
    public Mat PushFrame(Mat frame)
    {
        if (frames.Count == limitOfFrame)
        {
            frames.Dequeue();
        }
        frames.Enqueue(frame);
        return GetCommonElements();
    }

    /// <summary>
    /// processes masks and returns common elements
    /// </summary>
    /// <returns></returns>
    private Mat GetCommonElements()
    {
        Mat result = frames.Peek();

        foreach (var frame in frames)
        {
            Cv2.BitwiseAnd(result,frame,result);
            Cv2.ImShow("result", result);
        }

        return result;
    }
}

но могло быть и лучше

...