From eb8fbbbf725bf853de9bb8ef6d8fd085bb33e98f Mon Sep 17 00:00:00 2001 From: Yoshiki Obinata <27789460+mqcmd196@users.noreply.github.com> Date: Wed, 5 Feb 2025 23:41:37 +0900 Subject: [PATCH] Enable to build the package in normal catkin workspace (#58) * Enabling catkin_virtualenv to build the package in normal catkin workspace * restore docker usage * fix cmake logic * [format] isort * temporary disable mypy test due to symlink submodules * [CI] try cleaning up GA environment --- .github/workflows/docker_build.yml | 43 ++++++++++++++ .github/workflows/peripheral.yml | 17 +++--- .gitignore | 2 - CMakeLists.txt | 59 ++++++++++++++++++- Dockerfile | 3 - datasets | 1 + detic_configs | 1 + example/client.py | 4 +- example/masked_image_publisher.py | 3 +- node_script/batch_processor.py | 3 +- node_script/detic | 1 + node_script/node.py | 19 +++--- node_script/third_party | 1 + package.xml | 11 +++- prepare.sh | 17 ------ requirements.txt | 5 ++ setup.py | 9 +++ src/detic_ros/__init__.py | 0 {node_script => src/detic_ros}/node_config.py | 10 ++-- {node_script => src/detic_ros}/wrapper.py | 2 +- test/test_detic_ros_node.py | 3 +- 21 files changed, 157 insertions(+), 57 deletions(-) create mode 120000 datasets create mode 120000 detic_configs mode change 100755 => 100644 node_script/batch_processor.py create mode 120000 node_script/detic mode change 100755 => 100644 node_script/node.py create mode 120000 node_script/third_party create mode 100644 setup.py create mode 100644 src/detic_ros/__init__.py rename {node_script => src/detic_ros}/node_config.py (93%) rename {node_script => src/detic_ros}/wrapper.py (99%) diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 5e31330..64f6fdf 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -15,6 +15,49 @@ jobs: name: test docker build runs-on: ubuntu-latest steps: + - name: Free disk space + run: | + sudo rm -rf "/opt/ghc" || true + sudo rm -rf "/usr/share/dotnet" || true + sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true + sudo rm -rf "/usr/local/lib/android" || true + sudo rm -rf "/usr/local/share/boost" || true + sudo apt purge -y \ + ansible* \ + aria2* \ + aspnetcore* \ + azure-cli* \ + cabal* \ + clang* \ + dotnet-* \ + firefox* \ + gfortran-* \ + ghc* \ + google-chrome-stable* \ + google-cloud-sdk* \ + imagemagick* \ + javascript* \ + kubectl* \ + llvm* \ + mono* \ + mysql* \ + nginx* \ + node* \ + npm* \ + nuget* \ + php* \ + postgresql* \ + powershell* \ + rpm* \ + ruby* \ + sqlite3* \ + subversion \ + temurin* \ + tmux* \ + vim* \ + yarn* + sudo apt-get autoremove -y >/dev/null 2>&1 || true + sudo apt-get autoclean -y >/dev/null 2>&1 || true - name: Checkout uses: actions/checkout@v2 - name: Setup QEMU diff --git a/.github/workflows/peripheral.yml b/.github/workflows/peripheral.yml index fd97763..3de8e1c 100644 --- a/.github/workflows/peripheral.yml +++ b/.github/workflows/peripheral.yml @@ -17,15 +17,16 @@ jobs: - name: pip install formatters and mypy run: | pip3 install mypy flake8 isort + # Temporary commented out due to avoid testing submodule packages + # TODO (HiroIshida) fix + # - name: check by mypy + # run: | + # pip3 install -r requirements.txt + # pip3 install numpy==1.23 # to enable numpy's type checking + # mypy --version + # mypy . - - name: check by mypy - run: | - pip3 install -r requirements.txt - pip3 install numpy==1.23 # to enable numpy's type checking - mypy --version - mypy . - - - name: check by isrot and flake8 + - name: check by isort and flake8 run: | python3 -m isort example/ test/ node_script/ python3 -m flake8 example/ test/ node_script/ diff --git a/.gitignore b/.gitignore index 4ed3247..c067b61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ /models -/node_script/third_party -/node_script/detic /test/data # Byte-compiled / optimized / DLL files diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c01fab..e5c175b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,50 @@ cmake_minimum_required(VERSION 3.0.2) project(detic_ros) -find_package(catkin REQUIRED +find_package(catkin REQUIRED COMPONENTS + catkin_virtualenv std_msgs sensor_msgs message_generation ) +find_program(NVIDIA_SMI nvidia-smi) +if(NOT NVIDIA_SMI) + message(WARNING "NVIDIA Driver not found. It is strongly recommended that the NVIDIA GPU is available") +endif() + +find_package(Git REQUIRED) +if ((NOT EXISTS ${PROJECT_SOURCE_DIR}/Detic/third_party/CenterNet2) + OR (NOT EXISTS ${PROJECT_SOURCE_DIR}/Detic/third_party/Deformable-DETR)) + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) +endif() + +catkin_python_setup() + +find_package(Wget REQUIRED) +add_custom_target(create_models_dir + COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_SOURCE_DIR}/models" +) +add_custom_target(download_LCOCOI21k_CLIP_SwinB_896b32_4x_ft4x ALL + DEPENDS create_models_dir + COMMAND ${WGET_EXECUTABLE} "https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_SwinB_896b32_4x_ft4x_max-size.pth" -O "${PROJECT_SOURCE_DIR}/models/Detic_LCOCOI21k_CLIP_SwinB_896b32_4x_ft4x_max-size.pth" +) +add_custom_target(download_LCOCOI21k_CLIP_CXT21k_640b32_4x_ft4x ALL + DEPENDS create_models_dir + COMMAND ${WGET_EXECUTABLE} "https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_CXT21k_640b32_4x_ft4x_max-size.pth" -O "${PROJECT_SOURCE_DIR}/models/Detic_LCOCOI21k_CLIP_CXT21k_640b32_4x_ft4x_max-size.pth" +) +add_custom_target(download_LCOCOI21k_CLIP_R5021k_640b32_4x_ft4x ALL + DEPENDS create_models_dir + COMMAND ${WGET_EXECUTABLE} "https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_R5021k_640b32_4x_ft4x_max-size.pth" -O "${PROJECT_SOURCE_DIR}/models/Detic_LCOCOI21k_CLIP_R5021k_640b32_4x_ft4x_max-size.pth" +) +add_custom_target(download_LCOCOI21k_CLIP_R18_640b32_4x_ft4x ALL + DEPENDS create_models_dir + COMMAND ${WGET_EXECUTABLE} "https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_R18_640b32_4x_ft4x_max-size.pth" -O "${PROJECT_SOURCE_DIR}/models/Detic_LCOCOI21k_CLIP_R18_640b32_4x_ft4x_max-size.pth" +) + add_message_files( FILES SegmentationInfo.msg @@ -23,6 +61,25 @@ generate_messages( std_msgs sensor_msgs ) + +catkin_package( + CATKIN_DEPENDS message_runtime +) + +catkin_generate_virtualenv( + PYTHON_INTERPRETER python3 + CHECK_VENV FALSE +) + +file(GLOB PYTHON_SCRIPTS node_script/*.py) +catkin_install_python( + PROGRAMS ${PYTHON_SCRIPTS} + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +install(FILES requirements.txt + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) if(CATKIN_ENABLE_TESTING) add_custom_target(${PROJECT_NAME}_download_image ALL diff --git a/Dockerfile b/Dockerfile index 31ec2fd..5dc78fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -76,9 +76,6 @@ USER user CMD /bin/bash SHELL ["/bin/bash", "-c"] -RUN sudo apt install python3-pip -y -RUN pip3 install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html - ######################################## ########### WORKSPACE BUILD ############ ######################################## diff --git a/datasets b/datasets new file mode 120000 index 0000000..07a4ff1 --- /dev/null +++ b/datasets @@ -0,0 +1 @@ +Detic/datasets \ No newline at end of file diff --git a/detic_configs b/detic_configs new file mode 120000 index 0000000..d4c0ed0 --- /dev/null +++ b/detic_configs @@ -0,0 +1 @@ +Detic/configs \ No newline at end of file diff --git a/example/client.py b/example/client.py index aa54fee..b794778 100755 --- a/example/client.py +++ b/example/client.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 import argparse -import cv2 import matplotlib.pyplot as plt import rospy from cv_bridge import CvBridge - from detic_ros.srv import DeticSeg +import cv2 + if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-image', type=str, help='input image path') diff --git a/example/masked_image_publisher.py b/example/masked_image_publisher.py index ecb2e70..07fe5a6 100755 --- a/example/masked_image_publisher.py +++ b/example/masked_image_publisher.py @@ -5,9 +5,8 @@ import numpy as np import rospy from cv_bridge import CvBridge -from sensor_msgs.msg import Image - from detic_ros.msg import SegmentationInfo +from sensor_msgs.msg import Image class SampleNode: diff --git a/node_script/batch_processor.py b/node_script/batch_processor.py old mode 100755 new mode 100644 index 717833f..e75b2d9 --- a/node_script/batch_processor.py +++ b/node_script/batch_processor.py @@ -8,9 +8,10 @@ import rosbag import tqdm from cv_bridge import CvBridge +from sensor_msgs.msg import Image + from moviepy.editor import ImageSequenceClip from node_config import NodeConfig -from sensor_msgs.msg import Image from wrapper import DeticWrapper, InferenceRawResult diff --git a/node_script/detic b/node_script/detic new file mode 120000 index 0000000..34e08d3 --- /dev/null +++ b/node_script/detic @@ -0,0 +1 @@ +../Detic/detic \ No newline at end of file diff --git a/node_script/node.py b/node_script/node.py old mode 100755 new mode 100644 index e1dc7ec..353a360 --- a/node_script/node.py +++ b/node_script/node.py @@ -2,23 +2,18 @@ from typing import Optional import rospy -import torch +from detic_ros.msg import SegmentationInfo +from detic_ros.node_config import NodeConfig +from detic_ros.srv import (CustomVocabulary, CustomVocabularyRequest, + CustomVocabularyResponse, DeticSeg, DeticSegRequest, + DeticSegResponse) +from detic_ros.wrapper import DeticWrapper from jsk_recognition_msgs.msg import LabelArray, VectorArray -from node_config import NodeConfig from rospy import Publisher, Subscriber from sensor_msgs.msg import Image from std_srvs.srv import Empty, EmptyRequest, EmptyResponse -from wrapper import DeticWrapper -from detic_ros.msg import SegmentationInfo -from detic_ros.srv import ( - CustomVocabulary, - CustomVocabularyRequest, - CustomVocabularyResponse, - DeticSeg, - DeticSegRequest, - DeticSegResponse, -) +import torch class DeticRosNode: diff --git a/node_script/third_party b/node_script/third_party new file mode 120000 index 0000000..8746bc7 --- /dev/null +++ b/node_script/third_party @@ -0,0 +1 @@ +../Detic/third_party \ No newline at end of file diff --git a/package.xml b/package.xml index 06fd47a..5b62045 100644 --- a/package.xml +++ b/package.xml @@ -7,14 +7,23 @@ MIT Hirokazu Ishida catkin - python3-catkin-pkg-modules. + python3-catkin-pkg-modules + python3-setuptools + catkin_virtualenv message_generation + wget message_runtime sensor_msgs std_srvs + jsk_common jsk_recognition_msgs cv_bridge + python3-rospkg rostest image_publisher + + + requirements.txt + diff --git a/prepare.sh b/prepare.sh index 3915988..da4ae40 100755 --- a/prepare.sh +++ b/prepare.sh @@ -9,20 +9,3 @@ cd node_script ln -sf ../Detic/detic ln -sf ../Detic/third_party cd .. - -if [ ! -d "models" ]; then - mkdir models - # All real-time models - # https://github.com/facebookresearch/Detic/blob/main/docs/MODEL_ZOO.md#real-time-models - - # Swin Transformer model - wget -q https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_SwinB_896b32_4x_ft4x_max-size.pth -O models/Detic_LCOCOI21k_CLIP_SwinB_896b32_4x_ft4x_max-size.pth - # ConvNet model - wget -q https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_CXT21k_640b32_4x_ft4x_max-size.pth -O models/Detic_LCOCOI21k_CLIP_CXT21k_640b32_4x_ft4x_max-size.pth - # Res50 model - wget -q https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_R5021k_640b32_4x_ft4x_max-size.pth -O models/Detic_LCOCOI21k_CLIP_R5021k_640b32_4x_ft4x_max-size.pth - # Res18 model - wget -q https://dl.fbaipublicfiles.com/detic/Detic_LCOCOI21k_CLIP_R18_640b32_4x_ft4x_max-size.pth -O models/Detic_LCOCOI21k_CLIP_R18_640b32_4x_ft4x_max-size.pth -fi - -pip3 install -r requirements.txt diff --git a/requirements.txt b/requirements.txt index 30c8c16..096ce8e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,8 @@ +-f https://download.pytorch.org/whl/torch_stable.html +torch==1.9.0+cu111 +torchvision==0.10.0+cu111 +torchaudio==0.9.0 + -f https://dl.fbaipublicfiles.com/detectron2/wheels/cu111/torch1.9/index.html detectron2 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6f60857 --- /dev/null +++ b/setup.py @@ -0,0 +1,9 @@ +from catkin_pkg.python_setup import generate_distutils_setup +from setuptools import setup + +d = generate_distutils_setup( + packages=['detic_ros'], + package_dir={'': 'src'} +) + +setup(**d) diff --git a/src/detic_ros/__init__.py b/src/detic_ros/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/node_script/node_config.py b/src/detic_ros/node_config.py similarity index 93% rename from node_script/node_config.py rename to src/detic_ros/node_config.py index 628ae29..01fadaf 100644 --- a/node_script/node_config.py +++ b/src/detic_ros/node_config.py @@ -7,8 +7,11 @@ import rospy import torch -# Dirty but no way, because CenterNet2 is not package oriented -sys.path.insert(0, os.path.join(sys.path[0], 'third_party/CenterNet2/')) +# Dirty but no way, because CenterNet2, Detic is not package oriented +rospack = rospkg.RosPack() +pack_path = rospack.get_path("detic_ros") +sys.path.insert(0, os.path.join(pack_path, 'node_script/third_party/CenterNet2')) +sys.path.insert(0, os.path.join(pack_path, 'Detic')) from centernet.config import add_centernet_config from detectron2.config import get_cfg @@ -60,8 +63,6 @@ def from_args( assert device_name in ['cpu', 'cuda'] assert model_type in NodeConfig.model_names - pack_path = rospkg.RosPack().get_path('detic_ros') - model_name = NodeConfig.model_names[model_type] default_detic_config_path = os.path.join( pack_path, 'detic_configs', @@ -119,7 +120,6 @@ def to_detectron_config(self): cfg.MODEL.ROI_HEADS.ONE_CLASS_PER_PROPOSAL = True # Maybe should edit detic_configs/Base-C2_L_R5021k_640b64_4x.yaml - pack_path = rospkg.RosPack().get_path('detic_ros') cfg.MODEL.ROI_BOX_HEAD.CAT_FREQ_PATH = os.path.join( pack_path, 'datasets/metadata/lvis_v1_train_cat_info.json') diff --git a/node_script/wrapper.py b/src/detic_ros/wrapper.py similarity index 99% rename from node_script/wrapper.py rename to src/detic_ros/wrapper.py index 1f0c3ff..6a8204c 100644 --- a/node_script/wrapper.py +++ b/src/detic_ros/wrapper.py @@ -11,7 +11,7 @@ from detectron2.utils.visualizer import VisImage from detic.predictor import VisualizationDemo from jsk_recognition_msgs.msg import Label, LabelArray, VectorArray -from node_config import NodeConfig +from detic_ros.node_config import NodeConfig from sensor_msgs.msg import Image from std_msgs.msg import Header diff --git a/test/test_detic_ros_node.py b/test/test_detic_ros_node.py index bcddc75..fcc5265 100755 --- a/test/test_detic_ros_node.py +++ b/test/test_detic_ros_node.py @@ -4,9 +4,8 @@ import rospy import rostest -from sensor_msgs.msg import Image - from detic_ros.msg import SegmentationInfo +from sensor_msgs.msg import Image class TestNode(unittest.TestCase):