From fa6b55aed51b73a30a534b77a6fb9914b5d0a204 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 26 Jun 2024 17:13:19 +0200 Subject: [PATCH] Copied initial tools. --- Dockerfile | 42 ++++++++++++++++++++++++ README.md | 18 ++++++++++ pyproject.toml | 3 ++ run_container.sh | 11 +++++++ scripts/draw_utils.py | 46 ++++++++++++++++++++++++++ scripts/utils_2d_pose.py | 71 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+) create mode 100644 Dockerfile create mode 100644 pyproject.toml create mode 100644 run_container.sh create mode 100644 scripts/draw_utils.py create mode 100644 scripts/utils_2d_pose.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..827b003 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +FROM nvcr.io/nvidia/tensorflow:22.08-tf2-py3 + +ARG DEBIAN_FRONTEND=noninteractive +ENV LANG C.UTF-8 +ENV LC_ALL C.UTF-8 +WORKDIR / + +RUN apt-get update && apt-get install -y --no-install-recommends feh +RUN apt-get update && apt-get install -y --no-install-recommends python3-opencv +RUN pip uninstall -y opencv-python && pip install --no-cache "opencv-python<4.3" + +# Show matplotlib images +RUN apt-get update && apt-get install -y --no-install-recommends python3-tk + +# Update pip to allow installation of skelda in editable mode +RUN pip3 install --upgrade --no-cache-dir pip + +# Install pytorch +RUN pip3 install --upgrade --no-cache-dir "torch<2.0" +RUN pip3 install --upgrade --no-cache-dir "torchvision<0.15" + +# Install MMPose +RUN pip3 install --upgrade --no-cache-dir openmim +RUN mim install mmengine +RUN mim install "mmpose>=1.1.0" +# Fix an error when importing mmpose +RUN pip3 install --upgrade --no-cache-dir numpy scipy +RUN git clone --depth=1 --branch=main https://github.com/open-mmlab/mmpose.git + +# Download pretrained model +COPY scripts/utils_2d_pose.py / +RUN python3 -c "from utils_2d_pose import load_model; load_model();" +RUN python3 -c "from utils_2d_pose import load_wb_model; load_wb_model();" + +# Fix an undefined symbol error with ompi +RUN echo "ldconfig" >> ~/.bashrc + +COPY ./skelda/ /skelda/ +RUN pip3 install --no-cache-dir -e /skelda/ + +WORKDIR /SimplePoseTriangulation/ +CMD ["/bin/bash"] diff --git a/README.md b/README.md index 87087f8..90f2015 100644 --- a/README.md +++ b/README.md @@ -1 +1,19 @@ # SimplePoseTriangulation + +Triangulation of multiple persons from multiple camera views. + +
+ +## Build + +- Clone this project with submodules: + ```bash + git clone --recurse-submodules https://gitlab.com/Percipiote/SimplePoseTriangulation.git + cd SimplePoseTriangulation/ + ``` + +- Build docker container: + ```bash + docker build --progress=plain -t simpleposetriangulation . + ./run_container.sh + ``` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3e7cd57 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[tool.isort] +profile = "black" +known_first_party = "skelda,draw_utils,test_triangulate,utils_2d_pose,triangulate_poses" diff --git a/run_container.sh b/run_container.sh new file mode 100644 index 0000000..5b4fb8d --- /dev/null +++ b/run_container.sh @@ -0,0 +1,11 @@ +#! /bin/bash + +xhost + +docker run --privileged --rm --network host -it \ + --gpus all --shm-size=16g --ulimit memlock=-1 --ulimit stack=67108864 \ + --volume "$(pwd)"/:/SimplePoseTriangulation/ \ + --volume "$(pwd)"/../datasets/:/datasets/ \ + --volume "$(pwd)"/skelda/:/skelda/ \ + --volume /tmp/.X11-unix:/tmp/.X11-unix \ + --env DISPLAY --env QT_X11_NO_MITSHM=1 \ + simpleposetriangulation diff --git a/scripts/draw_utils.py b/scripts/draw_utils.py new file mode 100644 index 0000000..1489dba --- /dev/null +++ b/scripts/draw_utils.py @@ -0,0 +1,46 @@ +import matplotlib.pyplot as plt +import numpy as np + +from skelda import utils_view + +# ================================================================================================== + + +def show_poses2d(bodies, images, joint_names, title=""): + num_imgs = len(images) + rowbreak = int(num_imgs / 2.0 + 0.5) + fig, axs = plt.subplots(2, rowbreak, figsize=(30, 20)) + fig.suptitle(title, fontsize=20) + + if isinstance(bodies, np.ndarray): + bodies = bodies.tolist() + + # Draw skeletons into images + for i, image in enumerate(images): + colors = plt.cm.hsv(np.linspace(0, 1, len(bodies[i]), endpoint=False)).tolist() + colors = [[int(c[0] * 255), int(c[1] * 255), int(c[2] * 255)] for c in colors] + + for j, body in enumerate(bodies[i]): + image = utils_view.draw_body_in_image(image, body, joint_names, colors[j]) + + # Rescale image range for plotting + images = [img / 255.0 for img in images] + + if rowbreak == 1: + axs[0].imshow(images[0]) + if len(images) == 2: + axs[1].imshow(images[1]) + else: + # Optionally delete last empty plot + fig.delaxes(axs[1]) + + else: + for i in range(rowbreak): + axs[0][i].imshow(images[i]) + if i + rowbreak < num_imgs: + axs[1][i].imshow(images[i + rowbreak]) + else: + # Optionally delete last empty plot + fig.delaxes(axs[1][i]) + + return fig diff --git a/scripts/utils_2d_pose.py b/scripts/utils_2d_pose.py new file mode 100644 index 0000000..f99a5d8 --- /dev/null +++ b/scripts/utils_2d_pose.py @@ -0,0 +1,71 @@ +import os + +import numpy as np +from mmpose.apis import MMPoseInferencer + +# ================================================================================================== + +filepath = os.path.dirname(os.path.realpath(__file__)) + "/" + +# ================================================================================================== + + +def load_model(): + print("Loading mmpose model ...") + + model = MMPoseInferencer( + pose2d="/mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py", + pose2d_weights="https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth", + det_model="/mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py", + det_weights="https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth", + det_cat_ids=[0], + ) + + print("Loaded mmpose model") + return model + + +def load_wb_model(): + print("Loading mmpose whole body model ...") + + model = MMPoseInferencer( + pose2d="/mmpose/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py", + pose2d_weights="https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth", + det_model="/mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py", + det_weights="https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth", + det_cat_ids=[0], + ) + + print("Loaded mmpose model") + return model + + +# ================================================================================================== + + +def get_2d_pose(model, imgs, num_joints=17): + """See: https://mmpose.readthedocs.io/en/latest/user_guides/inference.html#basic-usage""" + + result_generator = model(imgs, show=False) + new_poses = [] + for _ in range(len(imgs)): + result = next(result_generator) + + poses = [] + for i in range(len(result["predictions"][0])): + kpts = result["predictions"][0][i]["keypoints"] + scores = result["predictions"][0][i]["keypoint_scores"] + + kpts = np.array(kpts) + scores = np.array(scores).reshape(-1, 1) + scores = np.clip(scores, 0, 1) + pose = np.concatenate((kpts, scores), axis=-1) + poses.append(pose) + + if len(poses) == 0: + poses.append(np.zeros([num_joints, 3])) + + poses = np.array(poses) + new_poses.append(poses) + + return new_poses