{"cells":[{"metadata":{},"cell_type":"markdown","source":"# NOTE\n### Please DO read this markdown carefully.\nThis Kernal just the starter Kernal and only for beginners who aim to find the starting path in the video analysis using Deep Learning. It is a mixture of ideas from different public Kernals but aims to give the complete solution to the beginners who wander off to find out the complex code about what is happening in the kernals that have been written by the very proficient programmers.\n\nI can not say everything again and again in every Kernal and I would feel bad about the fact if I get to know that some beginner is still unable to understand what is going on. So before you start here, even if you have some knowledge of NN and every other thing,\n\n### Please do [check out this kernal](https://www.kaggle.com/deshwalmahesh/bengali-ai-complete-beginner-tutorial-95-acc) about Keras, NN, Images and much more before you start because a lot of very very useful links have been given in the links there for beginners."},{"metadata":{},"cell_type":"markdown","source":"# Problem Statement\nIf you haven't been to the kernal suggest, please go there and check the links before you start.\n\nFor this problem we have been provided a dataset of videos that have been altered using [Deep Fakes](https://www.youtube.com/watch?v=gLoI9hAX9dw). Deep Fakes are alterded data either audio,video or image data by using Deep Neural Networks mostly (Encoder - Decoder) Structure. So what basically is Encoder- Decoder and how it works? To give this answer, let us suppose we have 2 two players one is very advanced in skills but lacks in physical aspect and the one is just the opposite. So what if in far future we are able to mutate the people by desire? Then I hope we are able to give the features to one another. This is what exactly Features and Deep Fakes works.\n\nTo give you the best idea about Features, we take example of different fruits. Each and evey fruit has different shape, size, weight, color and so on BUT...if we have enough different Fruits, can we classify or give similarities? Yes , we can. This is where features come into play. Even if fruits are not completely related, we can still group them somwhow, say by taste, origin, continent or something else.\n\nIn terms of images or videos (videos are just images playing with your brain), they resemble Fruits and our model ```just finds out the features``` somehow. It happens by the use of Encoders and Decoders. We train out computers to extract the features from two different things with the use of Encoders say A and B. Then when there are features given by the Encoders, we use the features of A to feed it to the Decoder of B. Complex? No. It is just like the mutation. We just swapped (one side to be precise) the features in the Encoded dimensions. It just just like Messi and Ronaldo getting trained under some strict conditions so either Ronaldo gets the agility and dribbling of Messi or Messi getting the physical aspect and power of Ronaldo. "},{"metadata":{},"cell_type":"markdown","source":"# Approach\nIn this tutorial we just want to start the journey in finding the Fakes by using a CNN model which I'll commit on the next version. This notebook describes every part BEFORE the Training about how to go till training.\nThe idea is to extract the Frames from the videos, then detect Faces (because only faces are altered) and then combine some faces to Train as Fake or Real. Simple!!!!"},{"metadata":{"trusted":true},"cell_type":"code","source":"pip install mtcnn","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"MTCNN is an implementation of the [Research Paper](https://arxiv.org/abs/1604.02878) published on using a [Convolution Neural Network](https://www.youtube.com/watch?v=FmpDIaiMIeA) to detect Faces given in an image. It is  pretrained model to detect faces with a degree of confidence such as 0.9 or 90% confidence that there is a face. It can return multiple faces with each face's coordinates in the image array where it has found a face. You can plot a rectangle aroung the box or just crop the image to see the cropped face which is later in the tutorial. It also returns the eyes and nose coordinates. More about the use of MTCNN can be learned either from the [official documentation of the library](https://pypi.org/project/mtcnn/) or from [this website](https://machinelearningmastery.com/how-to-perform-face-detection-with-classical-and-deep-learning-methods-in-python-with-keras/). These are very good resources. Please do go through them."},{"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)\nimport matplotlib.pyplot as plt\nimport cv2\nfrom IPython.display import HTML\nfrom base64 import b64encode\nfrom tqdm import tqdm\nfrom skimage.transform import resize\nfrom skimage.metrics import structural_similarity\nfrom keras.layers import Dense,Dropout,Conv2D,Conv3D,LSTM,Embedding,BatchNormalization,Input,LeakyReLU,ELU,\\\nGlobalMaxPooling2D,GlobalMaxPooling3D\nfrom keras.optimizers import Adam\nfrom keras.callbacks import ReduceLROnPlateau,ModelCheckpoint,EarlyStopping\nfrom keras.applications.inception_v3 import InceptionV3,preprocess_input\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom mtcnn.mtcnn import MTCNN\nfrom matplotlib.patches import Rectangle\nfrom tensorflow import random as tf_rnd\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\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"INPUT_PATH = '/kaggle/input/deepfake-detection-challenge/'\nTEST_PATH = 'test_videos/'\nTRAIN_PATH = 'train_sample_videos/'\nPAD = 50 # padding for the copped face so that a little bit of around of face can be visible\nSIZE = 128\nBATCH_SIZE = 32\nCASCADE_PATH = cv2.data.haarcascades # with this line, you do not need to download the XML files from web. Later.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"SEED = 13\nnp.random.seed(SEED) # set random seed to get reproducible results\ntf_rnd.set_seed(SEED) # tensor flow randomness remover\nplt.style.use('seaborn-whitegrid') # just some fancy un useful stuff","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Getting Files and EDA"},{"metadata":{"trusted":true},"cell_type":"code","source":"# iterate through the directory to get all the file names and save them as a DataFrame. No need to pay attention to\ntrain_files = []\next = []\nfor _, _, filenames in os.walk(INPUT_PATH+TRAIN_PATH): # iterate within the directory\n    for filename in filenames: # get all the files inside directory\n        splitted = filename.split('.') # split the files as a . such .exe, .deb, .txt, .csv\n        train_files.append(splitted[0]) # first part is name of file\n        ext.append(splitted[1]) # second one is extension type\n\nfiles_df = pd.DataFrame({'filename':train_files, 'type':ext})\nfiles_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"files_df.shape # 401 files","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"files_df['type'].value_counts() # 400 mp4 files and 1 json file","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"meta_df = pd.read_json(INPUT_PATH+TRAIN_PATH+'metadata.json') # We have Transpose the Df\nmeta_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"meta_df = meta_df.T\nmeta_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"meta_df.reset_index(inplace=True) # set the index as 0,1,2....\nmeta_df.rename(columns={'index':'names'},inplace=True) \n# rename the column which was first index but is currently named as 'index'\nmeta_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"meta_df.isna().sum() # 77 original files are missing","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"meta_df['label'].value_counts().plot(kind='pie',autopct='%1.1f%%',label='Real Vs Fake')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"80% files are FAKE and only 20% are REAL"},{"metadata":{},"cell_type":"markdown","source":"# Extracting and Processing Features"},{"metadata":{"trusted":true},"cell_type":"code","source":"class VideoFeatures():\n    '''\n    Class for working with features related to videos such getting frames, plotting frames, playing videos etc\n    '''\n    \n    def get_properties(self,filepath):\n        '''\n        returns the properties of a video file\n        args:\n            filepath: path of the video file\n        out:\n            num_frames: total number of frames in a video\n            frame_rate: frames played per second\n        '''\n        cap = cv2.VideoCapture(filepath)\n        num_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)\n        frame_rate = cap.get(cv2.CAP_PROP_FPS)\n        return num_frames, frame_rate\n        \n    \n    def get_frames(self,filepath,first_only=False, show=False):\n        '''\n        method for getting the frames from a video file\n        args: \n            filepath: exact path of the video file\n            first_only: whether to detect the first frame only or all of the frames\n        out:\n            frame: first frame in form of numpy array \n        '''\n    \n        cap = cv2.VideoCapture(filepath) \n        # captures the video. Think of it as if life is a movie so we ask the method to focus on patricular event\n        # that is our video in this case. It will concentrate on the video\n        \n        \n        if not first_only: # whether to get all the frames or not\n            all_frames = []\n            while(cap.isOpened()): # as long as all the frames have been traversed\n                ret, frame = cap.read()\n                # capture the frame. Again, if life is a movie, this function acts as camera\n                \n                if ret==True:\n                    all_frames.append(frame)\n                    if cv2.waitKey(1) & 0xFF == ord('q'): # break in between by pressing the key given\n                        break\n                else:\n                    break\n                    \n        else:\n            ret, all_frames = cap.read()\n            if show:\n                plt.imshow(cv2.cvtColor(all_frames, cv2.COLOR_BGR2RGB))\n                # plot the image but the cv2 changes thge ordering to Blue,Green,Red than RGB so it converts the \n                # metrices to proper ordering\n        \n        \n        cap.release()\n        # release whatever was held by the method for say, resources and the video itself\n        return all_frames\n        \n        \n    def play_video(self, filepath):\n        '''\n        Method that uses the HTML inside Python to put a code in the Kernal so that there is a HTML page\n        like code where the supported video can be played\n        args:\n            filepath: path of the file which you want to play\n        '''\n        \n        video = open(filepath,'rb').read() # read video file\n        dec_data = \"data:video/mp4;base64,\" + b64encode(video).decode()\n        # decode the video data in form of a sting. Funny! Video is now a string\n        \n        return HTML(\"\"\"<video width=350 controls><source src=\"%s\" type=\"video/mp4\"></video>\"\"\" % dec_data)\n        # embed the string as <video> tag in HTML Kernal so that it can be understood by HTML and can be played \n    \n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## HaarCascade"},{"metadata":{},"cell_type":"markdown","source":"Below is what was very new to me once I saw it. It is called HaarCascade. A HaarCascade is basically a classifier which is used to detect the object for which it has been trained for, from the source. So source is our image and it detects Faces and different features of faces like smile, side profile, eyes etc. HaarCascade is basically a XML file where there is a code written inside it by very tech savvy coders so that we do not have to do it again and again. It will detect the structure from the file. Each XML is trained for a different feature. As this is the first commit, I'll just keep it simple and when tuning the model, we will have tweak lots of parameters.\nTo get insight about the working of HaarCascades I recommend you [this insightful blog](http://www.willberger.org/cascade-haar-explained/)"},{"metadata":{"trusted":true},"cell_type":"code","source":"class FrameProcessor():\n    '''\n    class to process the images such as resizing, changing colors, detect faces from frames etc\n    '''\n\n    def __init__(self):\n        '''\n        Constructor where the data from OpenCV is used directly to find the Faces. \n        '''\n        self.face_cascade=cv2.CascadeClassifier(CASCADE_PATH+'haarcascade_frontalface_default.xml')\n        # XML file which has code for Frontal Face\n        self.eye_cascade=cv2.CascadeClassifier(CASCADE_PATH+'haarcascade_eye.xml')\n        # it extracts eyes\n        \n    \n    def detect_face_eye(self,img,scaleFactor=1.3, minNeighbors=5, minSize=(50,50),get_cropped_face=False):\n        '''\n        Method to detect face and eye from the image\n        args:\n            img: image in the form of numpy array pixels\n            scaleFactor: scale the image in proportion. indicates how much the image size is \n                         reduced at each image scale. A lower value uses a smaller step for downscaling.\n            minNeighbors: int, number of Neighbors to select from. You know that the pixels at eyes are correlated \n                            with surrounding with pixels around the eye but not the 1000 pixels away at feet\n            minSize: tuple. Smaller the face in the image, it is best to adjust the minSize value lower\n            get_zoomed_face: Bin. Wheter to return the zoomed face only rather than the full image\n        out:\n            image with detected faces\n        '''\n        \n        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n        # convert image to Grayscale to make better use of resources\n        \n        faces = self.face_cascade.detectMultiScale(gray,scaleFactor=scaleFactor,\n                                                   minNeighbors=minNeighbors,\n                                                  minSize=minSize)\n        # Return the face rectangle from the image\n        \n        if get_cropped_face:\n            for (x,y,w,h) in faces:\n                cropped_img = img[y-PAD:y+h+PAD, x-PAD:x+w+PAD] # slice the array to-from where the face(s) have been found\n            return cropped_img\n            \n        \n        for (x,y,w,h) in faces:\n            img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),3)\n            # draw a rectangle around the face with (0,0,255= Blue) color\n        \n            eyes = self.eye_cascade.detectMultiScale(gray,minSize=(minSize[0]//2,minSize[1]//2),\n                                                     minNeighbors=minNeighbors)\n            # eyes will always be inside a front profile. So it will reduce the TruePositive of finding other eyes\n            \n            for (ex,ey,ew,eh) in eyes:\n                cv2.rectangle(img,(ex,ey),(ex+ew,ey+eh),(0,255,0),3)\n                # draw a rectangle around the eyes with Green color (0,255,0)\n        \n        return img\n        \n        \n        \n    def plot_frame(self,img):\n        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n        \n    \n    def resize_frame(self,frame,res_w=256,preserve_aspect=True,anti_aliasing=True):\n        '''\n        resize the images according to desired width and height\n        param:\n            frame: numpy image pixels array\n            rew_w: resize width default to 256\n            preserve_aspect: preserve the aspect ratio in the frame. If not, the output will be a square matrix\n            anti_aliasing: whether to apply or not\n        out:\n            resized numpy array\n        '''\n        \n        res_h = res_w\n        if preserve_aspect: # protect the aspect ratio even after the resizing\n            aspect_ratio = frame.shape[0]/frame.shape[1]  # get aspect ratio\n            res_h = res_w*aspect_ratio # set resulting height according to ratio\n            \n        return resize(frame,(res_h,res_w),anti_aliasing=anti_aliasing)\n        \n    \n    def frames_similarity(self,frames,full=True, multichannel=True):\n        '''\n        Find the similarity between the consecutive frames based on a common scale\n        param:\n            frames: list of numpy pixel arrays\n            full: whether to return full  structural similarity \n            multichannel: Bool. IF the images are Grayscale or RGB\n            with_resize: Bool. Default True. whether to resize the frames before finding similarity\n        '''\n        sim_scores = []\n        for i in tqdm(range(1, len(frames))): # tqdm shows a progress bar\n            curr_frame = frames[i]\n            prev_frame = frames[i-1]\n\n            if curr_frame.shape[0] != prev_frame.shape[0]: \n                # different sizes of same images will be seen as two different images so we have to deal with this\n                # so just resize the bigger image as the smaller one\n                if  curr_frame.shape[0] > prev_frame.shape[0]:\n                    curr_frame = curr_frame[:prev_frame.shape[0], :prev_frame.shape[0], :]\n                else:\n                    prev_frame = prev_frame[:curr_frame.shape[0], :curr_frame.shape[0], :]\n\n\n            mean_ssim,_ = structural_similarity(curr_frame, prev_frame, full=full,multichannel=multichannel)\n            # get mean similarity scores of the images \n            sim_scores.append(mean_ssim)\n        \n        return sim_scores\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vf =  VideoFeatures() # instantiate both the classes to use later\nfp = FrameProcessor()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vf.get_properties(INPUT_PATH+TRAIN_PATH+'cwrtyzndpx.mp4') # get properties of video","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"300 frames on total with 30 FPS"},{"metadata":{"trusted":true},"cell_type":"code","source":"vf.play_video(INPUT_PATH+TRAIN_PATH+'cwrtyzndpx.mp4') # see the magic of HTML with Python","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = vf.get_frames(INPUT_PATH+TRAIN_PATH+'cwrtyzndpx.mp4',first_only=True,show=True)\n# get first frame from image and display it too","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"detected_face = fp.detect_face_eye(img,minNeighbors=5,scaleFactor=1.3,minSize=(50,50))\n# detect the faces form the image. Tweak the parameters to get the face if ace is not found\n# it is difficult to tweak the parameters for every image and this is one the reasons there is need of MTCNN\nfp.plot_frame(detected_face)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"frames = vf.get_frames(INPUT_PATH+TRAIN_PATH+'cwrtyzndpx.mp4') # get all the frames\nfp.plot_frame(frames[54]) # plot a random frame from the frames ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# plt.plot(range(1,len(frames)),fp.frames_similarity(frames))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There is a huge dip in the frames similarity many times. It means either the whole picture has changes or there is some other issue. You can get the desired frame to look what has happened so that you can have better understanding of what and how it is happening."},{"metadata":{"trusted":true},"cell_type":"code","source":"zoomed_face = fp.detect_face_eye(frames[13],get_cropped_face=True,) # get cropped image array which has pixels of face\nfp.plot_frame(zoomed_face)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## MTCNN"},{"metadata":{"trusted":true},"cell_type":"code","source":"class MTCNNWrapper():\n    '''\n    Detect and show faces using MTCNN\n    '''\n    \n    def get_face(self,mtcnn_obj,img):\n        '''\n        method to get face from an image\n        args:\n            img: image as numpy array\n        out:\n            rect: coordinates of rectangle(s) for multiple face(s)\n        '''\n        faces = mtcnn_obj.detect_faces(img)\n        # dectect_faces returns a list of dicts of all the faces\n        x, y, width, height = faces[0]['box'] \n        # faces return a list of dicts so [0] means first faces out of all the faces\n        return faces\n    \n    \n    def show_faces(self,img):\n        '''\n        Show faces on the original image as red boxes\n        args:\n            img: image as numpy array\n        out: \n            None: plot the original image with faces inside red boxes\n        '''\n        \n        faces = self.get_face(img)   # get the list of faces dict\n        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # plot the image and next modify the image\n        ax = plt.gca() # get the context for drawing boxes\n        # Get the current Axes instance on the current figure matching the given keyword args, or create one\n\n        for result in faces: # faces returns a list of dicts of all the faces\n            x, y, width, height = result['box'] # get coordinates of each box found\n            rect = Rectangle((x, y), width, height, fill=False, color='red') # form rectangle at the given coordinates\n            ax.add_patch(rect) # add that box to the axis/ current image\n        plt.show() # plot the extra rectangles\n        \n        \n    def get_cropped(self,img,show_only=False):\n        '''\n        get the cropped image only from detected face\n        args:\n            img: numpy image array\n            show_only: whether to return cropped array or just plot the image. Default False\n        out:\n            numpy array of cropped image at the face\n        '''\n        faces = self.get_face(img)\n        x, y, width, height = faces[0]['box'] # first face. Will add logic later to find the most significant face\n        if show_only:\n            plt.imshow(cv2.cvtColor(img[y-PAD:y+height+PAD, x-PAD:x+width+PAD], cv2.COLOR_BGR2RGB))\n            return None\n        else:\n            return img[y-PAD:y+height+PAD, x-PAD:x+width+PAD]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = VideoFeatures().get_frames(INPUT_PATH+TRAIN_PATH+'cwrtyzndpx.mp4',first_only=True)\nmt_wrapper = MTCNNWrapper()\nmt_wrapper.show_faces(img)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mt_wrapper.get_cropped(img,show_only=True) # show only. it does not return anything","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Saving Data to Disk\nWe are going to extract features (frames) from the Video file one by one, Extract Faces from MTCNN and then get the cropped face to save the images in Fake, Real directory. "},{"metadata":{"trusted":true},"cell_type":"code","source":"#os.makedirs('train_1') # run this line of code only once.\nimport shutil \n# shutil.rmtree('train_1') # just in case you want to delete the directory","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"x = '''\nmt_wrapper = MTCNNWrapper()\nframes_names = []\nframes_labels = []\nfor i in tqdm(range(meta_df.shape[0])):\n    filepath = INPUT_PATH+TRAIN_PATH+meta_df['names'][i]\n    label = meta_df['label'][i]\n    cap = cv2.VideoCapture(filepath)\n    framerate = cap.get(5) # 5 means to get the framerarate, 3 means get width, 4 for height and so on\n    # https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_gui/py_video_display/py_video_display.html\n    # https://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get\n    count=0\n    while(cap.isOpened()):\n        frame_no = cap.get(1) # get frame number of current frame\n        ret,frame = cap.read()\n        if ret!=True:\n            break\n        if count%10==0:\n            filename ='train_1/' + filepath.split('/')[-1].split('.')[-2]+\"_%d.jpg\" % count\n            #frame = mt_wrapper.get_cropped(img)\n            cv2.imwrite(filename, frame)\n            frames_names.append(filename)\n            frames_labels.append(label)\n        count+=1\n\nimages_csv = pd.DataFrame({'image_name':frames_names,'label':frames_labels})\nimages_csv.to_csv('video_faces.csv')\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images_df = pd.read_csv('video_faces.csv')\n#images_df[] = images_df['label'].apply(lambda x: x.split('/')[-1])\nimages_df.drop('Unnamed: 0',axis=1,inplace=True)\nimages_df['label'] = images_df['label'].apply(lambda x: x.split('/')[-1])\nimages_df.head()\nimages_df.to_csv('video_faces.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Implementation\nImplementation is coming soon but the idea is to apply the given method for the very basic starting point model as:\n1. Get the videos one by one\n2. Extract all the ```N``` frames\n3. Extract all the ```F``` faces from the frames and discrads the remaining ```\n4. Develop an algorithm to detect only the significant face as there is only 1 altered face and there can be more than one face in the frame\n5. Get ```f``` faces from each set of ```F``` frames and label those as Fake or Real\n6. Resize these faces to save computational power and time\n6. Train a very basic CNN\n7. Predict using the steps 1-5 in continuation\n\nNote: You can select ```significant``` frames to select ```k``` frames to save resources that will be used to find faces for all the ```N``` frames. Discard remaining ```N-k``` frames."}],"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}