У меня есть этот практический проект, который позволяет пользователю рисовать на экране, когда они касаются их пальцами. Очень простое приложение, которое я сделал в качестве упражнения назад. Мой маленький двоюродный брат позволил себе рисовать вещи с помощью моего iPad в этом приложении (детские рисунки: круги, линии и т. Д., Что бы ему ни приходило в голову). Затем он начал рисовать круги, а затем попросил меня сделать его «хорошим кругом» (из моего понимания: сделать нарисованный круг идеально круглым, поскольку мы знаем, насколько бы устойчивыми мы не пытались рисовать что-то пальцем на экране, круг никогда не бывает таким округлым, каким должен быть круг).
Поэтому мой вопрос здесь заключается в том, существует ли какой-либо способ в коде, где мы можем сначала обнаружить линию, нарисованную пользователем, которая образует круг, и создать примерно такой же размер круга, сделав его идеально круглым на экране. Я бы знал, как сделать не очень прямую прямую линию, но что касается круга, я не совсем знаю, как это сделать с помощью кварца или других методов.
Я рассуждаю так: начальная и конечная точки линии должны касаться друг друга или пересекаться после того, как пользователь поднимает палец, чтобы оправдать тот факт, что он действительно пытался нарисовать круг.
Ответы:
Иногда действительно полезно потратить некоторое время на изобретение колеса. Как вы, возможно, уже заметили, существует множество фреймворков, но не так сложно реализовать простое, но полезное решение, не представляя всей этой сложности. (Пожалуйста, не поймите меня неправильно, для каких-либо серьезных целей лучше использовать некоторые зрелые и зарекомендовавшие себя стабильные рамки).
Сначала я представлю свои результаты, а затем объясню простую и понятную идею.
Вы увидите, что в моей реализации нет необходимости анализировать каждую точку и выполнять сложные вычисления. Идея состоит в том, чтобы найти некоторую ценную метаинформацию. Я буду использовать тангенс в качестве примера:
Давайте определим простой и понятный шаблон, типичный для выбранной фигуры:
Так что не так сложно реализовать механизм обнаружения кругов, основанный на этой идее. См. Рабочую демонстрацию ниже (извините, я использую Java как самый быстрый способ предоставить этот быстрый и немного грязный пример):
Это не должно быть проблемой для реализации аналогичного поведения на iOS, так как вам просто нужно несколько событий и координат. Что-то вроде следующего (см. Пример ):
Есть несколько возможных улучшений.
Начать в любой момент
Текущее требование состоит в том, чтобы начать рисовать круг от верхней средней точки из-за следующего упрощения:
Обратите внимание, что используется значение по умолчанию
index
. Простой поиск доступных «частей» фигуры устранит это ограничение. Обратите внимание, что вам нужно использовать круговой буфер для определения полной формы:По часовой стрелке и против часовой стрелки
Для поддержки обоих режимов вам нужно будет использовать кольцевой буфер из предыдущего улучшения и искать в обоих направлениях:
Нарисуйте эллипс
У вас есть все, что вам нужно, уже в
bounds
массиве.Просто используйте эти данные:
Другие жесты (необязательно)
Наконец, вам просто нужно правильно обработать ситуацию, когда
dx
(илиdy
) равен нулю, чтобы поддерживать другие жесты:Обновить
Этому маленькому PoC уделялось достаточно много внимания, поэтому я немного обновил код, чтобы он работал плавно и предоставил некоторые подсказки по рисованию, выделение опорных точек и т. Д.
Вот код:
источник
Классической техникой Computer Vision для определения формы является преобразование Хафа. Одна из приятных особенностей Hough Transform заключается в том, что она очень терпима к частичным данным, несовершенным данным и шумам. Использование Hough для круга: http://en.wikipedia.org/wiki/Hough_transform#Circle_detection_process
Учитывая, что ваш круг нарисован от руки, я думаю, что преобразование Хафа может вам подойти.
Вот «упрощенное» объяснение, я прошу прощения за то, что это не так просто. Во многом это из школьного проекта, который я сделал много лет назад.
Hough Transform - это схема голосования. Выделен двумерный массив целых чисел, и все элементы установлены в ноль. Каждый элемент соответствует одному пикселю в анализируемом изображении. Этот массив называется массивом-накопителем, поскольку каждый элемент будет накапливать информацию, голоса, указывающие на вероятность того, что пиксель может находиться в начале круга или дуги.
Детектор края оператора градиента применяется к изображению, и краевые пиксели или края записываются. Край - это пиксель, который имеет разную интенсивность или цвет по отношению к своим соседям. Степень различия называется величиной градиента. Для каждого ребра достаточной величины применяется схема голосования, которая будет увеличивать элементы массива аккумуляторов. Увеличиваемые элементы (за которые проголосовали) соответствуют возможным источникам окружностей, которые проходят через рассматриваемый край. Желаемый результат состоит в том, что если дуга существует, то истинное происхождение получит больше голосов, чем ложное происхождение.
Обратите внимание, что элементы массива аккумуляторов, которые посещаются для голосования, образуют окружность вокруг рассматриваемого края. Вычисление координат x, y для голосования аналогично вычислению координат x, y круга, который вы рисуете.
На рисованном изображении вы можете использовать заданные (цветные) пиксели напрямую, а не вычислять края.
Теперь с несовершенно расположенными пикселями вы не обязательно получите один элемент массива аккумуляторов с наибольшим количеством голосов. Вы можете получить коллекцию соседних элементов массива с кучей голосов, кластер. Центр тяжести этого скопления может предложить хорошее приближение к началу координат.
Обратите внимание, что вам, возможно, придется запустить преобразование Хафа для различных значений радиуса R. Тот, который производит более плотную группу голосов, - это «лучшее» соответствие.
Существуют различные методы, чтобы уменьшить количество голосов за ложное происхождение. Например, одним из преимуществ использования ребер является то, что они не только имеют величину, но и направление. При голосовании нам нужно только проголосовать за возможное происхождение в соответствующем направлении. Места, получающие голоса, будут образовывать дугу, а не полный круг.
Вот пример. Начнем с круга радиуса один и инициализированного массива аккумуляторов. Поскольку каждый пиксель считается потенциальным источником проголосовали за. Истинное происхождение получает большинство голосов, в данном случае это четыре.
источник
Вот другой способ. Использование UIView touchSbegin, touchesMoved, touchesEnded и добавление точек в массив. Вы делите массив на две половины и проверяете, имеет ли каждая точка в одном массиве примерно такой же диаметр от своего аналога в другом массиве, что и все остальные пары.
Это звучит хорошо? :)
источник
Я не эксперт по распознаванию фигур, но вот как я могу подойти к проблеме.
Во-первых, отображая путь пользователя от руки, тайно собирайте список точек (x, y) вместе со временем. Вы можете получить оба факта из событий перетаскивания, обернуть их в простой объект модели и собрать их в изменяемый массив.
Вы, вероятно, хотите брать образцы довольно часто, скажем, каждые 0,1 секунды. Другой возможностью было бы начать действительно часто, возможно, каждые 0,05 секунды, и посмотреть, как долго пользователь тянет; если они тянутся дольше, чем какое-то время, уменьшите частоту сэмплов (и отбросьте все пропущенные сэмплы) до 0,2 секунд
(И не принимайте мои цифры за Евангелие, потому что я просто вытащил их из своей шляпы. Экспериментируйте и найдите лучшие значения.)
Во-вторых, проанализируйте образцы.
Вы хотите получить два факта. Во-первых, центр фигуры, который (IIRC) должен быть просто средним из всех точек. Во-вторых, средний радиус каждого образца из этого центра.
Если, как догадался @ user1118321, вы хотите поддерживать полигоны, то остальная часть анализа состоит в принятии этого решения: хочет ли пользователь нарисовать круг или многоугольник. Вы можете посмотреть на образцы как на полигон, чтобы начать это определение.
Есть несколько критериев, которые вы можете использовать:
Третий и последний шаг заключается в создании фигуры с центром в предварительно определенной центральной точке с заранее определенным радиусом.
Нет никаких гарантий, что все, что я сказал выше, будет работать или будет эффективно, но я надеюсь, что это, по крайней мере, выведет вас на правильный путь - и, пожалуйста, если кто-то, кто знает больше о распознавании формы, чем я (что является очень низкой планкой), видит это, не стесняйтесь оставить комментарий или свой собственный ответ.
источник
Мне очень повезло с правильно обученным распознавателем за 1 доллар ( http://depts.washington.edu/aimgroup/proj/dollar/ ). Я использовал его для кругов, линий, треугольников и квадратов.
Это было давно, до UIGestureRecognizer, но я думаю, что это должно быть легко создать правильные подклассы UIGestureRecognizer.
источник
Как только вы определили, что пользователь закончил рисовать свою форму, где он начал, вы можете взять образец координат, которые они нарисовали, и попытаться подогнать их к кругу.
Здесь есть решение MATLAB для решения этой проблемы: http://www.mathworks.com.au/matlabcentral/fileexchange/15060-fitcircle-m
Который основан на статье « Подгонка кругов и эллипсов по методу наименьших квадратов » Уолтера Гандера, Джина Х. Голуба и Рольфа Штребеля: http://www.emis.de/journals/BBMS/Bulletin/sup962/gander.pdf
Доктор Ян Купе из Кентерберийского университета, Новая Зеландия опубликовал статью с рефератом:
http://link.springer.com/article/10.1007%2FBF00939613
Файл MATLAB может вычислять как нелинейную задачу TLS, так и линейную задачу LLS.
источник
Вот довольно простой способ использования:
предполагая эту матрицу сетки:
Поместите несколько UIViews в местах «X» и проверьте их на предмет попадания (по порядку). Если их всех ударить последовательно, я думаю, что было бы справедливо позволить пользователю сказать: «Хорошо, вы нарисовали круг»
Звучит хорошо? (и просто)
источник