From e06af50389f849be0bfe4fa97d39f4519ef2c711 Mon Sep 17 00:00:00 2001 From: adamhrv Date: Fri, 18 Jan 2019 11:00:18 +0100 Subject: change to cli_proc --- .../notebooks/face_analysis/3d_face_plot.ipynb | 1662 +++- .../face_analysis/3d_face_plot_cpdp.ipynb | 2967 +++++++ .../face_analysis/face_recognition_vgg.ipynb | 8111 +++++++++++++++++++- 3 files changed, 12578 insertions(+), 162 deletions(-) create mode 100644 megapixels/notebooks/face_analysis/3d_face_plot_cpdp.ipynb (limited to 'megapixels/notebooks') diff --git a/megapixels/notebooks/face_analysis/3d_face_plot.ipynb b/megapixels/notebooks/face_analysis/3d_face_plot.ipynb index 591b8706..81419941 100644 --- a/megapixels/notebooks/face_analysis/3d_face_plot.ipynb +++ b/megapixels/notebooks/face_analysis/3d_face_plot.ipynb @@ -178,7 +178,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -198,7 +198,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -216,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -225,9 +225,809 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " fig.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(68.0, 201.0) (110.0, 225.0) (-61.021374, 41.419292)\n" + ] + } + ], "source": [ "im = cv.imread(fp_im)\n", "im_rgb = cv.cvtColor(im, cv.COLOR_BGR2RGB)\n", @@ -245,20 +1845,29 @@ "generate_3d_face_plain(im_rgb, lm)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\"RGB:0/51/153 (hexadecimal: 003399)\" for \"PANTONE REFLEX BLUE\" and \"RGB:255/204/0 (hexadecimal: FFCC00)\" for \"PANTONE YELLOW\" for the web palette (the limited 12\n", + "```" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ " # line weight\n", - "def generate_3d_face(lm, fp_out, num_frames=30, dpi=72, stroke_weight=2, size=(480,480),\n", - " mark_size=10, mark_type='.', mark_clr=(0,255,0), fps=10, transparent=False):\n", + "def generate_3d_face(lm, fp_out, num_frames=30, dpi=72, stroke_weight=0, size=(480,480),\n", + " mark_size=2, mark_type='*', mark_clr=(0,255,0), fps=10, transparent=False):\n", " '''Generates 3D plot of face landmarks\n", " '''\n", " # convert opencv BGR numpy image to RGB\n", - " bg_color = '#%02x%02x%02x' % (0,0,0)\n", - " mark_clr = '#%02x%02x%02x' % (0,255,255)\n", + " bg_color = '#%02x%02x%02x' % (0,51,153)\n", + " mark_clr = '#%02x%02x%02x' % (255,204,0)\n", " \n", " # scale to make larger\n", " #lm = np.array([1.2*x,y,z] for x,y,z in list(lm))\n", @@ -293,27 +1902,27 @@ " \n", " # scatter plot the dots\n", " # jaw line\n", - " mark_clr = '#%02x%02x%02x' % (0,255,0) # green\n", + " #mark_clr = '#%02x%02x%02x' % (0,255,0) # green\n", " ax.plot3D(lm[:17,0]*1.2,lm[:17,1], lm[:17,2],\n", " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " # stage-right eyebrow\n", - " mark_clr = '#%02x%02x%02x' % (255,0,0) # green\n", + " #mark_clr = '#%02x%02x%02x' % (255,0,0) # green\n", " ax.plot3D(lm[17:22,0]*1.2,lm[17:22,1],lm[17:22,2],\n", " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " # stage-left eyebrow\n", - " mark_clr = '#%02x%02x%02x' % (255,255,0) # yellow\n", + " #mark_clr = '#%02x%02x%02x' % (255,255,0) # yellow\n", " ax.plot3D(lm[22:27,0]*1.2,lm[22:27,1],lm[22:27,2], \n", " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " # nose ridge\n", - " mark_clr = '#%02x%02x%02x' % (0,0,255) # blue\n", + " #mark_clr = '#%02x%02x%02x' % (0,0,255) # blue\n", " ax.plot3D(lm[27:31,0]*1.2,lm[27:31,1],lm[27:31,2],\n", " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " # nose-bottom\n", - " mark_clr = '#%02x%02x%02x' % (255,0,255) # magenta\n", + " #mark_clr = '#%02x%02x%02x' % (255,0,255) # magenta\n", " ax.plot3D(lm[31:36,0]*1.2,lm[31:36,1],lm[31:36,2],\n", " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " # stage-left eye\n", - " mark_clr = '#%02x%02x%02x' % (0,255,255) # cyan\n", + " #mark_clr = '#%02x%02x%02x' % (0,255,255) # cyan\n", " px, py, pz = lm[36:42,0]*1.2,lm[36:42,1],lm[36:42,2]\n", " px = np.append(px, lm[36,0]*1.2)\n", " py = np.append(py, lm[36,1])\n", @@ -321,7 +1930,7 @@ " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " \n", " # stage-right eye\n", - " mark_clr = '#%02x%02x%02x' % (255,255,255) # white\n", + " #mark_clr = '#%02x%02x%02x' % (255,255,255) # white\n", " px, py, pz = lm[42:48,0]*1.2,lm[42:48,1],lm[42:48,2]\n", " px = np.append(px, lm[42,0]*1.2)\n", " py = np.append(py, lm[42,1])\n", @@ -329,7 +1938,7 @@ " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", " \n", " # mouth\n", - " mark_clr = '#%02x%02x%02x' % (255,125,0) # orange?\n", + " #mark_clr = '#%02x%02x%02x' % (255,125,0) # orange?\n", " px, py, pz = lm[48:,0]*1.2,lm[48:,1],lm[48:,2]\n", " px = np.append(px, lm[48,0]*1.2)\n", " py = np.append(py, lm[48,1])\n", @@ -371,11 +1980,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "time: 0.0018\n", + "Saved file to /home/adam/Downloads/0012_01.gif\n" + ] + } + ], "source": [ "# filepaths\n", "dir_out = '/home/adam/Downloads/'\n", diff --git a/megapixels/notebooks/face_analysis/3d_face_plot_cpdp.ipynb b/megapixels/notebooks/face_analysis/3d_face_plot_cpdp.ipynb new file mode 100644 index 00000000..ba6f97b1 --- /dev/null +++ b/megapixels/notebooks/face_analysis/3d_face_plot_cpdp.ipynb @@ -0,0 +1,2967 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 3D Face Plot\n", + "\n", + "Attenzione visualization" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "import os\n", + "from os.path import join\n", + "import sys\n", + "import time\n", + "from random import randint\n", + "import random\n", + "\n", + "import cv2 as cv\n", + "import numpy as np\n", + "import imutils\n", + "import matplotlib.animation\n", + "%matplotlib notebook\n", + "from glob import glob\n", + "from matplotlib import cbook\n", + "from matplotlib import cm\n", + "#from matplotlib.colors import LightSource\n", + "import face_alignment\n", + "import numpy as np\n", + "\n", + "from mpl_toolkits.mplot3d import Axes3D\n", + "import matplotlib.pyplot as plt\n", + "import mpl_toolkits.mplot3d.axes3d as p3\n", + "from matplotlib import animation\n", + "\n", + "from skimage import io\n", + "from tqdm import tqdm_notebook as tqdm\n", + "from IPython.display import clear_output\n", + "from pathlib import Path\n", + "\n", + "sys.path.append('/work/megapixels_dev/megapixels/')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate random hex colors\n", + "def rhex():\n", + " r = lambda: random.randint(0,255)\n", + " return '#%02X%02X%02X' % (r(), r(), r())" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# init 3d face\n", + "# Run the 3D face alignment on a test image, without CUDA.\n", + "fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._3D, device='cuda:0', flip_input=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "metadata": {}, + "outputs": [], + "source": [ + "fp_im = '/home/adam/Nextcloud/files-ahprojects-com/ahprojects/cpdp_politicians/may/may_1.jpg'\n", + "im = cv.imread(fp_im)" + ] + }, + { + "cell_type": "code", + "execution_count": 160, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_3d_face_plain(im, lm):\n", + " preds = lm\n", + " fig = plt.figure(figsize=plt.figaspect(.5))\n", + " ax = fig.add_subplot(1, 2, 1)\n", + " ax.imshow(im)\n", + " ax.plot(preds[0:17,0],preds[0:17,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[17:22,0],preds[17:22,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[22:27,0],preds[22:27,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[27:31,0],preds[27:31,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[31:36,0],preds[31:36,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[36:42,0],preds[36:42,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[42:48,0],preds[42:48,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[48:60,0],preds[48:60,1],marker='o',markersize=6,linestyle='-',color='w',lw=2)\n", + " ax.plot(preds[60:68,0],preds[60:68,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) \n", + " ax.axis('off')\n", + "\n", + " ax = fig.add_subplot(1, 2, 2, projection='3d')\n", + " surf = ax.scatter(preds[:,0]*1.2,preds[:,1],preds[:,2],c=\"cyan\", alpha=1.0, edgecolor='b')\n", + " ax.plot3D(preds[:17,0]*1.2,preds[:17,1], preds[:17,2], color='blue' )\n", + " ax.plot3D(preds[17:22,0]*1.2,preds[17:22,1],preds[17:22,2], color='blue')\n", + " ax.plot3D(preds[22:27,0]*1.2,preds[22:27,1],preds[22:27,2], color='blue')\n", + " ax.plot3D(preds[27:31,0]*1.2,preds[27:31,1],preds[27:31,2], color='blue')\n", + " ax.plot3D(preds[31:36,0]*1.2,preds[31:36,1],preds[31:36,2], color='blue')\n", + " ax.plot3D(preds[36:42,0]*1.2,preds[36:42,1],preds[36:42,2], color='blue')\n", + " ax.plot3D(preds[42:48,0]*1.2,preds[42:48,1],preds[42:48,2], color='blue')\n", + " ax.plot3D(preds[48:,0]*1.2,preds[48:,1],preds[48:,2], color='blue' )\n", + " \n", + " # pad\n", + " xmm = (np.min(lm[:,0]),np.max(lm[:,0]))\n", + " ymm = (np.min(lm[:,1]),np.max(lm[:,1]))\n", + " zmm = (np.min(lm[:,2]),np.max(lm[:,2]))\n", + " \n", + " print(xmm, ymm, zmm)\n", + "# ax.set_xticks([])\n", + "# ax.set_yticks([])\n", + "# ax.set_zticks([])\n", + " plt.setp( ax.get_xticklabels(), visible=False)\n", + " plt.setp( ax.get_yticklabels(), visible=False)\n", + " #ax.set_xlim(xmm[0]-50, xmm[1]+50)\n", + " #ax.set_ylim(ymm[0]-50, ymm[1]+50)\n", + " #ax.set_ylim(zmm[0]- .1*zmm[0],zmm[1] + .1*zmm[1])\n", + " #ax.set_ylim(103, 275)\n", + " #ax.set_zlim((-100,100))\n", + " ax.view_init(elev=15., azim=135.)\n", + "\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 161, + "metadata": {}, + "outputs": [], + "source": [ + "from app.utils import im_utils" + ] + }, + { + "cell_type": "code", + "execution_count": 162, + "metadata": {}, + "outputs": [], + "source": [ + "im = cv.imread(fp_im)\n", + "im_resized = im_utils.resize(im, width=600, height=600)\n", + "im_rgb = cv.cvtColor(im, cv.COLOR_BGR2RGB)" + ] + }, + { + "cell_type": "code", + "execution_count": 163, + "metadata": {}, + "outputs": [], + "source": [ + "#import dlib\n", + "from app.processors import face_detector" + ] + }, + { + "cell_type": "code", + "execution_count": 164, + "metadata": {}, + "outputs": [], + "source": [ + "#face_detector = face_detector.DetectorDLIBCNN(gpu=0) # -1 for CPU\n", + "face_detector = face_detector.DetectorCVDNN()" + ] + }, + { + "cell_type": "code", + "execution_count": 165, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "detecting face...\n" + ] + }, + { + "ename": "IndexError", + "evalue": "list index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m--------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mst\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mbboxes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mface_detector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdetect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mim_resized\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlargest\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpyramids\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mbbox\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mbboxes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dim\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mim_resized\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" + ] + } + ], + "source": [ + "print('detecting face...')\n", + "st = time.time()\n", + "bboxes = face_detector.detect(im_resized, largest=True, pyramids=3)\n", + "bbox = bboxes[0].to_dim(im_resized.shape[:2][::-1])" + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'tuple' object has no attribute 'to_xyxy'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m--------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbbox\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mbbox\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_xyxy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbbox\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'tuple' object has no attribute 'to_xyxy'" + ] + } + ], + "source": [ + "bbox = bbox.to_xyxy()\n", + "print(bbox)" + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "metadata": {}, + "outputs": [], + "source": [ + "points = fa.get_landmarks_from_image(im_resized, [bbox] )" + ] + }, + { + "cell_type": "code", + "execution_count": 168, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " fig.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(172.0, 328.0) (129.0, 267.0) (-63.546772, 46.46999)\n" + ] + } + ], + "source": [ + "im = cv.imread(fp_im)\n", + "im_rgb = cv.cvtColor(im, cv.COLOR_BGR2RGB)\n", + "lm = fa.get_landmarks(im_rgb)[-1]\n", + "generate_3d_face_plain(im_rgb, lm)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\"RGB:0/51/153 (hexadecimal: 003399)\" for \"PANTONE REFLEX BLUE\" and \"RGB:255/204/0 (hexadecimal: FFCC00)\" for \"PANTONE YELLOW\" for the web palette (the limited 12\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 156, + "metadata": {}, + "outputs": [], + "source": [ + " # line weight\n", + "def generate_3d_face_anim(lm, fp_out, num_frames=30, dpi=72, stroke_weight=0, size=(480,480),\n", + " mark_size=2, mark_type='*', mark_clr=(0,255,0), fps=10, transparent=False):\n", + " '''Generates 3D plot of face landmarks\n", + " '''\n", + " # convert opencv BGR numpy image to RGB\n", + " bg_color = '#%02x%02x%02x' % (0,51,153)\n", + " mark_clr = '#%02x%02x%02x' % (255,204,0)\n", + " \n", + " # scale to make larger\n", + " #lm = np.array([1.2*x,y,z] for x,y,z in list(lm))\n", + " \n", + " # center x,y,z\n", + " xmm = (np.min(lm[:,0]),np.max(lm[:,0]))\n", + " ymm = (np.min(lm[:,1]),np.max(lm[:,1]))\n", + " zmm = (np.min(lm[:,2]),np.max(lm[:,2]))\n", + " \n", + " # make copy of landmarks\n", + " lm_orig = lm.copy()\n", + " xmm = (np.min(lm_orig[:,0]),np.max(lm_orig[:,0]))\n", + " ymm = (np.min(lm_orig[:,1]),np.max(lm_orig[:,1]))\n", + " zmm = (np.min(lm_orig[:,2]),np.max(lm_orig[:,2]))\n", + " \n", + " # swap the y and z components to improve 3d rotation angles for matplotlib\n", + " lm = np.zeros_like(lm_orig).astype(np.uint8)\n", + " for i,p in enumerate(lm_orig):\n", + " x,y,z = p\n", + " lm[i] = np.array([x - xmm[0], z - zmm[0], y - ymm[0]])\n", + " \n", + " # Create plot\n", + " figsize = (size[0]/dpi, size[1]/dpi )\n", + " fig = plt.figure(figsize=figsize, dpi=dpi) # frameon=False\n", + " #fig.set_size_inches(100/100, 1, forward=False)\n", + " fig.tight_layout()\n", + " fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)\n", + " ax = fig.add_subplot(111, projection='3d')\n", + " ax.set_facecolor(bg_color) # background color\n", + " \n", + " xscale, yscale, zscale = (1.2, 1.0, 1.0)\n", + " \n", + " # scatter plot the dots\n", + " # jaw line\n", + " #mark_clr = '#%02x%02x%02x' % (0,255,0) # green\n", + " ax.plot3D(lm[:17,0]*1.2,lm[:17,1], lm[:17,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # stage-right eyebrow\n", + " #mark_clr = '#%02x%02x%02x' % (255,0,0) # green\n", + " ax.plot3D(lm[17:22,0]*1.2,lm[17:22,1],lm[17:22,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # stage-left eyebrow\n", + " #mark_clr = '#%02x%02x%02x' % (255,255,0) # yellow\n", + " ax.plot3D(lm[22:27,0]*1.2,lm[22:27,1],lm[22:27,2], \n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # nose ridge\n", + " #mark_clr = '#%02x%02x%02x' % (0,0,255) # blue\n", + " ax.plot3D(lm[27:31,0]*1.2,lm[27:31,1],lm[27:31,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # nose-bottom\n", + " #mark_clr = '#%02x%02x%02x' % (255,0,255) # magenta\n", + " ax.plot3D(lm[31:36,0]*1.2,lm[31:36,1],lm[31:36,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # stage-left eye\n", + " #mark_clr = '#%02x%02x%02x' % (0,255,255) # cyan\n", + " px, py, pz = lm[36:42,0]*1.2,lm[36:42,1],lm[36:42,2]\n", + " px = np.append(px, lm[36,0]*1.2)\n", + " py = np.append(py, lm[36,1])\n", + " pz = np.append(pz, lm[36,2])\n", + " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " \n", + " # stage-right eye\n", + " #mark_clr = '#%02x%02x%02x' % (255,255,255) # white\n", + " px, py, pz = lm[42:48,0]*1.2,lm[42:48,1],lm[42:48,2]\n", + " px = np.append(px, lm[42,0]*1.2)\n", + " py = np.append(py, lm[42,1])\n", + " pz = np.append(pz, lm[42,2])\n", + " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " \n", + " # mouth\n", + " #mark_clr = '#%02x%02x%02x' % (255,125,0) # orange?\n", + " px, py, pz = lm[48:,0]*1.2,lm[48:,1],lm[48:,2]\n", + " px = np.append(px, lm[48,0]*1.2)\n", + " py = np.append(py, lm[48,1])\n", + " pz = np.append(pz, lm[48,2])\n", + " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr, linewidth=stroke_weight)\n", + " \n", + " rh = '#00ff00' # edge color\n", + " #ax.scatter(lm[:,0]*xscale,lm[:,1]*yscale,lm[:,2]*zscale, c=rh, alpha=1.0, s=35, edgecolor=rh)\n", + " #ax.scatter(lm[:,0]*xscale,lm[:,1]*yscale,lm[:,2]*zscale, c=rh, alpha=1.0, s=1)\n", + " \n", + " # center center x,y,z points\n", + " cx = ((xmm[0] - xmm[1]) // 2) + xmm[1]\n", + " cy = ((ymm[1] - ymm[0]) // 2) + ymm[0]\n", + " cz = ((zmm[1] - zmm[0]) // 2) + zmm[0]\n", + " \n", + " # set initial plot view\n", + " ax.view_init(elev=120., azim=70.)\n", + " \n", + " # remove ticks\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax.set_zticks([])\n", + " \n", + " # remove axis\n", + " ax.set_frame_on(False)\n", + " ax.set_axis_off()\n", + "\n", + " # rotation increments: from 0 to 360 in num_frames\n", + " phi = np.linspace(np.pi/2, 2*np.pi, num_frames)\n", + "\n", + " def update(phi):\n", + " ax.view_init(180,phi*180./np.pi)\n", + " \n", + " ani = matplotlib.animation.FuncAnimation(fig, update, frames=phi)\n", + " savefig_kwargs = {'pad_inches': 0, 'transparent': transparent}\n", + " ani.save(fp_out, writer='imagemagick', fps=fps, savefig_kwargs=savefig_kwargs)\n", + " clear_output()" + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": {}, + "outputs": [], + "source": [ + " # line weight\n", + "def generate_3d_face(lm, fp_out, num_frames=30, dpi=72, stroke_weight=0, size=(480,480),\n", + " mark_size=2, mark_type='*', mark_clr=(0,255,0), fps=10, transparent=False):\n", + " '''Generates 3D plot of face landmarks\n", + " '''\n", + " # convert opencv BGR numpy image to RGB\n", + " bg_color = '#%02x%02x%02x' % (0,51,153)\n", + " mark_clr = '#%02x%02x%02x' % (255,204,0)\n", + " \n", + " # scale to make larger\n", + " #lm = np.array([1.2*x,y,z] for x,y,z in list(lm))\n", + " \n", + " # center x,y,z\n", + " xmm = (np.min(lm[:,0]),np.max(lm[:,0]))\n", + " ymm = (np.min(lm[:,1]),np.max(lm[:,1]))\n", + " zmm = (np.min(lm[:,2]),np.max(lm[:,2]))\n", + " \n", + " # make copy of landmarks\n", + " lm_orig = lm.copy()\n", + " xmm = (np.min(lm_orig[:,0]),np.max(lm_orig[:,0]))\n", + " ymm = (np.min(lm_orig[:,1]),np.max(lm_orig[:,1]))\n", + " zmm = (np.min(lm_orig[:,2]),np.max(lm_orig[:,2]))\n", + " \n", + " # swap the y and z components to improve 3d rotation angles for matplotlib\n", + " lm = np.zeros_like(lm_orig).astype(np.uint8)\n", + " for i,p in enumerate(lm_orig):\n", + " x,y,z = p\n", + " lm[i] = np.array([x - xmm[0], z - zmm[0], y - ymm[0]])\n", + " \n", + " # Create plot\n", + " \n", + " figsize = (size[0]/dpi, size[1]/dpi )\n", + " fig = plt.figure(figsize=figsize, dpi=dpi) # frameon=False\n", + " #fig.set_size_inches(100/100, 1, forward=False)\n", + " fig.tight_layout()\n", + " fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)\n", + " ax = fig.add_subplot(111, projection='3d')\n", + " ax.set_facecolor(bg_color) # background color\n", + " \n", + " xscale, yscale, zscale = (1.2, 1.0, 1.0)\n", + " \n", + " # scatter plot the dots\n", + " # jaw line\n", + " #mark_clr = '#%02x%02x%02x' % (0,255,0) # green\n", + " ax.plot3D(lm[:17,0]*1.2,lm[:17,1], lm[:17,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # stage-right eyebrow\n", + " #mark_clr = '#%02x%02x%02x' % (255,0,0) # green\n", + " ax.plot3D(lm[17:22,0]*1.2,lm[17:22,1],lm[17:22,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # stage-left eyebrow\n", + " #mark_clr = '#%02x%02x%02x' % (255,255,0) # yellow\n", + " ax.plot3D(lm[22:27,0]*1.2,lm[22:27,1],lm[22:27,2], \n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # nose ridge\n", + " #mark_clr = '#%02x%02x%02x' % (0,0,255) # blue\n", + " ax.plot3D(lm[27:31,0]*1.2,lm[27:31,1],lm[27:31,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # nose-bottom\n", + " #mark_clr = '#%02x%02x%02x' % (255,0,255) # magenta\n", + " ax.plot3D(lm[31:36,0]*1.2,lm[31:36,1],lm[31:36,2],\n", + " marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " # stage-left eye\n", + " #mark_clr = '#%02x%02x%02x' % (0,255,255) # cyan\n", + " px, py, pz = lm[36:42,0]*1.2,lm[36:42,1],lm[36:42,2]\n", + " px = np.append(px, lm[36,0]*1.2)\n", + " py = np.append(py, lm[36,1])\n", + " pz = np.append(pz, lm[36,2])\n", + " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " \n", + " # stage-right eye\n", + " #mark_clr = '#%02x%02x%02x' % (255,255,255) # white\n", + " px, py, pz = lm[42:48,0]*1.2,lm[42:48,1],lm[42:48,2]\n", + " px = np.append(px, lm[42,0]*1.2)\n", + " py = np.append(py, lm[42,1])\n", + " pz = np.append(pz, lm[42,2])\n", + " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr,linewidth=stroke_weight)\n", + " \n", + " # mouth\n", + " #mark_clr = '#%02x%02x%02x' % (255,125,0) # orange?\n", + " px, py, pz = lm[48:,0]*1.2,lm[48:,1],lm[48:,2]\n", + " px = np.append(px, lm[48,0]*1.2)\n", + " py = np.append(py, lm[48,1])\n", + " pz = np.append(pz, lm[48,2])\n", + " ax.plot3D(px, py, pz, marker=mark_type, markersize=mark_size, color=mark_clr, linewidth=stroke_weight)\n", + " \n", + " rh = '#%02x%02x%02x' % (255,224,10) # edge color\n", + " ax.scatter(lm[:,0]*xscale,lm[:,1]*yscale,lm[:,2]*zscale, c=rh, alpha=1.0, s=35, edgecolor=rh)\n", + " ax.scatter(lm[:,0]*xscale,lm[:,1]*yscale,lm[:,2]*zscale, c=rh, alpha=1.0, s=1)\n", + " \n", + " # center center x,y,z points\n", + " cx = ((xmm[0] - xmm[1]) // 2) + xmm[1]\n", + " cy = ((ymm[1] - ymm[0]) // 2) + ymm[0]\n", + " cz = ((zmm[1] - zmm[0]) // 2) + zmm[0]\n", + " \n", + " # set initial plot view\n", + " ax.view_init(elev=180., azim=90.)\n", + " \n", + " # remove ticks\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax.set_zticks([])\n", + " \n", + " # remove axis\n", + " ax.set_frame_on(False)\n", + " ax.set_axis_off()\n", + "\n", + " # rotation increments: from 0 to 360 in num_frames\n", + " phi = np.linspace(np.pi/2, 2*np.pi, num_frames)\n", + "\n", + " plt.savefig(fp_out)\n", + " fig.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 172, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " fig.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('