-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Open
Description
I am working on Raspberry Pi 5 and OpenFace. I have succed to modify my docker images so that it is working on my Raspberry Pi.
My spec on my Raspberry Pi 5 :
OS: Debian GNU/Linux 12 (bookworm)
Kernel: 6.6.74+rpt-rpi-2712
CPU: Cortex-A76 (4) @ 71% 2400.0000 1500.0000MHz
Memory: 1474MiB / 8048MiB
Here is my Dockerfile for my Raspberry Pi. I changed :
- the image from Ubuntu from Ubuntu:18.04 to arm64v8/ubuntu:18.04
- In the section
== Building OpenFace ==I modify the cmake with adding some flags :
CXX=g++-8 CC=gcc-8 cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D OpenBLAS_INCLUDE_DIR=/usr/include \
-D OpenBLAS_LIB=/usr/lib/aarch64-linux-gnu/libopenblas.so \
-G Ninja .. \
-DCMAKE_CXX_FLAGS="-march=armv8-a" \
-DCMAKE_C_FLAGS="-march=armv8-a" && \
I mostly did this with ChatGPT : here is the prompt for explaination : https://chatgpt.com/share/6787e7eb-3a74-8010-865a-a659b565ea1d
# ==================== Building Model Layer ===========================
# This is a little trick to improve caching and minimize rebuild time
# and bandwidth. Note that RUN commands only cache-miss if the prior layers
# miss, or the dockerfile changes prior to this step.
# To update these patch files, be sure to run build with --no-cache
FROM alpine as model_data
RUN apk --no-cache --update-cache add wget
WORKDIR /data/patch_experts
RUN wget -q https://www.dropbox.com/s/7na5qsjzz8yfoer/cen_patches_0.25_of.dat &&\
wget -q https://www.dropbox.com/s/k7bj804cyiu474t/cen_patches_0.35_of.dat &&\
wget -q https://www.dropbox.com/s/ixt4vkbmxgab1iu/cen_patches_0.50_of.dat &&\
wget -q https://www.dropbox.com/s/2t5t1sdpshzfhpj/cen_patches_1.00_of.dat
## ==================== Install Ubuntu Base libs ===========================
## This will be our base image for OpenFace, and also the base for the compiler
## image. We only need packages which are linked
FROM arm64v8/ubuntu:18.04 as ubuntu_base
LABEL maintainer="Michael McDermott <[email protected]>"
ARG DEBIAN_FRONTEND=noninteractive
# todo: minimize this even more
RUN apt-get update -qq &&\
apt-get install -qq curl &&\
apt-get install -qq --no-install-recommends \
libopenblas-dev liblapack-dev \
libavcodec-dev libavformat-dev libswscale-dev \
libtbb2 libtbb-dev libjpeg-dev \
libpng-dev libtiff-dev &&\
rm -rfv /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y libopenblas-dev
RUN echo OUI
RUN ldconfig -p | grep openblas
## ==================== Build-time dependency libs ======================
## This will build and install opencv and dlib into an additional dummy
## directory, /root/diff, so we can later copy in these artifacts,
## minimizing docker layer size
## Protip: ninja is faster than `make -j` and less likely to lock up system
FROM ubuntu_base as cv_deps
WORKDIR /root/build-dep
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qq && apt-get install -qq -y \
cmake ninja-build pkg-config build-essential checkinstall\
g++-8 &&\
rm -rf /var/lib/apt/lists/* &&\
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
## llvm clang-3.7 libc++-dev libc++abi-dev \
## ==================== Building dlib ===========================
RUN curl http://dlib.net/files/dlib-19.13.tar.bz2 -LO &&\
tar xf dlib-19.13.tar.bz2 && \
rm dlib-19.13.tar.bz2 &&\
mv dlib-19.13 dlib &&\
mkdir -p dlib/build &&\
cd dlib/build &&\
cmake -DCMAKE_BUILD_TYPE=Release -G Ninja .. &&\
ninja && \
ninja install && \
DESTDIR=/root/diff ninja install &&\
ldconfig
## ==================== Building OpenCV ======================
ENV OPENCV_VERSION=4.1.0
RUN curl https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.tar.gz -LO &&\
tar xf ${OPENCV_VERSION}.tar.gz && \
rm ${OPENCV_VERSION}.tar.gz &&\
mv opencv-${OPENCV_VERSION} opencv && \
mkdir -p opencv/build && \
cd opencv/build && \
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_TBB=ON -D WITH_CUDA=OFF \
-DWITH_QT=OFF -DWITH_GTK=OFF\
-G Ninja .. && \
ninja && \
ninja install &&\
DESTDIR=/root/diff ninja install
## ==================== Building OpenFace ===========================
FROM cv_deps as openface
WORKDIR /root/openface
COPY ./ ./
COPY --from=model_data /data/patch_experts/* \
/root/openface/lib/local/LandmarkDetector/model/patch_experts/
RUN mkdir -p build && cd build && \
CXX=g++-8 CC=gcc-8 cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D OpenBLAS_INCLUDE_DIR=/usr/include \
-D OpenBLAS_LIB=/usr/lib/aarch64-linux-gnu/libopenblas.so \
-G Ninja .. \
-DCMAKE_CXX_FLAGS="-march=armv8-a" \
-DCMAKE_C_FLAGS="-march=armv8-a" && \
ninja && \
DESTDIR=/root/diff ninja install
## ==================== Streamline container ===========================
## Clean up - start fresh and only copy in necessary stuff
## This shrinks the image from ~8 GB to ~1.6 GB
FROM ubuntu_base as final
WORKDIR /root
# Copy in only necessary libraries
COPY --from=openface /root/diff /
# Since we "imported" the build artifacts, we need to reconfigure ld
RUN ldconfig
## ==================== Python ===========================
WORKDIR /root/openface/opengaze
COPY ./opengaze .
# Install Python and FastAPI dependencies
RUN apt-get update && apt-get install -y python3 python3-pip && \
pip3 install -r requirements.txt
# pip3 install --no-cache-dir fastapi uvicorn==0.16.0
# # Copy FastAPI application
# COPY main.py /root/main.py
# # Expose FastAPI port
EXPOSE 8000I also had to modify the CMakeLists.txt :
from
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_LESS 8.0)
MESSAGE(FATAL_ERROR "Need a 8.0 or newer GCC compiler. Current GCC: ${GCC_VERSION}")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse -msse2 -msse3")
endif ()
endif ()to
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_LESS 8.0)
MESSAGE(FATAL_ERROR "Need a 8.0 or newer GCC compiler. Current GCC: ${GCC_VERSION}")
else ()
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse -msse2 -msse3")
endif ()
endif ()
endif ()I also add at the end a python app with fastapi where I can send a photo to my docker with HTTP.
from fastapi import FastAPI, File, UploadFile, HTTPException
import uvicorn
import os
import subprocess
import csv
import json
app = FastAPI()
# Ensure the /tmp/openface directory exists
os.makedirs("/tmp/openface", exist_ok=True)
@app.get("/start-record/")
async def start_record() :
command = []
return
@app.post("/upload-photo/")
async def upload_photo(file: UploadFile = File(...)):
# Define the path where the file will be saved
file_path = os.path.join("/tmp/openface", file.filename.split("/")[-1])
try:
# Save the file to the specified path
with open(file_path, "wb") as buffer:
buffer.write(await file.read())
# Check if the file was saved correctly
if not(os.path.exists(file_path)):
# return {"message": f"Photo '{file.filename}' was correctly downloaded and saved to /tmp/openface."}
raise HTTPException(status_code=500, detail="Failed to save the photo.")
# TODO faire le subprocess, importer pandas et renvoyer la réponse sous forme de json ou csv c'est mpoins lourd
command = ["FeatureExtraction", "-gaze", "-f", file_path, "-of", "/tmp/openface/output.csv"]
# command = f"FeatureExtraction -gaze -f {file_path} -of /tmp/openface/output.csv"
# print(command)
subprocess.check_call(command)
# print("ok")
csv_path = "/tmp/openface/output.csv"
# Read the CSV file
with open(csv_path, 'r') as csvfile:
reader = csv.DictReader(
csvfile, delimiter=',', skipinitialspace=True)
# Filter out the rows that have no gaze data
out = [{"face_id": row["face_id"],
"confidence": row["confidence"],
"gaze_angle_x": row["gaze_angle_x"],
"gaze_angle_y": row["gaze_angle_y"]
}
for row in reader]
# print(out)
# use gaze_data = list(reader) to get all the rows
gaze_data = list(out)
# Convert the gaze data to JSON string
gaze_data_json = json.loads(json.dumps(gaze_data))
return gaze_data_json
# return f"FeatureExtraction -gaze -f {file_path} -of /tmp/openface/output.csv"
except Exception as e:
print(e)
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)I am not an expert on Docker so I am looking for improvement to My Dockerfile.
pluto0203
Metadata
Metadata
Assignees
Labels
No labels