Как обвести объект по контуру?

617
31 января 2017, 19:50

Добрый день. У меня есть массив с координатами контура объекта, координаты в массиве в рандомном порядке. Нужно упорядочить элементы в таком порядке, что бы при соединении точек получился замкнутый контур (не прерывная линия). Подскажите как это можно реализовать, или в каком направлении двигаться? Нахожу контур объекта следующим образом

 //FIND LEFT EDGE OF COLOR AREA
            int LFillLoc = x; //the location to check/fill on the left
            while (true)
            {
                PixelsChecked[LFillLoc, y] = true;
                LFillLoc--;                    //de-increment counter
                bool ret = CheckPixel(LFillLoc, y, imgBrush, startcolor);
                if (LFillLoc <= 0 || !ret || (PixelsChecked[LFillLoc, y]))
                    break;               //exit loop if we're at edge of bitmap or color area
            }
            LFillLoc ++;
            //FIND RIGHT EDGE OF COLOR AREA
            int RFillLoc = x; //the location to check/fill on the left
            while (true)
            {
                PixelsChecked[RFillLoc, y] = true;
                RFillLoc++;          //increment counter
                bool ret = CheckPixel(RFillLoc, y, imgBrush, startcolor);
                if (RFillLoc >= bmpsize.Width || !ret || (PixelsChecked[RFillLoc, y]))
                    break;           //exit loop if we're at edge of bitmap or color area
            }
            RFillLoc --;

            //START THE LOOP UPWARDS AND DOWNWARDS
            //ptr = (int)bmpsize.Width * (y1) + x;
            for (int i = LFillLoc; i <= RFillLoc; ++i)
            {
                //START LOOP UPWARDS
                //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
                if (y > 0 && CheckPixel(i, y - 1, imgBrush, startcolor) && !PixelsChecked[i, y - 1])
                    LinearFloodFill4(i, y - 1, bmpsize, startcolor, imgBrush);
                //START LOOP DOWNWARDS
                if (y < (bmpsize.Height - 1) && CheckPixel(i, y + 1, imgBrush, startcolor) && !PixelsChecked[i, y + 1])
                    LinearFloodFill4(i, y + 1, bmpsize, startcolor, imgBrush);
            }    
    bool CheckPixel(int x, int y, Color[] imgBrush, Color original)
    {
        int index = (int)imagerender.Size.Width * (y) + x;
        bool ret = true;
        if (30 * Math.Pow((imgBrush[index].R - original.R), 2) + 59 * Math.Pow((imgBrush[index].G - original.G), 2) + 11 * Math.Pow((imgBrush[index].B - original.B), 2) > sl)
        {
            position.Add(index); // координата контура
            ret = false;
        }
        return ret;
    }

Инструмент "Волшебная палочка" в Photoshop.

Answer 1

Если по данному набору случайно перемешанных N вершин надо построить произвольный простой N-угольник, то одно из элементарных решений задачи - это просто выбрать произвольную вершину многоугольника в качестве "центра" (вершина O), а затем выполнить радиальное заметание плоскости лучом выходящим из вершины O - как лучом радара. (Допустим, заметание выполняется в диапазоне углов [0, 360) против часовой стрелки, хотя направление и стартовый угол роли не играют.)

Первая обнаруженная нашим "лучом радара" вершина соединяется с точкой O, а остальные - с предыдущей обнаруженной вершиной. Последняя обнаруженная вершина соединяется с точкой O, тем самым замыкая многоугольник.

Если на каком-то луче радара окажется сразу несколько вершин, то их можно добавлять в порядке удаления от O или приближения к O. При этом небольшая тонкость заключается в том, что на самом первом луче нужно всегда добавлять точки в порядке удаления от О, а на самом последнем - в порядке приближения к O.

Такой алгоритм построит многоугольник особого класса - звездообразный (звёздчатый?) многоугольник. Внутри или на границе звездообразного многоугольника найдется точка (точки), из которой просматривается вся внутренность многоугольника.

Answer 2

Если вы занимаетесь по сути обработкой изображений (а иначе откуда взялась такая задача?), имеет смысл не строить велосипед, а воспользоваться готовым и уже «взрослым» фреймворком OpenCV. В нём есть готовая функциональность нахождения контуров объектов.

Единственная сложность: OpenCV — нативный фреймворк, так что вам понадобится либо собственный wrapper на C++/CLI, либо можно воспользоваться готовым Emgu CV.

READ ALSO
Выполнение операций по расписанию

Выполнение операций по расписанию

Необходимо проводить определенные действия по расписанию, абстрактный пример:

542
Передача параметров в PartialView

Передача параметров в PartialView

Как передать строго типизированный параметр из контроллера в PartialView, при условии что вызов одного и того же PartialView происходит из разных функций...

400
Как заблокировать клавишу в Unity?

Как заблокировать клавишу в Unity?

В моей игре есть пауза, которая вызывается клавишей "Esc"

557
Создание чекбокса для проверки webBrowser (c#)

Создание чекбокса для проверки webBrowser (c#)

Хочу сделать чекбокс, который будет проверять, открыта ли форма webBrowser(те

387