Кошачье пианино - CatPiano

искусственный интеллект задняя часть компьютерное зрение
Кошачье пианино - CatPiano

Соси кошек вместе с кодом! Эта статья участвует【Эссе "Мяу Звезды"】

src=http___5b0988e595225.cdn.sohucs.com_q_70,c_zoom,w_640_images_20191108_aa75477c7c5144108a70a1c7a7e22f49.gif&refer=http___5b0988e595225.cdn.sohucs.gif

Введение

Я видел много видео в Интернете, где офицеры, разгребающие дерьмо, посылают своих кошек, играющих на пианино. Хотя в нашей семье есть знатный владелец кота, но из-за отсутствия фортепиано он не может проявить свой художественный талант.

image.png

Как квалифицированный сгребатель дерьма, никто не может огорчить своего владельца кота, и он должен найти способ создать условия без условий. Поэтому мы решили сделать «электронное» пианино для нашего владельца кошки, чтобы владелец кошки мог полностью осуществить свою музыкальную мечту.

Хоть и говорят, что это "электронное" пианино, но из-за ограниченного времени (чтобы заработать консервированные деньги для хозяина кота) нет возможности купить механические детали для изготовления клавиатуры, поэтому я планирую сделать "нищенское версия», чтобы дать владельцу кота целый «виртуальный» ключ.

Кроме того, все мы знаем, что самых больших препятствий в обучении игре на фортепиано на самом деле всего два — левая рука и правая рука. Так что мы собираемся сделать что-то другое - играть на пианино головой.

Поэтому мы решили сделать один для владельца кота"Кошачья голова фортепиано", используйте камеру, чтобы зафиксировать положение головы кошки, разные положения соответствуют разным клавишам и производят разные звуки. Таким образом решается проблема временных и денежных затрат, а во-вторых, это не дает котовладельцу научиться выходить из себя на нас, а также позволяет котовладельцу в полной мере насладиться радостью музыки, убив трех зайцев. одним камнем Разве это не красиво.

(Мастер Кот: Так вы обманываете труд и капитал?)

image.png

общий дизайн

Чтобы реализовать пианино с кошачьей головой, необходимо решить три проблемы:

  • Как снять на видео хозяина кота
  • Как определить положение головы кошки
  • Как играть на пианино и как показывать

Первый – это съемка видео. Первоначально я купил дешевую USB-камеру на Double Eleven, но она еще не пришла из-за медленной доставки. Таким образом, вы можете использовать мобильный телефон только для записи видео, чтобы имитировать камеру, чтобы сначала захватить изображение.

Обнаружение кошачьих голов — самая сложная часть, и я планирую использовать для этого глубокое обучение. Прежде всего, вам нужно собрать несколько фотографий владельца кошки и использовать инструмент аннотации, чтобы отметить голову кошки. Затем используйте модель YOLOV5 с открытым исходным кодом Megvii для ее обучения. Наконец, исходный код openppl, недавно открытый SenseTime, используется для развертывания вывода модели.

Что касается того, как играть на пианино, я планирую использовать для этого Мингуса. Обработка видео и часть графического интерфейса выполняются с помощью OpenCV.

Получение изображения и аннотация

Хорошо использовать мобильный телефон для получения изображения, но сложность заключается в том, как заставить владельца кошки послушно сотрудничать.

Здесь я пожертвовал артефактом - кефиром, несколько раз протаскал хозяина кота по дому и наконец подобрал несколько подходящих роликов

(Cat Master: Дедушка такой милый, не напои дедушку)

image.png

Когда видео было собрано, на компьютере с Windows под рукой не было установленного OpenCV, поэтому я нашел сайт для конвертации видео в картинку:Woohoo.IMG2go.com/convert-to-…, конечно, это также можно сделать с помощью OpenCV VideoCapture

После преобразования его в изображение я использовал инструмент для аннотаций, найденный на github:GitHub.com/Тайзу Таллинн/Ла…

  • Как мы все знаем, кошки — это жидкости, поэтому маркировка тела кошки не способствует обнаружению, поэтому я, наконец, решил пометить голову кошки.
  • Поскольку фон простой, а задача одна, обнаружение кошачьей головы можно выполнить, пометив небольшое количество изображений.
  • При маркировке необходимо обращать внимание на формат этикетки.Обязательно используйте для маркировки шаблон, который может распознать модель YOLOV5.

Наконец, мы аннотировали 430 изображений, число обучающих, проверочных и тестовых наборов: 400, 20, 10.

Обучение модели YOLOV5

обучение модели

Сначала клонируйте исходный код YOLOV5 с github:GitHub.com/ultra Еще одна ICS…

В процессе обучения не было внесено слишком много изменений в код, а напрямую использовался обучающий скрипт в репозитории.train.py

python .\train.py --data .\data\cat.yaml --weights .\weights\yolov5s.pt --img 160 --epochs 3000

Чтобы увеличить скорость обучения, размер изображения может быть соответственно уменьшен. Размер изображения, используемый в этом эксперименте, составляет (160, 160)

Тестирование модели

После обучения модели используйте немаркированные изображения, чтобы убедиться, что модель обучена правильно. Тестовый скрипт также относится к YOLOv5.decect.py

предварительная модельтренироватьсявизуализация

train_batch0.jpg

предварительная модельпроверятьвизуализация

val_batch0_pred.jpg

Способна правильно определить владельца кота, модель без проблем обучается

Экспорт модели

Чтобы лучше адаптироваться к развертыванию, мы преобразуем модель PyTorch вONNXМодель. Преобразование модели также может напрямую использовать сценарий преобразования YOLOv5.export.py

Развертывание логического вывода

Установка платформы вывода

Среда развертывания выбрала платформу SenseTime.openppl, может эффективно работать на архитектуре x86/CUDA и имеет интерфейс Python, с помощью которого можно легко создавать и развертывать проекты:GitHub.com/open PP out — универсальный...

Скачайте и скомпилируйте openppl:

git clone https://github.com/openppl-public/ppl.nn.git
cd ppl.nn
./build.sh -DHPCC_USE_X86_64=ON -DHPCC_USE_OPENMP=ON -DPPLNN_ENABLE_PYTHON_API=ON

После компиляции в./pplnn-build/install/libбудет сгенерирован по путиpypplпакет, наборPYTHONPATHОн готов к использованию после

Вывод модели

Следуйте примеру Python в репозитории., я написал ModelRunner для запуска сетевого вывода для заданного ввода:

def RegisterEngines():
    engines = []

    # create x86 engine
    x86_options = pplnn.X86EngineOptions()
    x86_engine = pplnn.X86EngineFactory.Create(x86_options)

    engines.append(pplnn.Engine(x86_engine))
    return engines

class ModelRunner(object):
    def __init__(self, model_path):
        self.__initialize(model_path)
    
    def __initialize(self, model_path):
        # register engines
        engines = RegisterEngines()
        if len(engines) == 0:
            raise Exception('failed to register engines')

        # create runtime builder
        runtime_builder = pplnn.OnnxRuntimeBuilderFactory.CreateFromFile(model_path, engines)
        if not runtime_builder:
            raise Exception('failed to create runtime builder from file: %s' % (model_path))

        # create runtime
        self.runtime = runtime_builder.CreateRuntime()
        if not self.runtime:
            raise Exception('failed to create runtime')
    
    def get_input_tensor_shape(self):
        return self.runtime.GetInputTensor(0).GetShape().GetDims()
    
    def forward(self, input):
        if not self.runtime:
            raise Exception('runtime not created')
        
        # get input tensor info
        tensor = self.runtime.GetInputTensor(0)
        shape = tensor.GetShape()
        np_data_type = g_pplnntype2numpytype[shape.GetDataType()]
        dims = shape.GetDims()

        # feed input data
        input = np.ascontiguousarray(input) # use contiguousarray to avoid calc error
        status = tensor.ConvertFromHost(input)
        if status != pplcommon.RC_SUCCESS:
            raise Exception('failed to set input data')
        
        # start to inference
        status = self.runtime.Run()
        if status != pplcommon.RC_SUCCESS:
            raise Exception('failed to run')
        
        # wait for inference finished
        status = self.runtime.Sync()
        if status != pplcommon.RC_SUCCESS:
            raise Exception('failed to sync')
        
        # get output data
        out_datas = {}
        for i in range(self.runtime.GetOutputCount()):
            # get output tensor info
            tensor = self.runtime.GetOutputTensor(i)
            tensor_name = tensor.GetName()
            # fetch output data
            tensor_data = tensor.ConvertToHost()
            if not tensor_data:
                raise Exception('failed to get output ' + tensor_name)
            
            out_data = np.array(tensor_data, copy=False)
            out_datas[tensor_name] = copy.deepcopy(out_data)
        
        return out_datas

Предварительная и постобработка данных

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

# preprocess
img = cv2.resize(img, (self.input_img_w, self.input_img_h)) # resize
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)                  # BGR -> RGB
img = img.transpose(2, 0, 1)                                # HWC -> CHW
img = img.astype(dtype = np.float32)                        # uint8 -> fp32
img /= 255                                                  # normalize
img = np.expand_dims(img, axis=0)                           # add batch dimension

Поскольку входная форма (160, 160) и все изображения в обучении имеют одинаковую форму, почтовый ящик здесь не используется.

Что касается постобработки, стандартный YOLOV5 имеет три выхода, которые необходимо комбинировать с привязками на разных уровнях для расчета положения выходного поля. Однако модель ONNX, экспортируемая репозиторием, уже сделала эту часть работы за нас, нам нужно только отфильтровать box_score и class_score в результате и выполнить nms. Я не буду публиковать здесь код постобработки.

сделать ключи

звук клавиатуры

Здесь я использую звук клавиатуры Python.mingusБиблиотека решается, установка очень простая:

pip3 install mingus
pip3 install fluidsynth

Воспроизведение заметок также очень просто, всего несколько строк кода:

from mingus.midi import fluidsynth
fluidsynth.init('/usr/share/sounds/sf2/FluidR3_GM.sf2', 'alsa')    # for ubuntu
fluidsynth.play_Note(64, 0, 100)                                   # 标准音 a1

дисплей клавиатуры

Графика клавиатуры сделана с помощью OpenCV

На клавиатуре фортепиано есть четыре вида клавиш - три вида белых клавиш и один вид черных клавиш.Здесь Enum используется для описания этих четырех видов клавиш, и различные виды клавиш подвергаются разной графической обработке, и, наконец, абстрагироваться в классыPianoKey:

class KeyType(Enum):
    WHITE_KEY = 0,
    WHITE_KEY_LEFT = 1,
    WHITE_KEY_RIGHT = 2,
    BLACK_KEY = 3

PianoKeyсуществует одинplay(self, position)Интерфейс, как только позиция попадает в диапазон клавиши, определяется, что клавиша нажата, и издается звук, соответствующий клавише.

Поместите картинку эффекта клавиши (желтый цвет - это клавиша, которая нажата, программатор подобрал цвет):

image.png

окончательный эффект

Соединив вышеперечисленные модули, мы получим наше «пианино с кошачьей головой».

Вставьте окончательный рендеринг, красный прямоугольник — обнаруженная голова кошки, красная точка — центр поля обнаружения, используйте эту точку, чтобы коснуться клавиш:

image.png

видео демонстрация

Демонстрация видео:Woohoo.Proportion.com/video/BV17 также…

ссылка на репозиторий гитхаб:GitHub.com/ZiChenTipress/…