From 2a89ec80a92e41aea9c9cdd8b70f7e630d681857 Mon Sep 17 00:00:00 2001 From: gbr1 Date: Sat, 3 Sep 2022 17:45:02 +0000 Subject: [PATCH 1/2] adding vision_msgs, issue on labels because are missing in msgs --- .../__pycache__/__init__.cpython-38.pyc | Bin 158 -> 158 bytes .../image_classification.cpython-38.pyc | Bin 5119 -> 5860 bytes edgeimpulse_ros/image_classification.py | 59 +++++++++++++++--- .../__pycache__/device_patches.cpython-38.pyc | Bin 551 -> 551 bytes package.xml | 2 +- setup.py | 2 +- 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/edgeimpulse_ros/__pycache__/__init__.cpython-38.pyc b/edgeimpulse_ros/__pycache__/__init__.cpython-38.pyc index 93d905d1c68404a466a409b288b6c6049434e2e0..af7ee0bd98b2d8814a4c70a1244bbd4467bb9dee 100644 GIT binary patch delta 20 acmbQoIFFGhl$V!_0SNqBgp()oOacHXzyv!0 delta 20 acmbQoIFFGhl$V!_0SLAUyiS_PGYJ4K6a@wV diff --git a/edgeimpulse_ros/__pycache__/image_classification.cpython-38.pyc b/edgeimpulse_ros/__pycache__/image_classification.cpython-38.pyc index e1ecdbea0543fe3d6882b61e9e58f64e94ea1db0..aa85919149c5a143f9b043d4e53084ec0ac02a98 100644 GIT binary patch delta 2763 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±G#0`w b0vHs&auD2*;HN?bp)=v1lIRje59{=Q{Hvl! diff --git a/edgeimpulse_ros/image_classification.py b/edgeimpulse_ros/image_classification.py index ab750fb..3a65bbf 100644 --- a/edgeimpulse_ros/image_classification.py +++ b/edgeimpulse_ros/image_classification.py @@ -24,7 +24,9 @@ from sensor_msgs.msg import Image -#from vision_msgs.msg import BoundingBox2DArray +from vision_msgs.msg import Detection2DArray +from vision_msgs.msg import Detection2D +from vision_msgs.msg import ObjectHypothesisWithPose #from vision_msgs.msg import VisionInfo import os @@ -35,7 +37,9 @@ + class EI_Image_node(Node): + def __init__(self): self.occupied = False @@ -45,21 +49,27 @@ def __init__(self): super().__init__('ei_image_classifier_node') self.init_parameters() self.ei_classifier = self.EI_Classifier(self.modelfile, self.get_logger()) - #self.publisher = self.create_publisher(BoundingBox2DArray,'/edge_impulse/detection',1) self.timer_parameter = self.create_timer(2,self.parameters_callback) self.image_publisher = self.create_publisher(Image,'/detection/output/image',1) + self.results_publisher = self.create_publisher(Detection2DArray,'/detection/output/results',1) + self.timer_classify = self.create_timer(0.01,self.classify_callback) self.timer_classify.cancel() self.subscription = self.create_subscription(Image,'/detection/input/image',self.listener_callback,1) self.subscription - + + + def init_parameters(self): self.declare_parameter('model.filepath','') self.modelfile= self.get_parameter('model.filepath').get_parameter_value().string_value + self.declare_parameter('frame_id','base_link') + self.frame_id= self.get_parameter('frame_id').get_parameter_value().string_value + self.declare_parameter('show.overlay', True) self.show_overlay = self.get_parameter('show.overlay').get_parameter_value().bool_value @@ -72,9 +82,6 @@ def init_parameters(self): - - - def parameters_callback(self): self.show_labels_on_image = self.get_parameter('show.labels').get_parameter_value().bool_value self.show_extra_classification_info = self.get_parameter('show.classification_info').get_parameter_value().bool_value @@ -91,13 +98,25 @@ def listener_callback(self, msg): self.img = current_frame self.timer_classify.reset() + + + + def classify_callback(self): self.occupied = True + + # vision msgs + results_msg = Detection2DArray() + time_now = self.get_clock().now().to_msg() + results_msg.header.stamp = time_now + results_msg.header.frame_id = self.frame_id + # classify features, cropped, res = self.ei_classifier.classify(self.img) - #prepare output + + #p repare output if "classification" in res["result"].keys(): if self.show_extra_classification_info: self.get_logger().info('Result (%d ms.) ' % (res['timing']['dsp'] + res['timing']['classification']), end='') @@ -112,6 +131,28 @@ def classify_callback(self): self.get_logger().info('Found %d bounding boxes (%d ms.)' % (len(res["result"]["bounding_boxes"]), res['timing']['dsp'] + res['timing']['classification'])) for bb in res["result"]["bounding_boxes"]: + result_msg = Detection2D() + result_msg.header.stamp = time_now + result_msg.header.frame_id = self.frame_id + + # object with hypthothesis + obj_hyp = ObjectHypothesisWithPose() + #obj_hyp.id = + obj_hyp.score = bb['value'] + obj_hyp.pose.pose.position.x = float(bb['x']) + obj_hyp.pose.pose.position.y = float(bb['y']) + result_msg.results.append(obj_hyp) + + # bounding box + result_msg.bbox.center.x = float(bb['x']) + result_msg.bbox.center.y = float(bb['y']) + result_msg.bbox.size_x = float(bb['width']) + result_msg.bbox.size_y = float(bb['height']) + + + results_msg.detections.append(result_msg) + + # image if self.show_extra_classification_info: self.get_logger().info('%s (%.2f): x=%d y=%d w=%d h=%d' % (bb['label'], bb['value'], bb['x'], bb['y'], bb['width'], bb['height'])) if self.show_overlay: @@ -124,6 +165,7 @@ def classify_callback(self): # publish message self.image_publisher.publish(self.cv_bridge.cv2_to_imgmsg(cropped,"bgr8")) + self.results_publisher.publish(results_msg) self.occupied= False self.timer_classify.cancel() @@ -166,6 +208,8 @@ def classify(self, img): self.logger.error('Error on classification') + + def main(): rclpy.init() node = EI_Image_node() @@ -174,7 +218,6 @@ def main(): node.destroy_node() rclpy.shutdown() - if __name__ == "__main__": main() diff --git a/edgeimpulse_ros/submodules/__pycache__/device_patches.cpython-38.pyc b/edgeimpulse_ros/submodules/__pycache__/device_patches.cpython-38.pyc index 9346394566c31c9a24c6e203eaa858ff89cad560..4c735e9cb41d75870bb5e72f2ae5fe03698872a4 100644 GIT binary patch delta 21 bcmZ3^vYdq{l$V!_0SNqBgp)V&NHYNdE@=b) delta 21 bcmZ3^vYdq{l$V!_0SH)xUngzkk!At_E)4`4 diff --git a/package.xml b/package.xml index 92eafb6..79ae856 100644 --- a/package.xml +++ b/package.xml @@ -14,7 +14,7 @@ ament_pep257 python3-pytest - + vision_msgs sensor_msgs ros2launch diff --git a/setup.py b/setup.py index a843408..4d5aa3d 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ submodules = 'edgeimpulse_ros/submodules' setup( name=package_name, - version='0.0.1', + version='0.0.2', packages=[package_name, submodules], data_files=[ ('share/ament_index/resource_index/packages', From b299893bdc729201623138f2b6046b4b5108c7aa Mon Sep 17 00:00:00 2001 From: gbr1 Date: Sun, 4 Sep 2022 15:16:39 +0000 Subject: [PATCH 2/2] fixed vision_msgs --- README.md | 34 ++++++++++++++++-- .../image_classification.cpython-38.pyc | Bin 5860 -> 6264 bytes edgeimpulse_ros/image_classification.py | 14 ++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f4ee4f2..156f229 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,25 @@ # edgeimpulse_ros -ROS2 wrapper for Edge Impulse +ROS2 wrapper for Edge Impulse on Linux. -## How to install + +## 1. Topics + +- `/detection/input/image`, image topic to analyze +- `/detection/output/image`, image with bounding boxes +- `/detection/output/info`, VisionInfo message +- `/detection/output/results`, results as text + +## 2. Parameters + +- `frame_id` (**string**), _"base_link"_, frame id of output topics +- `model.filepath` (**string**), _""_, absolute filepath to .eim file +- `show.overlay` (**bool**), _true_, show bounding boxes on output image +- `show.labels` (**bool**), _true_, show labels on bounding boxes, +- `show.classification_info` (**bool**), _true_, show the attendibility (0-1) of the prediction + + +## 3. How to install 1. install edge_impulse_linux:
`pip3 install edge_impulse_linux` @@ -30,12 +47,23 @@ ROS2 wrapper for Edge Impulse `source install/setup.bash`
-## How to run +## 4. How to run Launch the node:
`ros2 run edgeimpulse_ros image_classification --ros-args -p model.filepath:="" -r /detection/input/image:="/your_image_topic"` `
+## 5. Models + +Here you find some prebuilt models: [https://github.com/gbr1/edgeimpulse_example_models](https://github.com/gbr1/edgeimpulse_example_models) + +## 6. Known issues + +- this wrapper works on foxy, galactic and humble are coming soon (incompatibility on vision msgs by ros-perception) +- if you use a classification model, topic results is empty +- you cannot change color of bounding boxes (coming soon) +- other types (imu and sound based ml) are unavailable + ***Copyright © 2022 Giovanni di Dio Bruno - gbr1.github.io*** diff --git a/edgeimpulse_ros/__pycache__/image_classification.cpython-38.pyc b/edgeimpulse_ros/__pycache__/image_classification.cpython-38.pyc index aa85919149c5a143f9b043d4e53084ec0ac02a98..59650d87ab5902a5887a566e83bd9c20cf129cba 100644 GIT binary patch delta 2720 zcmZuzO^hQ)74GUkx9xV@9{rpD``3XDmPOCn)dRaRwR4L!;df^@}t4?CI+usYgLJrcYm%Cv%=s$=31M;q1CH%C!I37uk7U_r5BthjVEO;bM zj48N*HaU{K6twB7G?l^5gnkA-#j_l2O)pE8nncwaSbK_-n{yg)I(&%=@@R#OQIkYp zaq{=E|B(CTv#z#b@lQ+jY9VX2*5felrZadtH|~{eZf0t_SEl zgC=YC+{k5NoSHGw{=khB0~UC0JBrmlsBg>b>#-KR*>_oNQFq`6`_3CM1ooZ(Q(hw~ z&nc^w+of#^p4t)6+re-!jJCxoHI&Vb&DaRq?ct#7(pc&CI?RM~j1AN~y|BX)yrsC` zj*UHx#_7^nzv(t9Og9e-4PzYwy%|tDPn%J*)eK$7586$f&dwcC|Bvg>$__DjRxPb0 zajHCX!=WFA&S2Q`yWve-iHPo;`eA(uEKb80J_I1iI?;(i4A}%M0v5?BXmfIo@J;O> z8ruLPzNEjcuY$lf_%HSE*3O`K?g-AKv<&b(uO@!->{qdS5#dpQy3W3a@+E|?BRr09 z8R0R6FLQPh6gT+4533!JD}Et$jl9hdQd{GZK{IfFQ%*4|fo#>JLo!NvW%yN`s^GF; z;A*3!w>ViEr7+d*8IMwc? zA$Pul9zbJ4VwWmXbTWDfdaxI?d?+81igd>W{|}GSBXcws8#8l8D^+k5ZF;9@Rk%ys zN#7-}V=(oR3jEeoz5@yBJu*2BcxKWVskAnoS0-;8SRxhy^~gKxX^sxX3IP*kVWWZJE z+erq+q}lKIE_kL!YPRz5K)%bx`Sbi8dRz*04 zfC<7L0jOsnJ$_+b(4R);JN#qoV(o!Use|Tq_(GdEvJHi#2)~g%sX}Z0`bXJ6kZUZD zV+#Pc&1+af*ReuAw$2ui%Fd{H5dyY&pCMLOpt9&7hp@}v%Wu813nJ`K(CN60Wv~OU zTQ_1S&;&P+y^N#=+JMDs7zG2&b5w`|^cqSJECVar@A#F4gT^;Ns>|$EG;$EWq`1Th z$HB+Id7uA%;l0<;)~?_k*mIlF5Gsqa$AaGMAz|0hiJ0>TAl0>5B%%_1A62g)*a#2A zgabd||0%S_7#;f|f^c?hCnQljS3vt)_(B~3igC$M8FKX$YeK_X2yF!63`;G;63MXC zF+4?K9%r1{%hz^&Sl=w9EiuhD+K9Oj&I|^SPdb8x@_q7!+_zV z8aD7{H3a*H_$TR@#WX)oLuT@)%2#OyN!$z(@NA!tmw0qGv2l48*cH6QA?}<>@MpkU XOxlxJbh&Yr3AOu2!L+1n%Lh7jpE~pZM|9^H<8a38@@8945-u(YR z`Fr;t6Op-aI4Hqi?wxpXZ|?2LhW$SRMrw-c z7s@uX>J4gh&o@SV{DE(jPbr%Qv!32478jdkn|i)-t;96W6q|2SXVQK+uNUnFX)exJ z%g$w+F`Zvi)BF?lyOBZA?}W!00+3{lXhfF{qLYLilld*}e$dkwSfOTHWy;_3-_Vj^ z#faF)j6^fUsX0v@}i=U3Db{mA4rq zfChroWLk2!xLbiUfJ?2)t0XP07!ZG3E7UST4)@Z!D7K*K3pc~q^xiG}yL-q~=1Xk<@%$bpYDedH zBg1o^cG)gao0+QP7HUnl4FjbCJiXs%OQOm=<%+%J^lCJPYNcFXXn2~)!eM*REr5VC zk)Mo?Y0n@x&Fj%aDN)q>fHwooF1m$!scN%HekVG0;whAdkDNVqcGjAmIlTAq%q+{I z%-`=&784f5t9vcC0TZAErOmKGMcuOzpz>js<40rrv;!zU##drbXV=2#f!i&+554fF*%1)4=TWDEQG^chSS6sF-p(MIfL0EN@oK>|j6T950xZs^CD!P}`b32{{#%+zAFxx~(+pTU1m zjkg~qj&VGtRw&nh#X#ae0r*mABq-~Iy@FcZvQTeX`C(IEg!k#%j>}|FnL%f99x7t7 zYCB8;0mJ5CFAJ5}bP~U84BJ=KKf_BgqXUjzcN)xs7H}r95B&UgIvLW@tk-<}m-Mrj zu!0yKP2|zLzDJp_UAd