Ловим кошек в Instagram

Технологии машинного обучения с каждым днем находят новые и новые сферы применения. Становится ясно, что следующая эпоха за machine learning и big data. Но, к сожалению, порог вхождения довольно высок для не подготовленного человека. Давайте же немного приоткроем занавес и попробуем сами пощупать machine learning на примере компьютерного зрения своими руками.

Ставим задачу

Найти все фотографии в профиле instagram с изображением котов.

Приступим

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

pip3 install instaloader

Далее напишем сам скрипт:

# cat_detector.py
from instaloader import Instaloader, Profile


PROFILE = '<instagram profile here...>'


def main():
    loader = Instaloader()
    post_iterator = Profile.from_username(loader.context, PROFILE).get_posts()

    for i, post in enumerate(post_iterator, 1):
        print(post.caption)
        print(post.url)
        print('-' * 10)


if __name__ == '__main__':
    main()

Просто, не правда ли?

Окей, мы получили картинки из постов профиля, дело осталось за малым - выбрать из них те, на которых изображены котики >^_^<. Для этого мы будем использовать библиотеку ImageAI, которая очень проста и супер функциональна, сейчас убедимся:

# ставим imageai и зависимости
pip install imageai tensorflow opencv-python keras

Также нам необходимо будет скачать файл https://github.com/OlafenwaMoses/ImageAI/releases/download/1.0/yolo.h5 и положить его рядом с нашим скриптом, который представляет из себя сохраненную модель нейронной сети, которая уже обучена распознавать тысячи различных объектов.

Теперь обновим наш скрипт:

# cat_detector.py
import os
import io
from PIL import Image
from instaloader import Instaloader, Profile
from imageai.Detection import ObjectDetection

PROFILE = '<instagram profile here...>'
BASE_DIR = os.path.dirname(os.path.abspath(__file__))


def has_cat(detections):
    for detection in detections:
        if detection['name'] == 'cat':
            return True
    return False


def main():
    detector = ObjectDetection()
    detector.setModelTypeAsYOLOv3()
    detector.setModelPath(os.path.join(BASE_DIR, "yolo.h5"))
    detector.loadModel()

    loader = Instaloader()
    post_iterator = Profile.from_username(loader.context, PROFILE).get_posts()

    for i, post in enumerate(post_iterator, 1):
        raw_image = loader.context.get_raw(post.url)
        image_array, detections = detector.detectObjectsFromImage(
            input_image=io.BytesIO(raw_image.raw.read()),
            input_type='stream',
            output_type='array',
            minimum_percentage_probability=30)

        if has_cat(detections):
            im = Image.fromarray(image_array)
            im.save(os.path.join(BASE_DIR, 'output', '{}.jpg'.format(i)))
            print("Cat detected! See image: output/{filename}.jpg\n\n"
                  "{caption}\n"
                  "{url}\n\n".format(
                        filename=i,
                        caption=post.caption,
                        url=post.url

            ))
            print('*' * 10)


if __name__ == '__main__':
    main()

Также создадим папку output, в которую наш скрипт бережно сложит всех найденых котов.

Пробуем запустить:

python3 cat_detector.py

И все коты найдены.

Что здесь происходит?

Давайте пройдемся по нашему скрипту и разберем основные моменты.

PROFILE = '<instagram profile here...>'

Здесь мы указываем профиль посты которого мы будем анализировать.

def has_cat(detections):
    for detection in detections:
        if detection['name'] == 'cat':
            return True
    return False

Простая функция которая вернет True, если среди всех найденых объектов есть объект с именем cat.

    detector = ObjectDetection()
    detector.setModelTypeAsYOLOv3()
    detector.setModelPath(os.path.join(BASE_DIR, "yolo.h5"))
    detector.loadModel()

Создаем и инициализируем наш детектор, в качестве модели указываем скачанный нами раннее файл yolo.h5.

    loader = Instaloader()
    post_iterator = Profile.from_username(loader.context, PROFILE).get_posts()

Создаем post_iterator, который позволит нам получать один за одним посты пользователя.

raw_image = loader.context.get_raw(post.url)

Скачиваем изображение поста по url.

        image_array, detections = detector.detectObjectsFromImage(
            input_image=io.BytesIO(raw_image.raw.read()),
            input_type='stream',
            output_type='array',
            minimum_percentage_probability=30)

Здесь происходит основная магия - мы передаем скачанную картинку нашему детектору. Остановимся подробнее на параметрах:

  •   input_image - входное изображение, может принимать имя файла, массив и поток;
  •   input_type - тип входного изображения, по умолчанию `file`. Может так же принимать значения `array` или `stream`;
  •   output_type - формат выходного изображения, может быть или `file`, или `array`;
  •   minimum_percentage_probability - минимальный процент “уверенности” нашего детектора в правильности распознанного объекта.
if has_cat(detections):
            im = Image.fromarray(image_array)
            im.save(os.path.join(BASE_DIR, 'output', '{}.jpg'.format(i)))

Если среди найденых объектов есть представители семейства кошачих, то нужно сохранить изображение в папку output.

Заключение

Надеюсь, вам понравилась задача и простота используемых инструментов. Если вы хотите разобраться подробнее, можете ознакомится с документацией на страницах проектов:

Instaloader https://github.com/instaloader/instaloader

ImageAI https://github.com/OlafenwaMoses/ImageAI

  instagram, machine learning, python

  Смотреть все посты