IT-инфраструктура для бизнеса и творчества
Разработка
Selectel

Сделай сам: умная камера для наблюдения за питомцами

Обучаем нейросеть на котиках.

В серии DIY-статей «Пространство для изобретений» мы пробуем в домашних условиях разработать необычные гаджеты и оставляем все необходимые инструкции, чтобы любой желающий мог повторить наш опыт. Серию статей поддерживает Selectel — провайдер ИТ-инфраструктуры, которая помогает в решении рабочих задач и разработке личных проектов. Посмотреть, что интересного есть у провайдера, и выбрать для себя подходящие решения можно на сайте.

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

Зачем нужна камера

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

Рассказываю, что из этого вышло.

Что потребуется для сборки

Большую часть времени коты проводят на участке — там у меня уже установлена система видеонаблюдения из четырёх аналоговых камер с простым регистратором Falcon Eye, поэтому ничего нового я не покупал. Для моей задумки было важно, чтобы регистратор мог отдавать в сеть RTSP-поток для покадровой обработки видео в режиме реального времени.

Устанавливаем софт

До начала сборки камеры у меня было довольно смутное представление о работе нейросетей и особенностях компьютерного зрения: в лаборатории робототехники для детей, которой я руковожу, мы занимаемся программированием на Arduino и до этого не касались подобных проектов. Изучать область я начал с библиотеки PixelLib — она помогает определять и сегментировать объекты на изображениях, при этом разбираться в нейросетях не нужно.

Установил утилиту Virtualenv — она позволяет создавать изолированные виртуальные окружения для Python: создаёт внутри вашего проекта каталог, в который устанавливает нужную версию Python и все необходимые пакеты для приложения, фреймворка или скрипта. В результате вы получаете рабочее, полностью изолированное и переносимое окружение — это значит, что пакеты мы сможем устанавливать именно в это окружение, а не глобально.

Устанавливаю в терминале

sudo pip3 install virtualenv

Если pip не установлен

sudo apt install python3-pip pip3 install –upgrade pip

Создаю виртуальную среду в папку Venv1 с python3.6

virtualenv -p python3.6 project/Venv1

И запускаю

source project/Venv1/bin/activate

Для выхода из среды Venv1

deactivate

Теперь устанавливаю библиотеку PixelLib, проект буду создавать в Virtualenv.

source project/Venv1/bin/activate

PixelLib требует Python версии 3.5–3.7 и версию pip больше 19.0.

pip3 install pip

Устанавливаю последнюю версию Tensorflow (Tensorflow 2.0+)

pip3 install tensorflow

А теперь imgaug:

pip3 install imgaug

И последний шаг — установка PixelLib:

pip3 install pixellib --upgrade

Захватываем RTSP-поток с камер

Регистратор отдаёт rtsp-поток по адресу

rtsp://<login>:<password>@<ip-адрес регистратора>:554/mode=real&idc=<n камеры>&ids=1

Сначала я настроил камеры в самом щадящем режиме — один кадр в секунду. А ещё отключил на них режим «тревоги», при котором поток увеличивается до 15 кадров в секунду.

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

Библиотека PixelLib хорошо документирована, в ней очень много примеров. Для этого скрипта, например, я использую Instance segmentation of images with PixelLib.

Подключение библиотек

import os os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" import time #import _thread from pixellib.instance import instance_segmentation import cv2 from datetime import datetime

Загрузка модели (указываю путь к скачанной модели mask_rcnn_coco.h5):

segment_frame.load_model("mask_rcnn_coco.h5")

Выбор объектов для определения (для тестирования person и cat):

target_class = segment_frame.select_target_classes(person=True,cat=True)

Создание объекта камеры:

vcap = cv2.VideoCapture(urlRtsp+"&idc="+idc+"&ids="+ids)

Получение кадра:

ret, frame = vcap.read()

Масштабирование картинки:

output=cv2.resize(frame,(int(frame.shape[1]/2),int(frame.shape[0]/2)))

И прогон через детектор:

result,img = segment_frame.segmentFrame ( output, #show_bboxes=True, segment_target_classes=target_class, #extract_segmented_objects=True, #save_extracted_objects=True, #output_image_name="output.jpg" )

При ненулевом результате сохранение картинки в папку:

f=cv2.imwrite(pathSaveImg+"/cam"+idc+"/"+ftime.strftime("%d-%m-%Y")+"/_"+ftime.strftime("%H:%M:%S.%f")+".jpg", output)

Скрипт целиком:

import os os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" import time #import _thread from pixellib.instance import instance_segmentation import cv2 from datetime import datetime # "rtsp://admin:191066@192.168.0.109:554/mode=real&idc=3&ids=1" urlRtsp="rtsp://admin:191066@192.168.0.109:554/mode=real" pathSaveImg="/home/petin/python3_prgs_1" idc="3" ind=1; ids="1" timePrevFrame=0 countAll=0 countDetect=0 segment_frame = instance_segmentation(infer_speed = "fast") segment_frame.load_model("mask_rcnn_coco.h5") target_class = segment_frame.select_target_classes(person=True,cat=True) vcap = cv2.VideoCapture(urlRtsp+"&idc="+idc+"&ids="+ids) print("start**********************************************") while(1): ret, frame = vcap.read() if ret: dt = datetime.now() countAll=countAll+1 print("countAll=",countAll) print(" pixellib ") output=cv2.resize(frame,(int(frame.shape[1]/2),int(frame.shape[0]/2))) timePrevFrame=dt.timestamp() result,img = segment_frame.segmentFrame ( output, #show_bboxes=True, segment_target_classes=target_class, #extract_segmented_objects=True, #save_extracted_objects=True, #output_image_name="output.jpg" ) dt = datetime.now() timeTekFrame=dt.timestamp() print(timePrevFrame," ",timeTekFrame," ",timeTekFrame-timePrevFrame) objects_count = len(result["scores"]) print(f"Найдено объектов: {objects_count}") if objects_count>0: #_thread.start_new_thread(detect,(frame,)) ftime=datetime.now() if(os.path.exists(pathSaveImg+"/cam"+idc+"/"+ftime.strftime("%d-%m-%Y"))==False): os.mkdir(pathSaveImg+"/cam"+idc+"/"+ftime.strftime("%d-%m-%Y")) f=cv2.imwrite(pathSaveImg+"/cam"+idc+"/"+ ftime.strftime("%d-%m-%Y")+"/_"+ftime.strftime("%H:%M:%S.%f")+".jpg", output) print("write file = ",f) cv2.imshow('VIDEO1', output) elif ret: vcap.release() vcap = cv2.VideoCapture(urlRtsp+"&idc="+idc+"&ids="+ids) print("restart vcap") else: print("no ret",countAll) cv2.waitKey(1)

Запускаю программу — опознание приемлемое, но скорость не радует: на анализ картинки уходит секунда. Это неудивительно: детектор работает с CPU. Для работы с графикой библиотеке необходима установка CUDA, а для этого нужны графическая карта NVIDIA, которой на NUC нет.

Есть пара альтернатив: можно установить OpenVINO и подключить Neural Compute Stick 2 или попробовать Nvidia Jetson Nano. У меня был Neural Compute Stick 2, поэтому пробую этот вариант.

Устанавливаю OpenVINO toolkit — открытый бесплатный набор инструментов, который помогает детектировать лицо, распознавать объекты, текст и речи. По описаниям Intel производительность OpenVINO при вычислении сетей на платформах Intel в разы выше по сравнению с популярными фреймворками, а требования памяти — значительно ниже.

Во время установки выбираю последний дистрибутив 2021.3.394 и устанавливаю Intel® Neural Compute Stick 2. OpenVINO включает в себя несколько модулей и скриптов. Сразу попробовал, как работает определение объектов. Я использовал модель mobilenet-ssd — её нужно преобразовать во внутренний формат OpenVino с помощью Model Optimizer.

Загрузка модели

путь к downloader.py

/opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader

команда загрузки модели

python3 /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/downloader.py --name mobilenet-ssd

Перед запуском примера с обученной моделью убедитесь, что она преобразована в формат механизма вывода (* .xml + * .bin) с помощью инструмента Model Optimizer.

Конвертирование модели

путь к converter.py

/opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader

После конвертирования получаю модель в формате OpenVino.

Проверяю работу на старых фотографиях.

python3 /opt/intel/openvino_2021/inference_engine/samples/python/object_detection_sample_ssd.py -i cat01.jpg -m home/petin/public/mobilenet-ssd/FP32/mobilenet-ssd.xml -nt 5 -d CPU

Опознание в модели mobilenet-ssd приемлемое, буду использовать ее. Дополнительно устанавливаю пакет imutils.

pip3 install imutils

Скачиваю файлы модели mobilenet-ssd.caffemodel и mobilenet-ssd.prototxt с помощью «Загрузчика моделей» (Model Downloader) OpenVino

python3 /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/downloader.py ----name mobilenet-ssd

Пишу скрипт захвата видео с четырёх камер, прогон картинки через детектор и сохранение картинки в каталог cam<n>/<d-n-Y> при детектировании кота.

# подключение библиотек from imutils.video import VideoStream from imutils.video import FPS import numpy as np import sys import argparse import imutils import time import cv2 from urllib.request import urlopen from datetime import datetime import os tekcamera=1 pathSaveImg="/home/petin/python3_prgs_1/OpenVino01" cameras=[[0,0,0,0,0], [0,0,0,0,0], [False,True,False,True,False], ["","Camera1","Camera2","Camera3","Camera4"]] for i in range(1,5): cameras[1][i] = 'rtsp://admin:191066@192.168.0.109:554/mode=real&idc='+str(i)+'&ids=1' fps = FPS().start() # получение аргументов командной строки # --prototxt путь к файлу mobilenet-ssd.prototxt # --model путь к файлу модели mobilenet-ssd.caffemodel # --show вывод изображений с камер в окна # -c минимальная точность определения объекта ap = argparse.ArgumentParser() ap.add_argument("--prototxt", required=True, help="path to Caffe 'deploy' prototxt file") ap.add_argument("--model", required=True, help="path to Caffe pre-trained model") ap.add_argument("--show", required=True, help="Show cv2.imshow)") ap.add_argument("-c", "--confidence", type=float, default=0.2, help="minimum probability to filter weak detections") args = vars(ap.parse_args()) # загрузка модели CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"] COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3)) print("[INFO] loading model...") net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"]) # обработка в Neural Compute Stick net.setPreferableTarget(cv2.dnn.DNN_TARGET_MYRIAD) # инициализация получения потока с камер print("[INFO] starting video stream...") for i in range(1,5): cameras[0][i] = cv2.VideoCapture(cameras[1][i]) print("OK") time.sleep(5.0) detected_objects = [] # цикл while(1): tekcamera = tekcamera+1 if tekcamera+==5: tekcamera=1 logfile=open("last.txt","w+") ftime=datetime.now() str1=.strftime("%d-%m-%Y % %H:%M:%S\n ") logfile.write(str1) logfile.close() if cameras[2][tekcamera] == False: continue # получение кадров из потока ret, frame = cameras[0][tekcamera].read() frame = imutils.resize(frame, width=800) # grab the frame dimensions and convert it to a blob (h, w) = frame.shape[:2] blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 0.007843, (300, 300), 127.5) # pass the blob through the network and obtain the detections and # predictions net.setInput(blob) detections = net.forward() # обработка результатов детектирования print("******************") for i in np.arange(0, detections.shape[2]): confidence = detections[0, 0, i, 2] idx = int(detections[0, 0, i, 1]) #if confidence > args["confidence"] and idx==15 : if confidence > args["confidence"] and (idx==8 or idx==12) : # save files ftime=datetime.now() if(os.path.exists(pathSaveImg+"/cam"+str(tekcamera)+"/"+ftime.strftime("%d-%m-%Y"))==False): os.mkdir(pathSaveImg+"/cam"+str(tekcamera)+"/"+ftime.strftime("%d-%m-%Y")) f=cv2.imwrite(pathSaveImg+"/cam"+str(tekcamera)+"/"+ftime.strftime("%d-%m-%Y")+"/_"+ftime.strftime("%H:%M:%S.%f")+".jpg", frame) print("write file = ",f) # extract the index of the class label from the # `detections`, then compute the (x, y)-coordinates of # the bounding box for the object #idx = int(detections[0, 0, i, 1]) box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = box.astype("int") # draw the prediction on the frame label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100) print(confidence," ",idx," - ",CLASSES[idx]) detected_objects.append(label) cv2.rectangle(frame, (startX, startY), (endX, endY), COLORS[idx], 2) y = startY - 15 if startY - 15 > 15 else startY + 15 cv2.putText(frame, label, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2) # show the output frame if args["show"] == "True": cv2.imshow(cameras[3][tekcamera], frame) key = cv2.waitKey(1) & 0xFF # выход по клавише 'q' if key == ord("q"): break fps.update() fps.stop() print("[INFO] elasped time: {:.2f}".format(fps.elapsed())) print("[INFO] approx. FPS: {:.2f}".format(fps.fps())) # do a bit of cleanup cv2.destroyAllWindows()

Запуск скрипта на выполнение

source Venv1/bin/activate cd /home/petin/python3_prgs_1/OpenVino01 python3 pets04.py --prototxt mobilenet-ssd.prototxt --model mobilenet-ssd.caffemodel --show True -c 0.3

Изображения сохраняются в папках cam/. Скорость хорошая — для двух камер при частоте 5 кадров в секунду задержек нет. Но получается слишком много фото, поэтому поток я уменьшил до 1 кадра в секунду.

Обязательно делаю автозагрузку скрипта. Создаю файл autoupload.sh следующего содержания:

#!/bin/bash source Venv1/bin/activate cd /home/petin/python3_prgs_1/OpenVino01 python3 pets04.py --prototxt mobilenet-ssd.prototxt --model mobilenet-ssd.caffemodel --show True -c 0.3

И помещаю в автозагрузку autoupload.sh.

Обзор → Автоматически запускаемые приложения → Добавить

И указываю путь к python-скрипту.

Собираем видео и отправляем в Telegram

Фотографии котов я хочу получать в виде ролика. Для этого устанавливаю пакет ffmpeg.

sudo apt install ffmpeg

И запускаю следующие команды:

Для камеры 1:

ffmpeg -f image2 -pattern_type glob -i /home/petin/python3_prgs_1/OpenVino01/cam1/$(date +%d-%m-%Y)/'*.jpg' -y /home/petin/python3_prgs_1/OpenVino01/cam1-$(date +%d-%m-%Y).mp4 –r 10

Для камеры 2:

ffmpeg -f image2 -pattern_type glob -i /home/petin/python3_prgs_1/OpenVino01/cam2/$(date +%d-%m-%Y)/'*.jpg' -y /home/petin/python3_prgs_1/OpenVino01/cam2-$(date +%d-%m-%Y).mp4 –r 10

Для остальных камер — по аналогии. Показалось, что фото будет много, поэтому выбрал скорость 10 кадров в секунду. Команды помещаю в cron (запуск в конце дня — в 18:00) для формирования файлов cam-.mp4.

Создаю файл cron.sh:

#!/bin/bash ffmpeg -f image2 -pattern_type glob -r 10 -i /home/petin/python3_prgs_1/OpenVino01/cam1/$(date +%d-%m-%Y)/'*.jpg' -y /home/petin/python3_prgs_1/OpenVino01/cam2-$(date +%d-%m-%Y).mp4 ffmpeg -f image2 -pattern_type glob -r 10 -i /home/petin/python3_prgs_1/OpenVino01/cam2/$(date +%d-%m-%Y)/'*.jpg' -y /home/petin/python3_prgs_1/OpenVino01/cam2-$(date +%d-%m-%Y).mp4 ffmpeg -f image2 -pattern_type glob -r 10 -i /home/petin/python3_prgs_1/OpenVino01/cam3/$(date +%d-%m-%Y)/'*.jpg' -y /home/petin/python3_prgs_1/OpenVino01/cam3-$(date +%d-%m-%Y).mp4 ffmpeg -f image2 -pattern_type glob -r 10 -i /home/petin/python3_prgs_1/OpenVino01/cam4/$(date +%d-%m-%Y)/'*.jpg' -y /home/petin/python3_prgs_1/OpenVino01/cam4-$(date +%d-%m-%Y).mp4

Добавляю задание cron. Записываю в файл /var/spool/cron/crontabs/petin строку

* 18 * * * /home/petin/python3_prgs_1/OpenVino01/cron.sh

Теперь настраиваю отправку файлов в Telegram. Создаю телеграм-бота: пишу пользователю @BotFather и придумываю имя. В ответ приходит сообщение с токеном для http api — его нужно сохранить.

Создаю группу, добавляю в неё бота, устанавливаю библиотеку:

pip3 install pytelegrambotapi

И пишу программу:

import telebot from telebot import types from datetime import datetime, timedelta from pathlib import Path keyboard1 = [["","Камера 1","Камера 2","Камера 3","Камера 4","Не надо"],["","cam1","cam2","cam3","cam4","no"]] bot = telebot.TeleBot('your-token'); @bot.message_handler(content_types=['text', 'document', 'audio']) def get_text_messages(message): chatId=message.chat.id print(chatId) key_1=[0,0,0,0,0,0] ftime=datetime.now() print(ftime.day," ",ftime.hour) day=ftime.strftime("%d-%m-%Y") if message.text == "/help": bot.send_message(message.from_user.id, "Привет, здесь ты можешь посмотреть, что делали мои котики за день 9:00–18:00. Набери /video") elif message.text == "/video": msg="здесь ты можешь посмотреть, что делали мои котики за день 9:00–18:00"+day bot.send_message(message.from_user.id, msg) keyboard = types.InlineKeyboardMarkup(); # клавиатура for i in range(1,6): #кнопка key_1[i] = types.InlineKeyboardButton(text=keyboard1[0][i], callback_data=keyboard1[1][i]); #добавляем кнопку в клавиатуру keyboard.add(key_1[i]); bot.send_message(message.from_user.id, "Выбери камеру", reply_markup=keyboard) else: bot.send_message(message.from_user.id, "Я тебя не понимаю. Напиши /help.") @bot.callback_query_handler(func=lambda call: True) def callback_worker(call): ftime=datetime.now() day=ftime.strftime("%d-%m-%Y") if call.data.find("cam") < 0: bot.send_message(call.message.chat.id, 'No'); else: if ftime.hour >= 18: bot.send_message(call.message.chat.id, 'Видео с камеры '+call.data.replace("cam","")+'. Wait ....'); videofile = Path(call.data+'-'+day+'.mp4') if videofile.is_file(): video = open(call.data+'-'+day+'.mp4', 'rb') bot.send_video(call.message.chat.id, video) bot.send_message(call.message.chat.id, "Загружено") else: bot.send_message(call.message.chat.id, 'Видео отсутствует !!!'); else: bot.send_message(call.message.chat.id, 'Просмотр видео текущего дня только после 18:00, Просмотр за предыдущий день'); ftime=datetime.now()- timedelta(days=1) dayold=ftime.strftime("%d-%m-%Y") videofile = Path(call.data+'-'+dayold+'.mp4') if videofile.is_file(): video = open(call.data+'-'+dayold+'.mp4', 'rb') bot.send_video(call.message.chat.id, video) bot.send_message(call.message.chat.id, "Загружено") else: bot.send_message(call.message.chat.id, 'Видео отсутствует !!!'); bot.polling(none_stop=True, interval=0)

Запуск бота (чтобы он мог отвечать на сообщения, скрипт должен быть постоянно запущен):

cd /home/petin/python3_prgs_1/OpenVino01 python3 pets_send_telegram.py

Скрипт бота также добавляю в автозагрузку.

Создаю файл autoupload_telegram.sh

#!/bin/bash cd /home/petin/python3_prgs_1/OpenVino01 python3 pets_send_telegram.py

И помещаю в автозагрузку autoupload.sh.

Обзор → Автоматически запускаемые приложения → Добавить

И указываю путь к python-скрипту.

Бот знает две команды: /help и /video. Когда просишь видео — открывает меню с выбором камеры. Бот присылает видео от сегодняшнего дня (если просим после шести вечера) или от вчерашнего.

Выбираем место для установки камер

Я выбирал места методом проб и ошибок, потому что не знаю точно, где котики обычно проводят время.

Подсоединяю камеры к регистратору.

В сети — роутер, регистратор, NUC по Wi-Fi. При загрузке запускаются python-скрипт получения данных с камер и детектирования, плюс скрипт бота.

Захожу в Telegram, выбираю камеру и… начинаю смотреть за котиками.

Подводим итоги и приступаем к новой версии

Все файлы проекта доступны на github.

Я доволен результатом — теперь могу медитировать, наблюдая за своими питомцами.

До совершенства пока далеко: хвостатые постоянно меняют места отдыха и разбредаются, ловить их на большом участке непросто. К тому же появились новые «хотелки»: здорово было бы получать видео по каждому коту — для этого нужно обучить модель их различать. Занялся этим сразу.

Первым делом решил собрать фотографии питомцев: для тренировки сети нужно минимум по 300 фото каждого кота и по 100 — для тестирования. При этом коты не хотели фотографироваться в разных позах, так что после нескольких дней съёмок я собрал всего 314 снимков.

Выделил объекты на фото и пометил их (использую программу labelme):

sudo pip3 install labelme

Для каждой фотографии создаётся файл json.

Разделяю фото в папки train и test и запускаю скрипт для обучения модели.

import pixellib from pixellib.custom_train import instance_custom_training train_maskrcnn = instance_custom_training() train_maskrcnn.modelConfig(network_backbone = "resnet101", num_classes= 2, batch_size = 4) train_maskrcnn.load_pretrained_model("mask_rcnn_coco.h5") train_maskrcnn.load_dataset("Nature") train_maskrcnn.train_model(num_epochs = 300, augmentation=True, path_trained_models = "mask_rcnn_models")

За 7 дней прошло 25 шагов тренировки из 300 — не очень-то быстро. Ускориться помогут либо мощное железо, либо облачные сервисы с графическими процессорами. Например, серверы с GPU от Selectel: провайдер предлагает мощную ресурсную базу, с которой время тренировки удастся сократить с нескольких недель — до дней или даже часов.

Вот такую конфигурацию служба поддержки Selectel подобрала для меня:

На сервере уже была установлена заказанная мной ОС Ubuntu 20.04. Устанавливаю CUDA по этой инструкции и библиотеку pixellib.

Install the latest version of tensorflow(Tensorflow 2.0+) with: pip3 install tensorflow-gpu pip3 install imgaug pip3 install pixellib --upgrade

Сделал много дополнительных фотографий, разделил их на две папки и разметил, как предыдущие в программе labelme. Загрузил набор данных на сервер.

Для обучения нашей модели будем применять методику трансферного обучения, используя базовую модель mask_rcnn_coco.h5, обученную на 80 категориях объектов.

Загрузка mask_rcnn_coco.h5

wget "https://github.com/ayoolaolafenwa/PixelLib/releases/download/1.2/mask_rcnn_coco.h5"

Скрипт для обучения customtrain01.py

import pixellib from pixellib.custom_train import instance_custom_training train_maskrcnn = instance_custom_training() train_maskrcnn.modelConfig(network_backbone = "resnet50", num_classes= 5, batch_size = 4) train_maskrcnn.load_pretrained_model("mask_rcnn_coco.h5") train_maskrcnn.load_dataset("pets03") train_maskrcnn.train_model(num_epochs = 200, augmentation=True, path_trained_models = "mask_rcnn_models")

Запуск скрипта

python3 customtrain01.py

Процесс обучения отображается в терминале

Using resnet50 as network backbone For Mask R-CNN model Applying Default Augmentation on Dataset Train 608 images Validate 89 images Checkpoint Path: /home/petin/petscats/mask_rcnn_models Selecting layers to train Epoch 1/100 100/100 [==============================] - 394s 3s/step - batch: 49.5000 - size: 4.0000 - loss: 1.9734 - rpn_class_loss: 0.1194 - rpn_bbox_loss: 0.7562 - mrcnn_class_loss: 0.1773 - mrcnn_bbox_loss: 0.7554 - mrcnn_mask_loss: 0.1652 - val_loss: 1.8159 - val_rpn_class_loss: 0.0354 - val_rpn_bbox_loss: 0.7352 - val_mrcnn_class_loss: 0.2133 - val_mrcnn_bbox_loss: 0.7738 - val_mrcnn_mask_loss: 0.0583 - lr: 0.0010 Epoch 2/100 100/100 [==============================] - 287s 3s/step - batch: 49.5000 - size: 4.0000 - loss: 1.5770 - rpn_class_loss: 0.0347 - rpn_bbox_loss: 0.6571 - mrcnn_class_loss: 0.1848 - mrcnn_bbox_loss: 0.6495 - mrcnn_mask_loss: 0.0510 - val_loss: 1.5399 - val_rpn_class_loss: 0.0318 - val_rpn_bbox_loss: 0.5624 - val_mrcnn_class_loss: 0.1974 - val_mrcnn_bbox_loss: 0.6905 - val_mrcnn_mask_loss: 0.0578 - lr: 0.0010 Epoch 3/100 13/100 [==>...........................] - ETA: 3:29 - batch: 6.0000 - size: 4.0000 - loss: 1.6279 - rpn_class_loss: 0.0347 - rpn_bbox_loss: 0.6848 - mrcnn_class_loss: 0.1869 - mrcnn_bbox_loss: 0.6644 - mrcnn_mask_loss: 0.0571

Модели сохраняются в папку mask_rcnn_models на основе уменьшения потерь при проверке

Запуск

python3 testtrain01.py

Вывод

mask_rcnn_models\ mask_rcnn_model.001-1.851553.h5 evaluation using iou_threshold 0.5 is 0.723500

Проверяем модель на фотографиях

import pixellib from pixellib.instance import custom_segmentation segment_image = custom_segmentation() segment_image.inferConfig(num_classes= 5, class_names= ["BG", "mimicat", "tigercat","smokeycat","redcat","wildcat"]) segment_image.load_model("mask_rcnn_models/mask_rcnn_model.xxx-1.yyyyyy.h5") segment_image.segmentImage("myimg.jpg", show_bboxes=True, output_image_name="sample_out.jpg")

Модель готова, теперь её можно использовать в проекте.

За месяц аренды сервера для своей задачи я бы потратил 25 600 рублей. Целого сервера для одного пет-проекта «слишком много»: арендовать его можно совместно с друзьями, чтобы по очереди учить модели для разных задач.

(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ { name: 'camera', url: `${cdnUrl}CameraCat`, text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', link: 'https://vc.ru/selectel/306690', num: 3 }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
6 комментариев
Популярные
По порядку
Написать комментарий...

Хозяин: делает систему видеонаблюдения за котами, медитирует на них.
Коты: делятся на группы А и Б, и пока группа А отвлекает внимание хозяина, валяясь, потягиваясь и вылизываясь под камерами, группа Б проникает на кухню и взламывает холодильник. ред.

12

"На что ты тратишь свою жизнь?"

3

Такие можно ставить в гостиницах для кошек, чтобы в отъезде можно было наблюдать за ушастыми и не беспокоиться ^_^

2

У нас в гостинице просто стоят камеры в каждом номере. Нужны ли там такие усложнения? У автора задачи посложнее.

0

Наверно идеально чтобы просто приходил ответ со списком котов и временем их последнего появления на камере

0

камера наблюдения за питомцами.

0
Читать все 6 комментариев
Как в 6 раз увеличить охваты в соцсетях и задать визуальные тренды в нише. Кейс «Мираж Синема»

Студия Чижова рассказывает, как делать SMM для кинотеатров: кейс федеральной сети «Мираж Синема»

В профиле на публикациях не видно дополнительных надписей, лента выглядит чисто и минималистично
ЮMoney сделали виртуальные банковские карты с дизайном из Cyberpunk 2077

Их можно заказать до 7 декабря, чтобы принять участие в розыгрыше призов.

Юбилей кешбэка: как в 130 лет выглядеть «на все сто»

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

eBay: 64% покупателей не жалеют о своих покупках в Черную пятницу

Черная пятница — одно из главных событий этой недели: тысячи покупателей находятся в поиске лучших скидок. А что происходит после Черной пятницы? eBay опросил около 1000 россиян и выяснил, считают ли они выгодными покупки, совершенные во время самой большой распродажи года.

Совет управляющих ЕЦБ одобрил новую систему контроля за электронными платежами

После общественных обсуждений в 2020 году Совет управляющих Европейского центрального банка (ЕЦБ) утвердил новую Евросистему контроля за электронными платежами, схемами и устройствами (далее - PISA).

Зимний набор на оплачиваемую стажировку в Тинькофф Старт: какие задачи решают стажеры

Стажировка пройдет по направлениям: аналитика, QA, бэкенд-разработка (Java, C++, Python, Scala, .Net, Golang), фронтенд, мобильная разработка (iOS и Android), ML, маркетинг и менеджмент образовательных проектов.

«У нас есть Волож, который нам мозг клюет»: Тиньков посчитал, что в «Яндексе» испугались покупать «Тинькофф» Статьи редакции

В «Яндексе» не захотели, чтобы после сделки Олег Тиньков остался консультировать бизнес, рассказал основатель «Тинькофф банка» в документальном фильме.

Экологичный email-маркетинг: полный гайд, как продавать через рассылки и не раздражать пользователей

Мы подготовили для вас полный гайд по созданию экологичной и эффективной email-стратегии: от подготовки базы до работы с анализом результатов.

Пять историй разработчиков облака Яндекса: как помогать тысячам компаний управлять данными и ​любить челленджи

Рассказываем, кто и как разрабатывает продукт в облаке Яндекса, который за полгода принес 15% выручки и вырос по объему потребления клиентами на 390%. Про найм, инженерную культуру, opensource и челленджи.

Команда Data Platform
Кинокомпания Bazelevs Тимура Бекмамбетова разработала сервис для продажи товаров в фильмах и сериалах Статьи редакции

Платформа работает на базе собственного плеера кинокомпании и облачных технологий Microsoft.

Ozon и «Яндекс» увеличили капиталы собственных банков в 1,6–2 раза за три месяца Статьи редакции

Компании планируют выдавать потребительские кредиты, считают эксперты.

null