{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "face_swap.ipynb", "provenance": [], "collapsed_sections": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "W9-ev1iPK7W6", "outputId": "9f5fca67-4a75-4f22-e3a3-442126c248fc" }, "source": [ "from google.colab import drive\n", "drive.mount('/content/drive')" ], "execution_count": 1, "outputs": [ { "output_type": "stream", "text": [ "Mounted at /content/drive\n" ], "name": "stdout" } ] }, { "cell_type": "code", "metadata": { "id": "U1Y9wtCRT-FV" }, "source": [ "import cv2\n", "import numpy as np\n", "import dlib\n", "from google.colab.patches import cv2_imshow\n", "\n", "img = cv2.imread(\"/content/drive/MyDrive/Colab Notebooks/images/charles-etoroma-95UF6LXe-Lo-unsplash.jpg\")\n", "img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "mask = np.zeros_like(img_gray)\n", "\n", "face_detector = dlib.get_frontal_face_detector()\n", "points_detector = dlib.shape_predictor(\"/content/drive/MyDrive/weights/shape_predictor_68_face_landmarks.dat\")\n", "faces = face_detector(img_gray)\n", "\n", "for face in faces:\n", " points_predict1 = points_detector(img_gray, face)\n", " points_list = []\n", " for n in range(0, 68):\n", " x = points_predict1.part(n).x\n", " y = points_predict1.part(n).y\n", " points_list+=[(x, y)]\n", "\n", " points = np.array(points_list, np.int32)\n", " convexhull = cv2.convexHull(points)\n", " cv2.fillConvexPoly(mask, convexhull, 255)\n", "face_image_1 = cv2.bitwise_and(img, img, mask=mask)\n", "\n", "cv2_imshow(img)\n", "cv2_imshow(face_image_1)\n", "cv2.waitKey(0)\n", "cv2.destroyAllWindows()" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "n3e3DPuTWRw1" }, "source": [ "rect = cv2.boundingRect(convexhull)\n", "subdiv = cv2.Subdiv2D(rect)\n", "subdiv.insert(points_list)\n", "triangles = subdiv.getTriangleList()\n", "triangles = np.array(triangles, dtype=np.int32)\n", "for t in triangles:\n", " pt1 = (t[0], t[1])\n", " pt2 = (t[2], t[3])\n", " pt3 = (t[4], t[5])\n", " " ], "execution_count": 3, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "6mCWfqy5hTbY" }, "source": [ "\n", "\n", "def extract_index_nparray(nparray):\n", " index = None\n", " for num in nparray[0]:\n", " index = num\n", " break\n", " return index" ], "execution_count": 4, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "_Z1j19LBhH6e", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "9fb295fc-bf5e-42b2-b7c4-6656f3dbeda0" }, "source": [ "rect = cv2.boundingRect(convexhull)\n", "subdiv = cv2.Subdiv2D(rect)\n", "subdiv.insert(points_list)\n", "triangles = subdiv.getTriangleList()\n", "triangles = np.array(triangles, dtype=np.int32)\n", "\n", "triangles_id = []\n", "def index_nparray(nparray):\n", " index = None\n", " for num in nparray[0]:\n", " index = num\n", " break\n", " return index\n", "for t in triangles:\n", " pt1 = (t[0], t[1])\n", " pt2 = (t[2], t[3])\n", " pt3 = (t[4], t[5])\n", "\n", " id_pt1 = np.where((points == pt1).all(axis=1))\n", " id_pt1 = index_nparray(id_pt1)\n", " id_pt2 = np.where((points == pt2).all(axis=1))\n", " id_pt2 = index_nparray(id_pt2)\n", " id_pt3 = np.where((points == pt3).all(axis=1))\n", " id_pt3 = index_nparray(id_pt3)\n", "\n", " if id_pt1 is not None and id_pt2 is not None and id_pt3 is not None:\n", " triangle = [id_pt1, id_pt2, id_pt3]\n", " triangles_id.append(triangle)\n", "print(triangles_id)" ], "execution_count": 5, "outputs": [ { "output_type": "stream", "text": [ "[[39, 20, 21], [20, 39, 38], [1, 0, 31], [65, 55, 56], [55, 65, 53], [2, 1, 49], [67, 62, 66], [62, 67, 61], [3, 2, 48], [58, 7, 6], [7, 58, 57], [4, 3, 48], [8, 57, 56], [57, 8, 7], [5, 4, 59], [51, 33, 52], [33, 51, 50], [6, 5, 59], [53, 14, 54], [14, 53, 15], [31, 0, 41], [9, 8, 56], [10, 9, 56], [42, 47, 35], [47, 42, 43], [11, 10, 55], [30, 42, 35], [42, 30, 29], [12, 11, 55], [27, 21, 22], [21, 27, 39], [13, 12, 54], [40, 39, 31], [39, 40, 38], [14, 13, 54], [37, 18, 19], [18, 37, 17], [20, 38, 19], [16, 15, 45], [36, 0, 17], [0, 36, 41], [17, 37, 36], [37, 19, 38], [19, 23, 20], [23, 19, 24], [42, 29, 28], [20, 23, 22], [42, 27, 22], [27, 42, 28], [21, 20, 22], [42, 23, 43], [23, 42, 22], [43, 23, 24], [43, 24, 44], [24, 25, 44], [26, 16, 45], [25, 26, 44], [30, 35, 34], [31, 39, 30], [27, 28, 39], [30, 33, 32], [33, 30, 34], [1, 31, 49], [28, 29, 39], [34, 52, 33], [52, 34, 35], [59, 4, 48], [29, 30, 39], [62, 61, 51], [52, 62, 51], [62, 52, 63], [31, 30, 32], [48, 2, 49], [53, 65, 63], [31, 32, 50], [55, 10, 56], [32, 33, 50], [12, 55, 54], [15, 53, 35], [15, 35, 45], [45, 35, 46], [37, 41, 36], [41, 37, 40], [37, 38, 40], [40, 31, 41], [44, 47, 43], [47, 44, 46], [26, 45, 44], [44, 45, 46], [46, 35, 47], [49, 31, 50], [48, 49, 60], [49, 50, 61], [50, 51, 61], [52, 35, 53], [52, 53, 63], [53, 54, 64], [54, 55, 64], [55, 53, 64], [67, 60, 49], [60, 67, 59], [56, 57, 66], [58, 6, 59], [49, 61, 67], [57, 58, 66], [58, 59, 67], [59, 48, 60], [58, 67, 66], [66, 65, 56], [65, 66, 62], [62, 63, 65]]\n" ], "name": "stdout" } ] }, { "cell_type": "code", "metadata": { "id": "U5UZmPDI4L8M" }, "source": [ "img2 = cv2.imread(\"/content/drive/MyDrive/Colab Notebooks/images/pedram-normohamadian-MrETbReEVjw-unsplash.jpg\")\n", "\n", "img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)\n", "\n", "faces2 = face_detector(img2_gray)\n", "for face in faces2:\n", " points_predict2 = points_detector(img2_gray, face)\n", " points_list2 = []\n", " for n in range(0, 68):\n", " x = points_predict2.part(n).x\n", " y = points_predict2.part(n).y\n", " points_list2.append((x, y))\n", " points2 = np.array(points_list2, np.int32)\n", " convexhull2 = cv2.convexHull(points2)\n", "\n" ], "execution_count": 6, "outputs": [] }, { "cell_type": "code", "metadata": { "id": "IrLwcSXfR-cw" }, "source": [ "img2_new_face = np.zeros_like(img2, np.uint8)\n", "for triangle_index in triangles_id:\n", "\n", " tr1_pt1 = points_list[triangle_index[0]]\n", " tr1_pt2 = points_list[triangle_index[1]]\n", " tr1_pt3 = points_list[triangle_index[2]]\n", " triangle1 = np.array([tr1_pt1, tr1_pt2, tr1_pt3], np.int32)\n", " rect1 = cv2.boundingRect(triangle1)\n", " (x1, y1, w1, h1) = rect1\n", " cropped_triangle = img[y1: y1 + h1, x1: x1 + w1]\n", " cropped_tr1_mask = np.zeros((h1, w1), np.uint8)\n", " points = np.array([[tr1_pt1[0] - x1, tr1_pt1[1] - y1],\n", " [tr1_pt2[0] - x1, tr1_pt2[1] - y1],\n", " [tr1_pt3[0] - x1, tr1_pt3[1] - y1]], np.int32)\n", " cv2.fillConvexPoly(cropped_tr1_mask, points, 255)\n", " cropped_triangle = cv2.bitwise_and(cropped_triangle, cropped_triangle,\n", " mask=cropped_tr1_mask)\n", "\n", " tr2_pt1 = points_list2[triangle_index[0]]\n", " tr2_pt2 = points_list2[triangle_index[1]]\n", " tr2_pt3 = points_list2[triangle_index[2]]\n", " triangle2 = np.array([tr2_pt1, tr2_pt2, tr2_pt3], np.int32)\n", " rect2 = cv2.boundingRect(triangle2)\n", " (x2, y2, w2, h2) = rect2\n", " cropped_triangle2 = img2[y2: y2 + h2, x2: x2 + w2]\n", " cropped_tr2_mask = np.zeros((h2, w2), np.uint8)\n", " points2 = np.array([[tr2_pt1[0] - x2, tr2_pt1[1] - y2],\n", " [tr2_pt2[0] - x2, tr2_pt2[1] - y2],\n", " [tr2_pt3[0] - x2, tr2_pt3[1] - y2]], np.int32)\n", " cv2.fillConvexPoly(cropped_tr2_mask, points2, 255)\n", " cropped_triangle2 = cv2.bitwise_and(cropped_triangle2, cropped_triangle2,\n", " mask=cropped_tr2_mask)\n", "\n", " points = np.float32(points)\n", " points2 = np.float32(points2)\n", " M = cv2.getAffineTransform(points, points2)\n", " warped_triangle = cv2.warpAffine(cropped_triangle, M, (w2, h2))\n", " warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle, mask=cropped_tr2_mask)\n", "\n", "\n", " img2_new_face_rect_area = img2_new_face[y2: y2 + h2, x2: x2 + w2]\n", " img2_new_face_rect_area_gray = cv2.cvtColor(img2_new_face_rect_area, cv2.COLOR_BGR2GRAY)\n", " \n", " _, mask_triangles_designed = cv2.threshold(img2_new_face_rect_area_gray, 1, 255, cv2.THRESH_BINARY_INV)\n", " warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle, mask=mask_triangles_designed)\n", "\n", " img2_new_face_rect_area = cv2.add(img2_new_face_rect_area, warped_triangle)\n", " img2_new_face[y2: y2 + h2, x2: x2 + w2] = img2_new_face_rect_area\n", "\n", "\n", "img2_face_mask = np.zeros_like(img2_gray)\n", "\n", "img2_head_mask = cv2.fillConvexPoly(img2_face_mask, convexhull2, 255)\n", "\n", "img2_face_mask = cv2.bitwise_not(img2_head_mask)\n", "\n", "img2_noface = cv2.bitwise_and(img2, img2, mask=img2_face_mask)\n", "no_face = cv2.resize(img2_noface, (int(img2_noface.shape[1]*0.5), int(img2_noface.shape[0]*0.5)), interpolation = cv2.INTER_AREA)\n", "\n", "result = cv2.add(img2_noface, img2_new_face)\n", "\n", "\n", "\n", "(x3, y3, w3, h3) = cv2.boundingRect(convexhull2)\n", "center_face2 = (int((x3 + x3 + w3) / 2), int((y3 + y3 + h3) / 2))\n", "\n", "seamlessclone = cv2.seamlessClone(result, img2, img2_head_mask, center_face2, cv2.MONOCHROME_TRANSFER)\n", "\n", "cv2_imshow(img2)\n", "cv2_imshow(seamlessclone)\n" ], "execution_count": null, "outputs": [] } ] }