Fictionarry / ER-NeRF

[ICCV'23] Efficient Region-Aware Neural Radiance Fields for High-Fidelity Talking Portrait Synthesis
https://fictionarry.github.io/ER-NeRF/
MIT License
1.07k stars 137 forks source link

OpenFace FeatureExtraction Docker Image #166

Open SanBingYouYong opened 2 months ago

SanBingYouYong commented 2 months ago

OpenFace provided a docker image to use and I extended based on it with conda and flask to provide an api access to get au.csv from videos.

The image is available on aliyun registry: docker pull registry.cn-hangzhou.aliyuncs.com/sanbingyouyong/openface_extract_flask:latest

The request can be sent using the following Python codes:

with open(video_full_path, 'rb') as f:
    files = {'video': f}
    form = {'video_name': video_name}
    response = requests.post(openface_service_url, files=files, data=form)

And the response is sent with send_file(output_file_path, as_attachment=True) and you can save the csv file like this:

with open(os.path.join(DATA_DIR, f'{video_name}/au.csv'), 'w') as f:
        f.write(response.content.decode('utf-8'))

If people are interested I can also post the Dockerfile (I need to make one then since I commit the image from my working container) and also the flask .py file that runs the service. Or as a PR, idk.

References: OpenFace docker image from its wiki Why we need to set OPENBLAS_NUM_THREADS

ezyfzy commented 1 month ago

@SanBingYouYong this docker image works fine, will it be possible for you to share the dockerfile?

SanBingYouYong commented 1 month ago

@SanBingYouYong this docker image works fine, will it be possible for you to share the dockerfile?

I currently have network difficulties testing dockerfiles (basically chances that they fail half way during building due to network errors) but here's the python file (and a shell script) that I put in the image, so basically you need to modify the OpenFace docker image to support running a flask application:

The Python file openface_extract.py:

from flask import Flask, request, send_file
import subprocess
import os

'''
copied into openface_auto as openface_extract.py
'''

app = Flask(__name__)

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))

@app.route('/process_video', methods=['POST'])
def process_video():
    # 检查是否有文件在请求中
    if 'video' not in request.files:
        return "No video part", 400
    if 'video_name' not in request.form:
        return "No video name", 400

    video = request.files['video']
    video_name = request.form['video_name']

    # 如果用户没有选择文件,浏览器也会发送一个空的文件名
    if video.filename == '':
        return "No selected video", 400

    if video:
        # 保存文件到此目录
        file_path = os.path.join(ROOT_DIR, f"{video_name}.mp4")
        video.save(file_path)

        # command = ['build/bin/FeatureExtraction', '-f', file_path]  # not easy to know when does it finish
        command = ["./run_extraction.sh", file_path]  # remember to chmod +x

        # 执行命令
        try:
            # execute shell script
            subprocess.Popen(command, cwd=ROOT_DIR).wait()

            # check for output in ./processed/video_name.csv
            output_file_path = os.path.join(ROOT_DIR, 'processed', f"{video_name}.csv")
            if not os.path.exists(output_file_path):
                return f"Error processing video: output file not found", 500
        except subprocess.CalledProcessError as e:
            return f"Error processing video: {e}", 500

        response = send_file(output_file_path, as_attachment=True)

        # 删除原始文件
        os.remove(file_path)
        # delete processed file
        # basically video.avi  video.csv  video.hog  video_aligned  video_of_details.txt
        the_file_list = [
            f"{video_name}.avi",
            f"{video_name}.csv",
            f"{video_name}.hog",
            f"{video_name}_of_details.txt"
        ]
        the_dir = f"{video_name}_aligned"  # this is a directory! 
        for file in os.listdir(os.path.join(ROOT_DIR, 'processed')):
            if file in the_file_list:
                os.remove(os.path.join(ROOT_DIR, 'processed', file))
            if file == the_dir:
                os.system(f"rm -rf {os.path.join(ROOT_DIR, 'processed', file)}")

        # 返回处理后的文件
        return response

    return "No video to process", 400

if __name__ == '__main__':
    if not os.environ.get("OPENBLAS_NUM_THREADS"):
        os.environ["OPENBLAS_NUM_THREADS"] = "10"  # credit: github issue
    app.run(host='0.0.0.0', port=8601)

The shell script that it executes (so to track task status): run_extraction.sh:

#! /bin/bash

if [ $# -eq 0 ]; then
     echo "Usage: $0 <video_file>"
     exit 1
fi

VIDEO_FILE=$1

build/bin/FeatureExtraction -f $VIDEO_FILE
ezyfzy commented 1 month ago

@SanBingYouYong Thanks for the quick response. Can you suggest the way to add python3.10 in this image, I was only able to add python3.5 not above that.

SanBingYouYong commented 1 month ago

@SanBingYouYong Thanks for the quick response. Can you suggest the way to add python3.10 in this image, I was only able to add python3.5 not above that.

IIRC I went with miniconda3 and installed flask and python=3.10 right in the base environment. Try with the following commands to get conda working in docker containers:

ENV PATH="/root/miniconda3/bin:${PATH}"

# SHELL ["conda", "run", "-n", "base", "/bin/bash", "-c"]  # if you want to use RUN to install new packages in the ENV
ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "base"]
CMD ["python", "openface_extract.py"]

There might have been some other dependency issues but I'm not sure.

ezyfzy commented 1 month ago

Thanks a lot for your work on extending the openface image. It works now.

ezyfzy commented 1 month ago

Sharing my docker file here, so that others facing issue extending or using openface with latest versions of linux can use.

Dockerfile.txt