1

I am currently trying to program an application that splits a video into its individual frames and then finds the faces on the video and extracts them as .jpg. I split the Project into multiple files, app.py which is responsible for GUI and so on and extractor.py which does the work.

I thought you would be able to import a file with:

import extractor

And then run it like this:

extractor()

Apparently, this doesnt seem to work. I also tried making the entire extractor script a function and then calling the function, but this also doesnt work.

app.py:

import extractor
extractor()

extractor.py:

import cv2
import os
import face_recognition
from PIL import Image
import multiprocessing

try:
    if not os.path.exists('frames'):
        os.makedirs('frames')
except OSError:
    print('Error: Creating directory of frames')

try:
    if not os.path.exists('faces'):
        os.makedirs('faces')
except OSError:
    print('Error: Creating directory of faces')

def extract_frames(video_file_path):
    currentFrame_extract = 1
    video_capture = cv2.VideoCapture(video_file_path)

    while(True):
        ret, frame = video_capture.read()
        if ret == False:
            break
        name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
        print(f"Extracting Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
        cv2.imwrite(name, frame)
        currentFrame_extract += 1

    video_capture.release()
    cv2.destroyAllWindows()
    return currentFrame_extract

def find_faces_a(a):
    i = 0
    currentFrame = 1

    while (True):

        if a > currentFrame:

            image = face_recognition.load_image_file(f"data/frame_{currentFrame}.jpg")
            face_locations = face_recognition.face_locations(image)

            if len(face_locations) >= 1:
                top, right, bottom, left = face_locations[0]

                face_image = image[top:bottom, left:right]
                pil_image = Image.fromarray(face_image)
                pil_image.save(f"faces/face_{currentFrame}.jpg".format(i))
                print(f"Found a face at Frame_{currentFrame}, exporting it as Face_{currentFrame}.jpg")

            currentFrame += 4
        else:
            break

def find_faces_b(a):
    i = 0
    currentFrame = 2

    while (True):

        if a > currentFrame:

            image = face_recognition.load_image_file(f"data/frame_{currentFrame}.jpg")
            face_locations = face_recognition.face_locations(image)

            if len(face_locations) >= 1:
                top, right, bottom, left = face_locations[0]

                face_image = image[top:bottom, left:right]
                pil_image = Image.fromarray(face_image)
                pil_image.save(f"faces/face_{currentFrame}.jpg".format(i))
                print(f"Found a face at Frame_{currentFrame}, exporting it as Face_{currentFrame}.jpg")

            currentFrame += 4
        else:
            break

def find_faces_c(a):
    i = 0
    currentFrame = 3

    while (True):

        if a > currentFrame:

            image = face_recognition.load_image_file(f"data/frame_{currentFrame}.jpg")
            face_locations = face_recognition.face_locations(image)

            if len(face_locations) >= 1:
                top, right, bottom, left = face_locations[0]

                face_image = image[top:bottom, left:right]
                pil_image = Image.fromarray(face_image)
                pil_image.save(f"faces/face_{currentFrame}.jpg".format(i))
                print(f"Found a face at Frame_{currentFrame}, exporting it as Face_{currentFrame}.jpg")

            currentFrame += 4
        else:
            break

def find_faces_d(a):
    i = 0
    currentFrame = 4

    while (True):

        if a > currentFrame:

            image = face_recognition.load_image_file(f"data/frame_{currentFrame}.jpg")
            face_locations = face_recognition.face_locations(image)

            if len(face_locations) >= 1:
                top, right, bottom, left = face_locations[0]

                face_image = image[top:bottom, left:right]
                pil_image = Image.fromarray(face_image)
                pil_image.save(f"faces/face_{currentFrame}.jpg".format(i))
                print(f"Found a face at Frame_{currentFrame}, exporting it as Face_{currentFrame}.jpg")

            currentFrame += 4
        else:
            break

if __name__ == "__main__":

    video_file_path = "Video_3.mp4"
    currentFrame_extract = extract_frames(video_file_path)

    currentFrame_extract = [currentFrame_extract]
    p1 = multiprocessing.Process(target=find_faces_a, args=(currentFrame_extract))
    p2 = multiprocessing.Process(target=find_faces_b, args=(currentFrame_extract))
    p3 = multiprocessing.Process(target=find_faces_c, args=(currentFrame_extract))
    p4 = multiprocessing.Process(target=find_faces_d, args=(currentFrame_extract))

    p1.start()
    p2.start()
    p3.start()
    p4.start()

    p1.join()
    p2.join()
    p3.join()
    p4.join()

    print("Frame extraction and alignment finished successfully.")

I receive the error: TypeError: 'module' object is not callable. If I do it like some of you have suggested or as in the question marked as "similar", the script will start but it still wont work and only create the folders.

marcr
  • 9
  • 3
  • Add full traceback. – shaik moeed Jul 09 '19 at 14:48
  • When you import the module, everything before the `if __name__ == '__main__'` block will be evaluated. So all those functions will be defined and added to the `extractor` namespace. Try `print(dir(namespace))` to see what I mean. You could call `extractor.find_faces_a(some_object_here)` after you import the module... – duhaime Jul 09 '19 at 14:50
  • What exactly do you mean with full traceback? – marcr Jul 09 '19 at 14:50
  • Hi duhaime, thank you for your answer. I'm aware that I have all these individual functions, but how can I combine them into one, so that when I call extractor() it justs executes the entire script? The problem is that the "if __name__ == "__main__" is essential for the script and it should all run just as if I would run the file manually. – marcr Jul 09 '19 at 14:51
  • Possible duplicate of [In Python, can I call the main() of an imported module?](https://stackoverflow.com/questions/14500183/in-python-can-i-call-the-main-of-an-imported-module) – Corentin Limier Jul 09 '19 at 14:58

2 Answers2

0

You can run extractor.py by converting if __name__ == "__main__": to a new function def extractor() and importing the module:

import extractor;
extractor.extractor();

You can also only import a specific name (in our case extractor() function) by using the following variant of import:

from extractor import extractor;
extractor();

Check out this link (https://repl.it/repls/MeaslyMerrySymbol) where I have done a sample import similar to your files.

Mayur Dhurpate
  • 1,112
  • 4
  • 16
  • 34
  • Hi, I tried doing that. It does create the folders and execute the start of the extractor script, however it doesnt extract the images neither search for faces. – marcr Jul 09 '19 at 15:17
  • So it runs without throwing any error per se? If it throws an error, pasting the full error message (5-10 red lines) (also called traceback) would give us more insights on what might be happening. – Mayur Dhurpate Jul 09 '19 at 15:25
  • Yep, just runs through and say "Process finished with exit code 0". However it doesnt really work and I think the all the functions dont get executed. It gets as far as creating the folders, nothing more happens. – marcr Jul 09 '19 at 15:28
  • Any Idea? I think the problem is that the __name__ == __main__ doesnt start and with that the functions on top dont get started either. I dont really understand what __name__ == __main__ even does, but when I leave it away the script doesnt work. – marcr Jul 09 '19 at 15:43
0

Encapsulate your extractor functionality in another file, like extractor_impl. Then put everything in a function in this file:

def extract(video_file_path)
    currentFrame_extract = extract_frames(video_file_path)

    currentFrame_extract = [currentFrame_extract]
    p1 = multiprocessing.Process(target=find_faces_a, args=(currentFrame_extract))
    p2 = multiprocessing.Process(target=find_faces_b, args=(currentFrame_extract))
    p3 = multiprocessing.Process(target=find_faces_c, args=(currentFrame_extract))
    p4 = multiprocessing.Process(target=find_faces_d, args=(currentFrame_extract))

    p1.start()
    p2.start()
    p3.start()
    p4.start()

    p1.join()
    p2.join()
    p3.join()
    p4.join()

    print("Frame extraction and alignment finished successfully.")

You can then import the extractor_impl file from your extractor file and just call this function, but you can import and call it from other files as well.

Frank Buss
  • 714
  • 7
  • 14
  • I tried that, but unfortunatly some of the parts of the script are just left out when I do it this way. It creates the folders, but doesnt extract any images. – marcr Jul 09 '19 at 15:17