{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Face tracking in OpenCV\n![](https://github.com/imadtoubal/face-tracking-in-opencv/raw/master/assets/preview.gif)"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Haar-cascade XML classifier\n!wget -P /kaggle/working/ https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls ../input/deepfake-detection-challenge","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n\nfiles =[]\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        files.append(os.path.join(dirname, filename))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Imports"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"## Imports\nimport cv2\nimport numpy as np \nimport math","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Helper functions"},{"metadata":{"trusted":true},"cell_type":"code","source":"def lerp(a, b, p):\n    '''Linear interpretation in 1D\n    Args:\n        a (int): point A\n        b (int): point B\n        c (float): percentage\n\n    Returns:\n        int: position\n    '''\n    return math.floor(a + (b - a) * p)\n\n# TODO: add docs\ndef image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):\n    '''Resizes Image respecitng aspect ratio (source: https://stackoverflow.com/a/44659589)\n    Args:\n        \n    Returns:\n        \n    '''\n    # initialize the dimensions of the image to be resized and\n    # grab the image size\n    dim = None\n    (h, w) = image.shape[:2]\n\n    # if both the width and height are None, then return the\n    # original image\n    if width is None and height is None:\n        return image\n\n    # check to see if the width is None\n    if width is None:\n        # calculate the ratio of the height and construct the\n        # dimensions\n        r = height / float(h)\n        dim = (int(w * r), height)\n\n    # otherwise, the height is None\n    else:\n        # calculate the ratio of the width and construct the\n        # dimensions\n        r = width / float(w)\n        dim = (width, int(h * r))\n\n    # resize the image\n    resized = cv2.resize(image, dim, interpolation = inter)\n\n    # return the resized image\n    return resized","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Parameters\n* `margin`: margin around the face (in px)\n* `threshold`: tracking threshold (to prevent huge jumps in \"phantom\" face detections)\n    $$ p_i = \\{\\matrix{p_{i-1},& if \\text{dist}(p_i, p_{i-1}) > \\theta \\\\ \\text{lerp}(p_{i}, p_{i-1}, v_{lerp}), & otherwise} $$\n    where:\n    * $\\theta$: threshold\n    * $i$: frame number"},{"metadata":{},"cell_type":"markdown","source":""},{"metadata":{"trusted":true},"cell_type":"code","source":"path_to_video = files[1]\nmargin = 80\nthreshold = 10","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"files[1]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Tracking!"},{"metadata":{"trusted":true},"cell_type":"code","source":"cap = cv2.VideoCapture(path_to_video)\nface_cascade = cv2.CascadeClassifier('/kaggle/working/haarcascade_frontalface_default.xml')\n\nfirst_frame = True\nx = -1\nwhile(True):\n    # Capture frame-by-frame\n    ret, frame = cap.read()\n\n    # Our operations on the frame come here\n    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n\n    gray_re = image_resize(gray, width=400)\n    \n    height, width = gray.shape\n    height_re, width_re = gray_re.shape\n\n    ratio = height / height_re\n\n    # Detect the faces\n    faces = face_cascade.detectMultiScale(gray_re, 1.1, 5)\n\n    # Draw the rectangle around each face\n    maxArea = 0\n    minDist = np.inf\n    \n    \n    for (_x, _y, _w, _h) in faces:\n        # cv2.rectangle(gray, (_x, _y), (x+fw, y+fh), (255, 0, 0), 2)\n        if  first_frame and _w*_h > maxArea:\n            x, y, w, h = _x, _y, _w, _h\n    \n        elif (_x - _xp) ** 2 + (_y - _yp) ** 2 < minDist:\n            x, y, w, h = _x, _y, _w, _h\n            minDist = (_x - _xp) ** 2 + (_y - _yp) ** 2  \n            \n        maxArea = w*h\n        _xp = x\n        _yp = y\n\n\n    #If one or more faces are found, draw a rectangle around the\n    #largest face present in the picture\n    if maxArea > 0 :\n        if minDist < threshold:\n            # add margin\n            x = max(math.floor(x * ratio - margin), 0)\n            y = max(math.floor(y * ratio - margin), 0)\n        if first_frame:\n            fw = math.floor(w * ratio + 2 * margin)\n            fh = math.floor(h * ratio + 2 * margin) \n        \n    # get rectangle\n    if not first_frame:\n        lerp_p = .3\n        if minDist < threshold:\n            x, y = lerp(xp, x, lerp_p), lerp(yp, y, lerp_p)\n        else:\n            x, y = xp, yp\n        \n\n    if x >= 0:\n        patch = gray[y:y+fh, x:x+fw]\n        # Convert patch to feature vector\n\n        xp, yp = x, y\n    \n    # Display the resulting frame\n    try:\n        print(x, y, w, h)\n#         cv2.imshow('frame', patch)\n        # cv2.imshow('frame', gray)\n    except:\n        print('finding face')\n    if cv2.waitKey(1) & 0xFF == ord('q'):\n        break\n\n    # check if faces were found\n    if (x >= 0):\n        first_frame = False\n    \n\n\n# When everything done, release the capture\ncap.release()\ncv2.destroyAllWindows()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":1}