{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# A slight introduction to cv and image processing with OpenCV + Bonus\n", "Этот туториал немного выходит за рамки открытого курса, но для коллег, решивших продолжить развиваться в области DL, computer vision, #class_cs231n введение в библиотеку OpenCV будет очень полезным.\n", "\n", "OpenCV (англ. Open Source Computer Vision Library, библиотека компьютерного зрения с открытым исходным кодом) — библиотека алгоритмов компьютерного зрения, обработки изображений и численных алгоритмов общего назначения с открытым кодом. Реализована на C/C++, также разрабатывается для Python, Java, Ruby, Matlab, Lua и других языков.\n", "\n", "В этом туториале продемонстрированно:\n", "\n", " - Как устанавливать нужные библиотеки\n", " - Особенности чтения изображений и вывода на экран\n", " - Принцип изображения простых геометрических фигур и текста на изображении\n", " - Различные преобразования над изображениями\n", " - Как читать видеопоток с файла и записывать в файл\n", " - Как читать видеопоток с камеры\n", " - Чистка изображений, фильтрация элементов изображений\n", " - Поиск паттернов\n", " - Распознавание лица и глаз при помощи каскадов Хаара\n", " - Bonus: распознавание лица и его элементов при помощи библиотеки dlib\n", "P.S. Я настоятельно рекомендую попробовать запустить этоу тетрадку у себя. Я параллельно написанию туториала сам изучаю OpenCV, с некоторыми фичами реально забавно работать (особенно бонусная часть). Надеюсь этот туториал не только принесет немного новых знаний, но и немного Вас развлечет.\n", "\n", "P.P.S. За помощь в составлении туториала отдельное спасибо [этому сайту](https://docs.opencv.org/3.0-beta/doc/tutorials/tutorials.html) и [особенно этому](https://pythonprogramming.net/)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Часть Первая" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Установка OpenCV\n", "\n", "Она же самая простая часть.\n", "\n", "Для всех систем, на которых я работал достаточно ввести команду типа **pip install opencv-python**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Часть вторая\n", "\n", "## Чтение изображений" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Первым делом импортируем opencv (cv2) и numpy\n", "import cv2\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтение изображений из файла происходит посредством комманды **imread('путь к изображению', флаг)**.\n", "\n", "Флаги бывают следующими:\n", "\n", " - cv2.IMREAD_COLOR - по умолчанию, чтение в цвете, но эффект прозрачности (alpha) будет удален\n", " - cv2.IMREAD_GRAYSCALE - чтение в градации серого\n", " - cv2.IMREAD_UNCHANGED - чтение цветного изображения включая alpha канал\n", "\n", "*Следует отметить, что все флаги в cv2 являются константами, их имена полностью состоят из заглавных букв. Например cv2.IMREAD_COLOR = 1. Подобных констант мы еще встретим не одну*." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-1.jpeg', cv2.IMREAD_COLOR)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Следует отдельно добавить, что к каждому пикселю изображения можно отдельно обратиться и изменить его значение. Например так:\n", "```python\n", "px = img[55,55]\n", "print(px)\n", "img[:55,:55] = [255,0,0]\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Вывод изображений\n", "\n", "\n", "Изображение можно вывести при помощи matplotlib и imshow. Но тут стоит быть внимательнее!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.imshow(img, interpolation='bicubic')\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Тут следует отдельно заметить, что цветовая схема изображения не соответствует оригиналу. Данный эффект наплюдается по причине того, что opencv читает и пишет изображения в формате BGR, следовательно для корректного изображения картинки посредством matplotlib, её необходимо преобразовать в формат RGB. Для этого используется команда cvtColor(img, флаг). Флагов очень много, проэтому советую ознакомиться с документацией или поэксперементировать." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.imshow(img_rgb, interpolation='bicubic')\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Второй способ отображения - штатный, но тут тоже есть свои особенности:\n", "\n", "1. Изображение открывается в отдельном окне\n", "2. Для закрытия изображения нужны две функции: waitKey(time) - после нажатия любой клавиши ждет time мсек до выполнения следующей функции, destroyAllWindows() - закрывает все окна\n", "3. **При сипользовании Jupyter и других тетрадок ни в коем случае на закрывайте окно нажатием \"на крестик\" мышкой - это повесит ваш кернел**\n", "4. Сама команда: **imshow('название окна', image)**" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Выводим окно с картинкой и закрываем нажатием любой клавиши клавиатуры\n", "cv2.imshow('image', img)\n", "cv2.waitKey(0)\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Сохранение изображений\n", "\n", "С сохранением изображений все очень просто и осуществляется посредством функии **imwrite**:\n", "```python\n", "cv2.imwrite('путь')\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть третья\n", "### Рисуем на изображении фигуры и пишем текст" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Эта базовая часть в последствии будет очень полезной, поэтому её освоить нужно одной из первых. Хороший пример тут\n", "\n", "В нашем распоряжении круги, прямоугольники, линии, текст, полигоны, овалы. Рассмотрим чуть подробнее часть из них:\n", "\n", " - **line**(Image, (x1, y1), (x2, y2), color, thickness, lineType), (x1, y1), (x2, y2) - координаты первой и последней точек линии\n", " - **rectangle**(Image, (x1, y1), (x2, y2), color, thickness, lineType, shift), (x1, y1), (x2, y2) - координаты верхнего левого и нижнего правого углов\n", " - **circle**(Image, (x1, y1), radius, color, thickness, lineType, shift), (x1, y1) координаты центра окружности\n", " - **polylines**(Image, pts, npts, ncontours, isClosed, color, thickness, lineType, shift), pts - координаты точек, isClosed - замыкание контура\n", " - **putText**(img, text, org, font, fontFace, fontScale, color, thickness, lineType), text - текст, org - нижний левый угол начала текста" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "draw = img\n", "cv2.line(draw, (300,300), (150,150), (255,255,255), 15, 5);\n", "cv2.rectangle(draw, (15,25), (200,150), (255,0,0), 5)\n", "# thickness = -1 означает полностью залить фигуру цветом\n", "cv2.circle(draw, (100,63), 55, (0,0,255),-1);\n", "pts = np.array([[10,5],[20,546],[464,131],[645,321]], np.int32)\n", "# ВАЖНО pts закрыть [pts] в скобки.\n", "cv2.polylines(draw, [pts], True, (15,154,214), 20);\n", "font = cv2.FONT_HERSHEY_SIMPLEX\n", "cv2.putText(draw, 'OpenCV', (546,154), fontFace =font, lineType =cv2.LINE_8, fontScale =5, color =(231,23,123), thickness =3);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cv2.imshow('img', draw)\n", "cv2.waitKey(0)\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 14,8\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), interpolation='bicubic')\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Также следует заметить, что наложение геометрических фигур постоянно для картинки (draw), поэтому её нужно пересожнавать для экспериментов, иначе старые изображения останутся" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть четвертая\n", "### Чтение видео" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для чтения видео необходимо воспользоваться функцией **VideoCapture**, которая может читать видео в двух режимах:\n", "\n", " - Чтение из файла: **cv2.VideoCapture('путь к файлу')**\n", " - Чтение с web-камеры: **cv2.VideoCapture(ind)**, где ind - порядковый номер желаемой камеры начиная с 0\n", "\n", "Отображать видею следует через цикл, так как оно отображается покадрово" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "\n", "while True:\n", " # cap возвращает 2 параметра: ret - bool (true, если сигнал с камеры или файла постувает), frame - изображение\n", " ret, frame = cap.read()\n", " # Я тут решил немного поиграться и конвертировать видео в формат градации серого\n", " gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n", " # Повернул изображение на 180 градусов, за это отвечает флаг - 1\n", " cv2.imshow('flip frame', cv2.flip(frame, 1))\n", " cv2.imshow('gray', gray)\n", " cv2.imshow('frame', frame)\n", " cv2.imshow('gray_flip', cv2.flip(gray, 1))\n", " # ВОТ НА ЭТУ КОНСТРУКЦИЮ СТОИТ ОБРАТИТЬ ВНИМАНИЕ cv2.waitKey(1) & 0xFF - побитовая операция and \n", " # (0100 and 1111 = 0100) по сути тут мы блокируем возможность получения символа с кодировкой ord() \n", " # выше 255 (ето рекомендация opencv), а также обозначаем, что нажатие 'q' закроет все окна\n", " # (раскладка английская иначе умрет кернел, потом мы решим эту проблему заменой на esc)\n", " if cv2.waitKey(10) & 0xFF == ord('q'):\n", " break\n", "#Не забываем высвободить видеоканал и закрыть все окна\n", "cap.release()\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Приведенная выше конструкция не подходит для чтения файлов ввиду того, что ret при работе с web-камерой почти всешда True, для работы с файлом следует немного поменять код:\n", "```python\n", "cap = cv2.VideoCapture(0)\n", "#Созданим заранее для запуска цикла\n", "ret = True\n", "while ret == True:\n", "\n", " ret, frame = cap.read()\n", " cv2.imshow('frame', frame)\n", "\n", " if (ret != True) or (cv2.waitKey(10) & 0xFF == ord('q')):\n", " break\n", "\n", "cap.release()\n", "cv2.destroyAllWindows()\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Запись видео\n", "Для записи видео нам необходимо две функции:\n", "\n", " - **VideoWriter_fourcc(codec) - инициализация кодека видео**\n", " - **VideoWriter('Адрес куда пишем', кодек, fps, разрешение)**\n", " \n", "Побробнее можно почитать [тут](https://docs.opencv.org/3.1.0/dd/d43/tutorial_py_video_display.html)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "fourcc = cv2.VideoWriter_fourcc(*'XVID')\n", "out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640,480))\n", "\n", "while True:\n", "\n", " ret, frame = cap.read()\n", " # Вот тут пришем\n", " out.write(frame)\n", " cv2.imshow('frame', frame)\n", "\n", " \n", " if cv2.waitKey(1) & 0xFF == ord('q'):\n", " break\n", "# не забываем высвобождать потоки ввода и вывода\n", "cap.release()\n", "out.release()\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Далее мы пойдем чуть веселее, меньше букв больше картинок и эффектов" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть пятая\n", "### Как логотип прикрепить к фону и сделать это более-менее красиво" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "logo = cv2.imread('../../img/cv2-2.jpg', cv2.IMREAD_COLOR)\n", "ground = cv2.imread('../../img/cv2-3.png', cv2.IMREAD_COLOR)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Есть два изображения: логотип EA (товарный знак и все такое), и картинка с фоном (не верьте глазам, фон гораздо больше)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.subplot(121)\n", "plt.imshow(cv2.cvtColor(logo, cv2.COLOR_BGR2RGB))\n", "plt.axis('off');\n", "plt.subplot(122)\n", "plt.imshow(cv2.cvtColor(ground, cv2.COLOR_BGR2RGB))\n", "plt.axis('off');" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rows, cols, channels = logo.shape\n", "#Указываем место размещения логотипа на фоне с учетом размера лого\n", "roi = ground[0:rows, 0:cols]\n", "logo_gray = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY)\n", "# Тут мы для формирования маски указываем, что нижняя граница цвета для маски 220, верхняя 255\n", "# (белый и близкие к нему оттенки серого)\n", "ret, mask = cv2.threshold(logo_gray, 220, 255, cv2.THRESH_BINARY_INV)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.subplot(121)\n", "plt.imshow(logo)\n", "plt.title('Logo', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(122)\n", "plt.imshow(mask, cmap='gray')\n", "plt.title('Mask', fontsize=15)\n", "plt.axis('off');\n", "\n", "\n", "# cv2.imshow('mask', mask)\n", "# cv2.imshow('logo', logo)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Тут тонкий момент: в mask при помощи threshold() мы из рисунка выделили из лого только его бэкграунд (белые элементы оригинального лого), в mask_inv мы выделили только изображение без белого фона" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mask_inv = cv2.bitwise_not(mask)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(mask_inv, cmap='gray')\n", "plt.title('Mask inversed', fontsize=15)\n", "plt.axis('off');\n", "# cv2.imshow('Mask inversed', mask_inv)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Посредством bitwise_and и mask_inv мы вырезаем область логотипа на фоне#Посредс \n", "ground_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)\n", "logo_fg = cv2.bitwise_and(logo, logo, mask=mask)\n", "dst = cv2.add(ground_bg, logo_fg)\n", "ground[0:rows, 0:cols] = dst" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(ground, cv2.COLOR_BGR2RGB))\n", "plt.title('Result', fontsize=15)\n", "plt.axis('off');\n", "\n", "# ground = cv2.resize(ground, (640,480))\n", "# cv2.imshow('add', ground)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Лого более высокого разрешения получилось бы лучше :-)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть шестая\n", "### Исправление затемненного изображения" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Немного продолжим работу с функциями типа **threshold()**. У нас есть абсолютно читаемый скан книжной страницы!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "bookpage = cv2.imread('../../img/cv2-4.jpg')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(bookpage, cv2.COLOR_BGR2RGB))\n", "plt.title('Bookpage', fontsize=15)\n", "plt.axis('off');\n", "\n", "# cv2.imshow('Bookpage', bookpage)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "retval, threshold = cv2.threshold(bookpage, 12, 255, cv2.THRESH_BINARY)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Попробуем применить отсев по яркости пикселей\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(threshold, cv2.COLOR_BGR2RGB))\n", "plt.title('Threshold 12-255', fontsize=15)\n", "plt.axis('off');\n", "\n", "\n", "# cv2.imshow('Bookpage', bookpage)\n", "# cv2.imshow('Threshold', threshold)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Все еще не очень! Попробуем сделать то же самое, но для изображения, преобразованного в оттенки серого." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "grayscaled = cv2.cvtColor(bookpage, cv2.COLOR_BGR2GRAY)\n", "retval, threshold_gray = cv2.threshold(grayscaled, 12, 255, cv2.THRESH_BINARY)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(threshold_gray, cmap='gray')\n", "plt.title('Threshold_gray 12-255', fontsize=15)\n", "plt.axis('off');\n", "\n", "# cv2.imshow('Bookpage', bookpage)\n", "# cv2.imshow('Threshold', threshold)\n", "# cv2.imshow('Threshold Gray', threshold_gray)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как видно из изображения, применение жесткой границы цветов не приносит полезного эффекта. На этот случай мы применим адаптивный фильтр adaptiveThreshold(). Подробнее [тут](https://docs.opencv.org/3.4.0/d7/d1b/group__imgproc__misc.html#ga72b913f352e4a1b1b397736707afcde3) и [здесь](https://docs.opencv.org/3.4.0/d7/d4d/tutorial_py_thresholding.html)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gaus = cv2.adaptiveThreshold(grayscaled, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)\n", "retval, otsu = cv2.threshold(grayscaled, 125, 255, cv2.THRESH_OTSU)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "grayscaledgrayscal = cv2.cvtColor(bookpage, cv2.COLOR_BGR2GRAY)\n", "retval, threshold_gray = cv2.threshold(grayscaled, 12, 255, cv2.THRESH_BINARY)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(gaus, cmap='gray')\n", "plt.title('Результат', fontsize=15)\n", "plt.axis('off');\n", "\n", "# cv2.imshow('Bookpage', bookpage)\n", "# cv2.imshow('Threshold', threshold)\n", "# cv2.imshow('Threshold Gray', threshold_gray)\n", "# cv2.imshow('Threshold Adaptive', gaus)\n", "# cv2.imshow('Threshold Otsu', otsu)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть седьмая\n", "### Bluring\n", "\n", "\n", "Тут бы я посоветовал использовать камеру и что-нибуль красное" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "while True:\n", " _, frame = cap.read()\n", " # Тут необходимо преобразовать изображение в формат HSV\n", " hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)\n", " # Задаем границы красного цвета\n", " lower_red = np.array([150,150,50])\n", " apper_red = np.array([180,255,255])\n", " \n", " # Создаем маску\n", " mask = cv2.inRange(hsv, lower_red, apper_red)\n", " #Применяем маску к изображению\n", " res = cv2.bitwise_and(frame, frame, mask=mask)\n", " \n", " \n", " kernel = np.ones((15,15), np.float32)/255\n", " \n", " #Производим разного рода преобразования\n", " smoothed = cv2.filter2D(res, -1, kernel)\n", " blur = cv2.GaussianBlur(res, (15,15), 0)\n", " median = cv2.medianBlur(res, 15)\n", " bilateral = cv2.bilateralFilter(res, 15, 75,75)\n", " \n", " k = cv2.waitKey(5) & 0xFF\n", " \n", " cv2.imshow('frame', frame)\n", " cv2.imshow('mask', mask)\n", " cv2.imshow('res', res)\n", " cv2.imshow('smoothed', smoothed) \n", " cv2.imshow('blur', blur)\n", " cv2.imshow('median', median)\n", " cv2.imshow('bilateral', bilateral)\n", " #Жмем esc для закрытия окон\n", " if k==27:\n", " break\n", "cv2.destroyAllWindows()\n", "cap.release()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для ленивых, то же самое, но на изображении" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "in_red = cv2.imread('../../img/cv2-5.jpg')\n", " \n", "hsv = cv2.cvtColor(in_red, cv2.COLOR_BGR2HSV)\n", "# Задаем границы красного цвета\n", "lower_red = np.array([150,150,50])\n", "apper_red = np.array([180,255,255])\n", " \n", "# Создаем маску\n", "mask = cv2.inRange(hsv, lower_red, apper_red)\n", "#Применяем маску к изображению\n", "res = cv2.bitwise_and(in_red, in_red, mask=mask)\n", " \n", " \n", "kernel = np.ones((15,15), np.float32)/255\n", " \n", "#Производим разного рода преобразования\n", "smoothed = cv2.filter2D(res, -1, kernel)\n", "blur = cv2.GaussianBlur(res, (15,15), 0)\n", "median = cv2.medianBlur(res, 15)\n", "bilateral = cv2.bilateralFilter(res, 15, 75,75)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.subplot(321)\n", "plt.imshow(cv2.cvtColor(in_red, cv2.COLOR_BGR2RGB))\n", "plt.title('Original', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(322)\n", "plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))\n", "plt.title('res', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(323)\n", "plt.imshow(cv2.cvtColor(smoothed, cv2.COLOR_BGR2RGB))\n", "plt.title('smoothed', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(324)\n", "plt.imshow(cv2.cvtColor(blur, cv2.COLOR_BGR2RGB))\n", "plt.title('blur', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(325)\n", "plt.imshow(cv2.cvtColor(median, cv2.COLOR_BGR2RGB))\n", "plt.title('median', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(326)\n", "plt.imshow(cv2.cvtColor(bilateral, cv2.COLOR_BGR2RGB))\n", "plt.title('bilateral', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Denoising\n", "Смягчение шума с камеры. Осень позоже на предыдущте действия. Тут опять лучше с камерой" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "while True:\n", " _, frame = cap.read()\n", " hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)\n", " \n", " lower_red = np.array([150,150,50])\n", " apper_red = np.array([180,255,255])\n", " \n", " mask = cv2.inRange(hsv, lower_red, apper_red)\n", " \n", " res = cv2.bitwise_and(frame, frame, mask=mask)\n", " \n", " kernel = np.array((5,5), np.uint8) \n", " erosion = cv2.erode(mask, kernel, iterations=1)\n", " dilation = cv2.dilate(mask, kernel, iterations=1)\n", " \n", " opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)\n", " closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)\n", " \n", "\n", " \n", " cv2.imshow('frame', frame)\n", " cv2.imshow('res', res)\n", " cv2.imshow('erosion', erosion)\n", " cv2.imshow('dilation', dilation)\n", " cv2.imshow('opening', opening)\n", " cv2.imshow('closing', closing)\n", " \n", " k = cv2.waitKey(5) & 0xFF\n", " if k==27:\n", " break\n", "cv2.destroyAllWindows()\n", "cap.release()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ленивым!)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hsv = cv2.cvtColor(in_red, cv2.COLOR_BGR2HSV)\n", "\n", "lower_red = np.array([150,150,50])\n", "apper_red = np.array([180,255,255])\n", " \n", "mask = cv2.inRange(hsv, lower_red, apper_red)\n", " \n", "res = cv2.bitwise_and(in_red, in_red, mask=mask)\n", " \n", "kernel = np.array((5,5), np.uint8) \n", "erosion = cv2.erode(mask, kernel, iterations=1)\n", "dilation = cv2.dilate(mask, kernel, iterations=1)\n", " \n", "opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)\n", "closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.subplot(321)\n", "plt.imshow(cv2.cvtColor(in_red, cv2.COLOR_BGR2RGB))\n", "plt.title('Original', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(322)\n", "plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))\n", "plt.title('res', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(323)\n", "plt.imshow(erosion, cmap='gray')\n", "plt.title('erosion', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(324)\n", "plt.imshow(dilation, cmap='gray')\n", "plt.title('dilation', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(325)\n", "plt.imshow(opening, cmap='gray')\n", "plt.title('opening', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(326)\n", "plt.imshow(closing, cmap='gray')\n", "plt.title('closing', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть восьмая\n", "### Распознавание границ\n", "Довольно часто при работе с изображениями есть необходимость убрать лишнюю информацию для упрощения обучения сетей: цвета, некоторая детализация объектов. Для этих целей прекрасно подходит встроенный в OpenCV алгоритм Canny\n", "\n", " - Canny(Image, minVal, maxVal), где minVal, maxVal - параметры алгоритма [за подробностями сюда](https://docs.opencv.org/3.1.0/da/d22/tutorial_py_canny.html)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "while True:\n", " _, frame = cap.read()\n", "\n", " edges = cv2.Canny(frame, 200,200)\n", " cv2.imshow('Edges', edges)\n", " k = cv2.waitKey(5) & 0xFF\n", " # Чтобы закрыть окно нажмите Esc\n", " if k==27:\n", " break\n", "cv2.destroyAllWindows()\n", "cap.release()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "car = cv2.imread('../../img/cv2-6.jpg')\n", "edges = cv2.Canny(car, 200,300)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.subplot(121)\n", "plt.imshow(cv2.cvtColor(car, cv2.COLOR_BGR2RGB))\n", "plt.title('Original', fontsize=15)\n", "plt.axis('off');\n", "plt.subplot(122)\n", "plt.imshow(edges, cmap='gray')\n", "plt.title('Canny', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть девятая\n", "### Поиск по шаблону\n", "Довольно часто стоит задача поиска объектов по шаблону. Для этого будет полезной функция **matchTemplate()**\n", "\n", " - matchTemplate(Image, Template, flag)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Загружаем изображение\n", "img_bgr = cv2.imread('../../img/cv2-7.jpg')\n", "img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Грузим шаблон для поиска# Грузим \n", "template = cv2.imread('../../img/cv2-8.jpg', 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 1,1\n", "plt.imshow(template, cmap='gray')\n", "plt.title('Template', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "w, h = template.shape[::-1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Ищем похожие объекты\n", "res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)\n", "# Ставим границу ссответствия\n", "threshold = 0.78\n", "#Поиск индексов похожих объектов\n", "loc = np.where(res >= threshold)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Тут пригодятся знания, про прорисовку прямоугольников#Тут при \n", "for pt in zip(*loc[::-1]):\n", " cv2.rectangle(img_bgr, pt, (pt[0]+w, pt[1]+h), (0,255,255), 2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');\n", "\n", "# cv2.imshow('detected', img_bgr)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Не идеально, но уже что-то" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Часть десятая\n", "### Сопоставление элементов\n", "В OpenCV осуществлена возможность сопоставления элементов одинаковых объектов на различных картинках" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img1 = cv2.imread('../../img/cv2-9.jpg', 0)\n", "img2 = cv2.imread('../../img/cv2-10.jpg', 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "orb = cv2.ORB_create()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "kp1, des1 = orb.detectAndCompute(img1, None)\n", "kp2, des2 = orb.detectAndCompute(img2, None)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "matches = bf.match(des1, des2)\n", "matches = sorted(matches, key = lambda x: x.distance)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# matches[:10] означает, что нас интересует 10 элементов\n", "img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags = 2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img3, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');\n", "\n", "# cv2.imshow('Corners', img3)\n", "# cv2.waitKey(0)\n", "# cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Самое интересное!!!\n", "## Определение лица и глаз при помощи каскадов Хаара" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Каскады Хаара - довольно древняя методика выявдения фич из изображения, но все еще работает. Для выполнения этой части туториала необходимо пройти [сюда](https://github.com/opencv/opencv/tree/master/data/haarcascades) и скачать 2 файла **'haarcascade_frontalface_default.xml'** и **'haarcascade_eye.xml'**. \n", " Причем скачать не кликнув правой клавишей мыши, а нажать на файл, кликнуть по опции raw и только потом созранить .xml\n", "\n", "\n", "\n", "Лучше используйте камеру!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')\n", "eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "while True:\n", " ret, img = cap.read()\n", " gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", " faces = face_cascade.detectMultiScale(gray, 1.3, 5)\n", " for (x, y, w, h) in faces:\n", " cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0),2)\n", " roi_gray = gray[y:y+h, x:x+w]\n", " roi_color = img[y:y+h, x:x+w]\n", " eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)\n", " for (ex, ey, ew, eh) in eyes:\n", " cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0,255,0), 2)\n", " \n", " cv2.imshow('img', img)\n", " k = cv2.waitKey(30) & 0xff\n", " if k == 27:\n", " break\n", " \n", "cap.release()\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Далее для просмотра" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-12.jpg')\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "#Ищем лица\n", "faces = face_cascade.detectMultiScale(gray, 1.3, 5)\n", "#Мы хотим искать глаза внутри лица\n", "for (x, y, w, h) in faces:\n", " cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0),2)\n", " roi_gray = gray[y:y+h, x:x+w]\n", " roi_color = img[y:y+h, x:x+w]\n", " eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)\n", " for (ex, ey, ew, eh) in eyes:\n", " cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0,255,0), 2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Вроде бы все хорошо, но работает не достаточно хорошо!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-13.jpg')\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "#Ищем лица\n", "faces = face_cascade.detectMultiScale(gray, 1.3, 5)\n", "#Мы хотим искать глаза внутри лица\n", "for (x, y, w, h) in faces:\n", " cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0),2)\n", " roi_gray = gray[y:y+h, x:x+w]\n", " roi_color = img[y:y+h, x:x+w]\n", " eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)\n", " for (ex, ey, ew, eh) in eyes:\n", " cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0,255,0), 2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В общем не совсем то! Поэтому я предлагаю попробовать воспользоваться библиотекой, основанной на нейронных сетях **dlib**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# BONUS DLIB\n", "Для установки пользователям *nix систем лучше воспользоваться [репозиторием](https://github.com/davisking/dlib), устанавливается по инструкции без проблем, правда перед компиляцией нужно поставить libx11-dev (sudo apt-get install libx11-dev).\n", "\n", "С пользователями Windows не все так просто, компилировать не советую ни в коем случае, лучше установите **dlib-19.8.1-cp36-cp36m-win_amd64.whl** [отсюда](https://pypi.org/simple/dlib/), потом *pip install dlib-19.8.1-cp36-cp36m-win_amd64.whl*\n", "\n", "Также надо будет скачать вот этот [файл](http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2) и разархивировать его, потом он будет использоваться в dlib.shape_predictor\n", "\n", "И последнее... Надо установить *imutils* (pip install imutils)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import dlib\n", "import imutils\n", "from imutils import face_utils" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def rect_to_bb(rect):\n", " #Принимает на вход объект dlib, содержащий координаты лиц и возвращает кортеж\n", " x = rect.left()\n", " y = rect.top()\n", " w = rect.right() - x\n", " h = rect.bottom() - y\n", "\n", "\n", " return (x, y, w, h)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def shape_to_np(shape, dtype=\"int\"):\n", "\n", " # возвращает координаты элементов лица\n", " coords = np.zeros((68, 2), dtype=dtype)\n", " for i in range(0, 68):\n", " coords[i] = (shape.part(i).x, shape.part(i).y)\n", "\n", " return coords" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "detector = dlib.get_frontal_face_detector()\n", "predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Обязательно пробовать с камерой" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "# fourcc = cv2.VideoWriter_fourcc(*'XVID')\n", "# out = cv2.VideoWriter('output.avi',fourcc, 10.0, (640,480))\n", "while True:\n", " ret, img = cap.read()\n", " gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", " dets = detector(gray, 1)\n", " for (i, rect) in enumerate(dets):\n", "\n", " shape = predictor(img, rect)\n", " shape = face_utils.shape_to_np(shape)\n", "\n", " # Очертание лица\n", " (x, y, w, h) = face_utils.rect_to_bb(rect)\n", " cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n", "\n", " # Нумировка лица\n", " cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n", " cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n", "\n", " #Прорисовка элементов лица\n", " for (x, y) in shape:\n", " cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n", "\n", " cv2.imshow('img', img)\n", " k = cv2.waitKey(30) & 0xff\n", " if k == 27:\n", " break\n", "cap.release()\n", "# out.release()\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-12.jpg')\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "dets = detector(gray, 1)\n", "for (i, rect) in enumerate(dets):\n", "\n", " shape = predictor(img, rect)\n", " shape = face_utils.shape_to_np(shape)\n", " # Очертание лица\n", " (x, y, w, h) = face_utils.rect_to_bb(rect)\n", " cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n", "\n", " # Нумировка лица\n", " cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n", " cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n", "\n", " #Прорисовка элементов лица\n", " for (x, y) in shape:\n", " cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Так уже лучше, проверим несколько лиц" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-13.jpg')\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "dets = detector(gray, 1)\n", "for (i, rect) in enumerate(dets):\n", "\n", " shape = predictor(img, rect)\n", " shape = face_utils.shape_to_np(shape)\n", " # Очертание лица\n", " (x, y, w, h) = face_utils.rect_to_bb(rect)\n", " cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n", "\n", " # Нумировка лица\n", " cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n", " cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n", "\n", " #Прорисовка элементов лица\n", " for (x, y) in shape:\n", " cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Тоже работает хорошо! Но можно сделать интереснее: точки на лице имеют определенную нумирацию.\n", "\n", "\n", "Следовательно можно сделать еще так!! + закомментил строки записи видео с определением лица" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Опять начинаем с камеры" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cap = cv2.VideoCapture(0)\n", "# fourcc = cv2.VideoWriter_fourcc(*'XVID')\n", "# out = cv2.VideoWriter('output.avi',fourcc, 10.0, (640,480))\n", "while True:\n", " ret, img = cap.read()\n", " gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", " dets = detector(gray, 1)\n", " for (i, rect) in enumerate(dets):\n", " \n", " shape = predictor(img, rect)\n", " shape = face_utils.shape_to_np(shape)\n", "\n", "\n", " (x, y, w, h) = face_utils.rect_to_bb(rect)\n", " cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n", "\n", "\n", " cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n", " cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n", "\n", "\n", " for i, (x, y) in enumerate(shape):\n", " if i < 16:\n", " cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n", " elif i>=17 and i < 27:\n", " cv2.circle(img, (x, y), 2, (0, 255, 0), -1)\n", " elif i >= 27 and i < 36:\n", " cv2.circle(img, (x, y), 2, (255, 0, 0), -1) \n", " elif i>=36 and i < 48:\n", " cv2.circle(img, (x, y), 2, (16, 255, 255), -1) \n", " else:\n", " cv2.circle(img, (x, y), 2, (135, 11, 189), -1)\n", "# out.write(img)\n", " cv2.imshow('img', img)\n", " k = cv2.waitKey(5) & 0xff\n", " if k == 27:\n", " break\n", "cap.release()\n", "# out.release()\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "На картинках" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-12.jpg')\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "dets = detector(gray, 1)\n", "for (i, rect) in enumerate(dets):\n", "\n", " shape = predictor(img, rect)\n", " shape = face_utils.shape_to_np(shape)\n", " # Очертание лица\n", " (x, y, w, h) = face_utils.rect_to_bb(rect)\n", " cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n", "\n", " # Нумировка лица\n", " cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n", " cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n", "\n", " #Прорисовка элементов лица + задаем цвет для каждого элемента\n", " for i, (x, y) in enumerate(shape):\n", " if i < 16:\n", " cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n", " elif i>=17 and i < 27:\n", " cv2.circle(img, (x, y), 2, (0, 255, 0), -1)\n", " elif i >= 27 and i < 36:\n", " cv2.circle(img, (x, y), 2, (255, 0, 0), -1) \n", " elif i>=36 and i < 48:\n", " cv2.circle(img, (x, y), 2, (16, 255, 255), -1) \n", " else:\n", " cv2.circle(img, (x, y), 2, (135, 11, 189), -1)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = cv2.imread('../../img/cv2-13.jpg')\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "dets = detector(gray, 1)\n", "for (i, rect) in enumerate(dets):\n", "\n", " shape = predictor(img, rect)\n", " shape = face_utils.shape_to_np(shape)\n", " # Очертание лица\n", " (x, y, w, h) = face_utils.rect_to_bb(rect)\n", " cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n", "\n", " # Нумировка лица\n", " cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n", " cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n", "\n", " #Прорисовка элементов лица + задаем цвет для каждого элемента\n", " for i, (x, y) in enumerate(shape):\n", " if i < 16:\n", " cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n", " elif i>=17 and i < 27:\n", " cv2.circle(img, (x, y), 2, (0, 255, 0), -1)\n", " elif i >= 27 and i < 36:\n", " cv2.circle(img, (x, y), 2, (255, 0, 0), -1) \n", " elif i>=36 and i < 48:\n", " cv2.circle(img, (x, y), 2, (16, 255, 255), -1) \n", " else:\n", " cv2.circle(img, (x, y), 2, (135, 11, 189), -1)\n", "\n", "plt.rcParams['figure.figsize'] = 18,10\n", "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n", "plt.title('Image', fontsize=15)\n", "plt.axis('off');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Гифка!!!!!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Все! Дошедшим до конца - Спасибо! Надеюсь Вам понравился туториал!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }