{
"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
}