Сравнение произвольных фигур (кривых)

Программирование на Юнити.

Сравнение произвольных фигур (кривых)

Сообщение Clindatu 27 мар 2018, 00:22

Друзья, привет.
Подскажите, насколько сложно реализовать такую вещь как сравнение произвольных фигур (кривых)?

Суть в чём: хочу мышкой (пальцем, в дальнейшем несколькими пальцами) двигать курсор. Система запоминает траекторию движения (кривую, фигуру) и сверяет с образцом.
Например, повторите рисунок - кружок, треугольник и тд.

Как новичок, я разделил проблему на части:
1. Запись траектории движения курсора. Т.е. запись координат курсора каждый тик.
(Решена. Правда не знаю на сколько правильно. С помощью двух объектов List);
2. Настроить систему так, чтобы вне зависимости от скорости движения количество координат не менялось. Сейчас, если быстро провести, например, прямую, то допустим получится 10 точек. А если эту же прямую провести медленно, то и все 100 точек получится;
3. Найти алгоритм сравнения двух кривых/фигур, нарисованную пользователем с образцами.

В разделах алгебры, что-то есть похожее, но это для точного соответствия, а как реализовать похожесть? То ли каждую точку сравнивать, то ли отрезками, то ли ещё как, плюс учитывая коэффициент отклонения/погрешности/похожести.

Ниже код скрипта. Удалось пока только записывать координаты и после отпускания мышки система повторяет траекторию. Со спецэффектами)
Пример работы на текущем этапе.
[youtube]https://youtu.be/YU_zjFdPeg8[/youtube]

Синтаксис:
Используется csharp
// СХЕМА:
//1. Зажимаем мышку и двигаем курсором. Система записывает траекторию движения курсором.
//2. Отпускаем мышку. Система повторяет траекторию движения курсором.
//+ за курсором передвигается и объекты ТрайлРендерер (спецэффекты)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class Swipe : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
        // Переменные для вывода текста на экран
    public Text TextX;
    public Text TextY;

    // Переменные для хранения координат курсора мыши, т.е. запись траектории движения мыши после зажатия ЛКМ
    List<float> listX = new List<float>();
    List<float> listY = new List<float>();

    public GameObject MouseFollow;
    private GameObject inst_MyGO1;
    private GameObject inst_MyGO2;

    bool GoMove = false; // хранится флаг запуска повтора движения курсора
    int i = -1;
    public float distanceFromCamera = 5.0f;

    private void OnMouseDown()
    {
        // ПРИ НАЖАТИИ НА МЫШЬ

        if (GoMove)
        { }
        else
        {
                // Повтор движения курсора мыши выключен

                // Получим координату курсора
            Vector3 mousePosition = Input.mousePosition;
            // Координаты по z устанавливаем как расстояние до камеры (хз зачем, но работает)
            mousePosition.z = distanceFromCamera;
            // Преобразуем одни координаты курсора в другие (хз зачем, но работает)
            Vector3 mouseScreenToWorld = Camera.main.ScreenToWorldPoint(mousePosition);

            // Уничтожим объект существующий ТрайлРендерер, иначе будут клонироваться до бесконечности
            Destroy(inst_MyGO2);
            // Добавим новый ТрайлРендерер
            inst_MyGO1 = Instantiate(MouseFollow, mouseScreenToWorld, Quaternion.identity) as GameObject;

            GoMove = false;

            //Выведем текущие координаты курсора на экран
            TextX.text = "X: " + mouseScreenToWorld.x + " - Начало";
            TextY.text = "Y: " + mouseScreenToWorld.y + " - Начало";

            // Добавим текущую координату в список
            listX.Add(mouseScreenToWorld.x);
            listY.Add(mouseScreenToWorld.y);
        }
         
    }

    public void OnDrag(PointerEventData eventData)
    {
        //ДВИЖЕНИЕ МЫШИ ПРОДОЛЖАЕТСЯ

        // Получаем координаты курсора мыши
        Vector3 mousePosition = Input.mousePosition;
        // Координаты по z устанавливаем как расстояние до камеры (хз зачем, но работает)
        mousePosition.z = distanceFromCamera;
        // Преобразуем одни координаты курсора в другие (хз зачем, но работает)
        Vector3 mouseScreenToWorld = Camera.main.ScreenToWorldPoint(mousePosition);

        //Выведем текущие координаты курсора на экран
        TextX.text = "X: " + mouseScreenToWorld.x;
        TextY.text = "Y: " + mouseScreenToWorld.y;

        // Добавим текущую координату в список
        listX.Add(mouseScreenToWorld.x);
        listY.Add(mouseScreenToWorld.y);

        // Передвигаем объект ТрайРендерер (спецэффекты) туда где курсор мыши, т.е. следуем за мышью
        inst_MyGO1.transform.position = new Vector3(mouseScreenToWorld.x, mouseScreenToWorld.y, distanceFromCamera);

    }

    public void OnEndDrag(PointerEventData eventData)
    {
        // ПРИ ОТПУСКАНИИ МЫШКИ
        if (GoMove)
        {
        }
        else
        {
                // Повтор движения курсора мыши выключен

                // Получаем координаты курсора мыши
            Vector3 mousePosition = Input.mousePosition;
            // Координаты по z устанавливаем как расстояние до камеры (хз зачем, но работает)
            mousePosition.z = distanceFromCamera;
            // Преобразуем одни координаты курсора в другие (хз зачем, но работает)
            Vector3 mouseScreenToWorld = Camera.main.ScreenToWorldPoint(mousePosition);

            //Выведем текущие координаты курсора на экран
            TextX.text = "X: " + mouseScreenToWorld.x + " - Конец";
            TextY.text = "Y: " + mouseScreenToWorld.y + " - Конец";

            // Запускаем повтор движения курсора
            GoMove = true;

            //Уничтожаем объект ТрайлРендерер (спецэффекты), который следовал за курсором пользователя
            Destroy(inst_MyGO1);

            // СОздаём новый объект ТрайлРендерер (спецэффекты), который будет следовать за курсором повтора
            inst_MyGO2 = Instantiate(MouseFollow, new Vector3(listX[0], listY[0], distanceFromCamera), Quaternion.identity) as GameObject;
        }
    }

    void Start()
    {
    }

    void Update()
    {
        // КАЖДЫЙ КАДР

        if (GoMove)
        {
                // ПОВТОР ДВИЖЕНИЯ КУРСОРА ВКЛЮЧЁН, т.е. сейчас система сама повторяет траекторию движения курсора
                // Увеличиваем счётчик
            i++;
            if (i < listX.Count)
            {
                // Текущий номер списка меньше, чем количество в списке координат
                //Переместим объект ТрайлРендерер в следующую координату
                inst_MyGO2.transform.position = new Vector3(listX[i], listY[i], distanceFromCamera);
            }
            else
            {
                //Все координаты пройдены, очистим списки координат и установим переменные в исходное положение
                listX.Clear();
                listY.Clear();
                i = -1;
                GoMove = false;
            }

        }
    }

}
 
Clindatu
UNец
 
Сообщения: 4
Зарегистрирован: 26 мар 2018, 23:45

Re: Сравнение произвольных фигур (кривых)

Сообщение 1max1 27 мар 2018, 02:35

Читайте про распознавание образов, это не так просто как кажется, конечно можно пойти самыми примитивными вариантами например, сделать заранее много шаблонов, а потом по ним сравнивать те же координаты к примеру, если (pos[0] / posTemplate[0] > 0.9) && (pos[0] / posTemplate[0] < 1.1), считаем, что координата совпала, если совпало 90% координат - фигура такая-то, но думаю багов буде-е-е-т, ммм))
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Сравнение произвольных фигур (кривых)

Сообщение Bill Gates 27 мар 2018, 08:48

1. Нормализуйте кривые по длине.
2. Каждой точке эталона сопоставьте точку нарисованной фигуры.
3. Представляте контур в виде массива центромассных расстояний.
4. Дальше используйте что-то вроде коэффициента корреляции Пирсона или придумайте свое.
5. ?????
6. PROFIT!!!

Вообще, конечно, не получится решить данную задачу на должном уровне при таком простом подходе.
Bill Gates
UNIт
 
Сообщения: 127
Зарегистрирован: 16 июл 2015, 11:27

Re: Сравнение произвольных фигур (кривых)

Сообщение artk 28 мар 2018, 16:55

готовых решений много. И знаю что есть очень простые алгоритмы для такого распознования, без использования нейронок.
https://assetstore.unity.com/packages/t ... izer-86410
Аватара пользователя
artk
Старожил
 
Сообщения: 749
Зарегистрирован: 22 май 2011, 12:22

Re: Сравнение произвольных фигур (кривых)

Сообщение Clindatu 29 мар 2018, 22:13

Спасибо, ребят. Эх, я думал, в Юнити уже есть стандартный механизм какой-то.
Скорее всего откажусь пока от идеи, т.к. я только начал изучать Юнити, к тому же только как хобби.
Или буду изобретать колхозный велосипед.
Clindatu
UNец
 
Сообщения: 4
Зарегистрирован: 26 мар 2018, 23:45

Re: Сравнение произвольных фигур (кривых)

Сообщение Clindatu 29 мар 2018, 22:16

artk писал(а):готовых решений много. И знаю что есть очень простые алгоритмы для такого распознования, без использования нейронок.
https://assetstore.unity.com/packages/t ... izer-86410


Спасибо за подсказку.
Но платные решения меня пока не интересуют, т.к., во-первых, я новичёк в Юнити и C#, а во-вторых, это просто хобби.
Clindatu
UNец
 
Сообщения: 4
Зарегистрирован: 26 мар 2018, 23:45

Re: Сравнение произвольных фигур (кривых)

Сообщение Clindatu 29 мар 2018, 22:18

Bill Gates писал(а):1. Нормализуйте кривые по длине.
2. Каждой точке эталона сопоставьте точку нарисованной фигуры.
3. Представляте контур в виде массива центромассных расстояний.
4. Дальше используйте что-то вроде коэффициента корреляции Пирсона или придумайте свое.
5. ?????
6. PROFIT!!!

Вообще, конечно, не получится решить данную задачу на должном уровне при таком простом подходе.


Буду пока решать проблему нормализовать кривые. И скорее всего буду просто ограничивать минимальное расстояние от предыдущей точки для фиксации новой точки.
А в Юнити нету типовой настройки шага движения курсором?
Clindatu
UNец
 
Сообщения: 4
Зарегистрирован: 26 мар 2018, 23:45

Re: Сравнение произвольных фигур (кривых)

Сообщение юnity 30 мар 2018, 11:37

Можно проверять позицию курсора, например:
Синтаксис:
Используется csharp
if(Input.GetMouseButton(0))Debug.Log(Input.mousePosition);
Give exact coordinates of the decision of the problems
Аватара пользователя
юnity
UNITрон
 
Сообщения: 290
Зарегистрирован: 21 июл 2015, 18:30

Re: Сравнение произвольных фигур (кривых)

Сообщение vovihro 01 апр 2018, 21:42

Делать проще, опираться на особенности фигур. Смотрим количество и качество линий, пересечений, углов, удаленность от центра фигуры, симметричность. Нужно распознать крестик? 2 линии с одним пересечением, квадрат - 4 линии с 4 прямыми углами, круг - замкнутая линия без углов. Когда линия рисуется смотреть нахождение точек на одной прямой, из таких прямых строить фигуры и соответственно считать углы и стороны.
vovihro
UNец
 
Сообщения: 1
Зарегистрирован: 01 апр 2018, 21:34


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15