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):