From a69b6bcbea25797a0d98e8b53cbef2e7e3b0e779 Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Fri, 14 Jan 2022 14:07:27 +0100 Subject: [PATCH 1/8] Added RPi camera Added Extension slot to Memristor Robot, and then the camera attached to it --- .../webots_data/protos/RobotMemristor.proto | 5 +++++ mep3_simulation/webots_data/worlds/eurobot_2022.wbt | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/mep3_simulation/webots_data/protos/RobotMemristor.proto b/mep3_simulation/webots_data/protos/RobotMemristor.proto index c80add351..9c32a63ce 100644 --- a/mep3_simulation/webots_data/protos/RobotMemristor.proto +++ b/mep3_simulation/webots_data/protos/RobotMemristor.proto @@ -27,6 +27,8 @@ PROTO RobotMemristor [ hiddenField SFFloat robot_z_size 0.335 hiddenField SFFloat robot_height 0.013 hiddenField SFFloat robot_plate_width 0.005 + field MFNode extensionSlot [] # Extends the robot with new nodes in the extension slot. + ] { Robot { @@ -161,6 +163,9 @@ Robot { translation 0 0 %<= fields.robot_z_size.value + 0.03 >% rotation 1 0 0 1.5708 } + Group { + children IS extensionSlot + } ] boundingObject Group { children [ diff --git a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt index f3724e176..dd5602c33 100644 --- a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt +++ b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt @@ -27,6 +27,17 @@ Floor { metalness 0 } } +RobotMemristor { + name "MemristorRobot" + translation 0 0 0 + controller "" + extensionSlot [ + JetBotRaspberryPiCamera { + translation 0.06 0 0.34 + rotation 0 1 0 2.3562 + } + ] +} Solid { children [ DEF purple_statuette_support_shape Group { From 8b7af645b9fba713f2928d97b3fefa3a86ed9ec4 Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Fri, 14 Jan 2022 18:15:04 +0100 Subject: [PATCH 2/8] Removing second robot... --- mep3_simulation/webots_data/worlds/eurobot_2022.wbt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt index b1b6d6478..0a6eef5a6 100644 --- a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt +++ b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt @@ -607,10 +607,6 @@ Sample { rotation 0.8246198587813874 0.4760949184673239 0.30550894768068065 -2.1681953071795865 frontTexture "blue" } -RobotMemristor { - translation 0 0 0 - controller "" -} ExcavationSquare { name "excSq0" translation -0.8325 -1.022 0 From 57d0b574f0cde31b50701383a49384134b984fe3 Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Fri, 14 Jan 2022 18:54:47 +0100 Subject: [PATCH 3/8] Setting up real Field of View for Raspberry Pi Camera --- mep3_simulation/webots_data/worlds/eurobot_2022.wbt | 1 + 1 file changed, 1 insertion(+) diff --git a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt index 0a6eef5a6..0d4cae02b 100644 --- a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt +++ b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt @@ -35,6 +35,7 @@ RobotMemristor { JetBotRaspberryPiCamera { translation 0.06 0 0.34 rotation 0 1 0 2.3562 + fieldOfView 1.16 } ] } From 1d4de4eac15c3e5de8c9300d012a816bff61b95d Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Fri, 14 Jan 2022 19:12:31 +0100 Subject: [PATCH 4/8] Adjusted the position of the Camera --- mep3_simulation/webots_data/worlds/eurobot_2022.wbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt index 0d4cae02b..bc1aa2b72 100644 --- a/mep3_simulation/webots_data/worlds/eurobot_2022.wbt +++ b/mep3_simulation/webots_data/worlds/eurobot_2022.wbt @@ -34,7 +34,7 @@ RobotMemristor { extensionSlot [ JetBotRaspberryPiCamera { translation 0.06 0 0.34 - rotation 0 1 0 2.3562 + rotation 0 1 0 2.62 fieldOfView 1.16 } ] From 97ab8de726324ecea9d00eb07a4be0cc005ed184 Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Fri, 14 Jan 2022 20:19:08 +0100 Subject: [PATCH 5/8] Added python subsriber to receive images from OnRobot camera --- mep3_vision/mep3_vision/__init__.py | 0 mep3_vision/mep3_vision/onrobot_camera.py | 75 +++++++++++++++++++++++ mep3_vision/package.xml | 25 ++++++++ mep3_vision/resource/mep3_vision | 0 mep3_vision/setup.cfg | 4 ++ mep3_vision/setup.py | 26 ++++++++ mep3_vision/test/test_copyright.py | 23 +++++++ mep3_vision/test/test_flake8.py | 25 ++++++++ mep3_vision/test/test_pep257.py | 23 +++++++ 9 files changed, 201 insertions(+) create mode 100644 mep3_vision/mep3_vision/__init__.py create mode 100644 mep3_vision/mep3_vision/onrobot_camera.py create mode 100644 mep3_vision/package.xml create mode 100644 mep3_vision/resource/mep3_vision create mode 100644 mep3_vision/setup.cfg create mode 100644 mep3_vision/setup.py create mode 100644 mep3_vision/test/test_copyright.py create mode 100644 mep3_vision/test/test_flake8.py create mode 100644 mep3_vision/test/test_pep257.py diff --git a/mep3_vision/mep3_vision/__init__.py b/mep3_vision/mep3_vision/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/mep3_vision/mep3_vision/onrobot_camera.py b/mep3_vision/mep3_vision/onrobot_camera.py new file mode 100644 index 000000000..2f745e3bc --- /dev/null +++ b/mep3_vision/mep3_vision/onrobot_camera.py @@ -0,0 +1,75 @@ +# Basic ROS 2 program to subscribe to real-time streaming +# video from your built-in webcam +# Author: +# - Addison Sears-Collins +# - https://automaticaddison.com + +# Import the necessary libraries +import cv2 # OpenCV library +import rclpy # Python library for ROS 2 +from rclpy.node import Node # Handles the creation of nodes +from sensor_msgs.msg import Image # Image is the message type +from cv_bridge import CvBridge # Package to convert between ROS and OpenCV Images + + +class ImageSubscriber(Node): + """ + Create an ImageSubscriber class, which is a subclass of the Node class. + """ + + def __init__(self): + """ + Class constructor to set up the node + """ + # Initiate the Node class's constructor and give it a name + super().__init__('image_subscriber') + + # Create the subscriber. This subscriber will receive an Image + # from the video_frames topic. The queue size is 10 messages. + self.subscription = self.create_subscription( + Image, + '/big/MemristorRobot/camera', + self.listener_callback, + 10) + self.subscription # prevent unused variable warning + + # Used to convert between ROS and OpenCV images + self.br = CvBridge() + + def listener_callback(self, data): + """ + Callback function. + """ + # Display the message on the console + self.get_logger().info('Receiving video frame') + + # Convert ROS Image message to OpenCV image + current_frame = self.br.imgmsg_to_cv2(data) + + # Display image + cv2.imshow("camera", current_frame) + + cv2.waitKey(1) + + +def main(args=None): + # Initialize the rclpy library + rclpy.init(args=args) + + # Create the node + image_subscriber = ImageSubscriber() + + # Spin the node so the callback function is called. + rclpy.spin(image_subscriber) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + image_subscriber.destroy_node() + + # Shutdown the ROS client library for Python + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/mep3_vision/package.xml b/mep3_vision/package.xml new file mode 100644 index 000000000..199819150 --- /dev/null +++ b/mep3_vision/package.xml @@ -0,0 +1,25 @@ + + + + mep3_vision + 0.0.0 + Computer vision for Memristor Eurobot + milos + TODO: License declaration + + rclpy + image_transport + cv_bridge + sensor_msgs + std_msgs + python3-opencv + + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/mep3_vision/resource/mep3_vision b/mep3_vision/resource/mep3_vision new file mode 100644 index 000000000..e69de29bb diff --git a/mep3_vision/setup.cfg b/mep3_vision/setup.cfg new file mode 100644 index 000000000..8432f2d3c --- /dev/null +++ b/mep3_vision/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/mep3_vision +[install] +install-scripts=$base/lib/mep3_vision diff --git a/mep3_vision/setup.py b/mep3_vision/setup.py new file mode 100644 index 000000000..e5349c957 --- /dev/null +++ b/mep3_vision/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup + +package_name = 'mep3_vision' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='milos', + maintainer_email='milostravian2@gmail.com', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'onrobot_cam_subscriber = mep3_vision.onrobot_camera:main', + ], + }, +) diff --git a/mep3_vision/test/test_copyright.py b/mep3_vision/test/test_copyright.py new file mode 100644 index 000000000..cc8ff03f7 --- /dev/null +++ b/mep3_vision/test/test_copyright.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_copyright.main import main +import pytest + + +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/mep3_vision/test/test_flake8.py b/mep3_vision/test/test_flake8.py new file mode 100644 index 000000000..27ee1078f --- /dev/null +++ b/mep3_vision/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/mep3_vision/test/test_pep257.py b/mep3_vision/test/test_pep257.py new file mode 100644 index 000000000..b234a3840 --- /dev/null +++ b/mep3_vision/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found code style errors / warnings' From a1699f986a57363b7cead55f6329817fc33584b9 Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Fri, 14 Jan 2022 22:07:43 +0100 Subject: [PATCH 6/8] First draft of AruCo marker detection. Next step is calibration --- .../mep3_vision/DummyCameraCalibration.pckl | 2616 +++++++++++++++++ mep3_vision/mep3_vision/onrobot_camera.py | 39 +- 2 files changed, 2654 insertions(+), 1 deletion(-) create mode 100644 mep3_vision/mep3_vision/DummyCameraCalibration.pckl diff --git a/mep3_vision/mep3_vision/DummyCameraCalibration.pckl b/mep3_vision/mep3_vision/DummyCameraCalibration.pckl new file mode 100644 index 000000000..0a105fdda --- /dev/null +++ b/mep3_vision/mep3_vision/DummyCameraCalibration.pckl @@ -0,0 +1,2616 @@ +(cnumpy.core.multiarray +_reconstruct +p0 +(cnumpy +ndarray +p1 +(I0 +tp2 +S'b' +p3 +tp4 +Rp5 +(I1 +(I3 +I3 +tp6 +cnumpy +dtype +p7 +(S'f8' +p8 +I0 +I1 +tp9 +Rp10 +(I3 +S'<' +p11 +NNNI-1 +I-1 +I0 +tp12 +bI00 +S'g\x00\xae|\xce\x83\x96@\x00\x00\x00\x00\x00\x00\x00\x00\xf3\xcf\x84\xcd\x82c\x8d@\x00\x00\x00\x00\x00\x00\x00\x00l\xe3\xf47\x17s\x96@.1\xc0\xab\xf0\x7f\x80@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?' +p13 +tp14 +bg0 +(g1 +(I0 +tp15 +g3 +tp16 +Rp17 +(I1 +(I1 +I5 +tp18 +g10 +I00 +S'\xf0k\xed\xce\xcc\r\xb4?|\xfd\x01\x15P\x9d\xe0\xbf\x9e\x84\xc6\xf5\xa1\xf0{\xbfi\xcc\xbcD\xf2%o\xbf#n\x88Q\x89\xad\xf0?' +p19 +tp20 +b(lp21 +g0 +(g1 +(I0 +tp22 +g3 +tp23 +Rp24 +(I1 +(I3 +I1 +tp25 +g10 +I00 +S'\x9a\xd5\xe8\x00\x1aP\x00@\xfe\x8c\x05\x83\x0f\x9b\xf9?\xec\x90\xbdo\xa7\x1f\xe5?' +p26 +tp27 +bag0 +(g1 +(I0 +tp28 +g3 +tp29 +Rp30 +(I1 +(I3 +I1 +tp31 +g10 +I00 +S'0\xaf\xf8\xbdlO\x00@i^\x08\x8a\xd9\x8d\xf9?U\xa5ifkR\xe5?' +p32 +tp33 +bag0 +(g1 +(I0 +tp34 +g3 +tp35 +Rp36 +(I1 +(I3 +I1 +tp37 +g10 +I00 +S'\xe3\xfd\x08\xd9#\x80\x01\xc0\xb76\xaf\xfe\x94}\xfc\xbf\xa1fA]C\x9f\xd5?' +p38 +tp39 +bag0 +(g1 +(I0 +tp40 +g3 +tp41 +Rp42 +(I1 +(I3 +I1 +tp43 +g10 +I00 +S'\x8f,\xa4\xb2\xd2Y\x01\xc0\xe08\xe0\xbcNF\xfc\xbf\xf8\xc6\\\x97\x9b.\xd6?' +p44 +tp45 +bag0 +(g1 +(I0 +tp46 +g3 +tp47 +Rp48 +(I1 +(I3 +I1 +tp49 +g10 +I00 +S'\xa3Q\xcd\xcf\xfbN\x01\xc0\xcb\x92H\x9aC\x1e\xfc\xbf6}O\xd6\x9f\xef\xd5?' +p50 +tp51 +bag0 +(g1 +(I0 +tp52 +g3 +tp53 +Rp54 +(I1 +(I3 +I1 +tp55 +g10 +I00 +S'\x98T\xfa=4Y\x01\xc0\xa0\x1d\xec\xcf\xe3\x13\xfc\xbfQF\xaa\x1e\xc5\xd2\xd5?' +p56 +tp57 +bag0 +(g1 +(I0 +tp58 +g3 +tp59 +Rp60 +(I1 +(I3 +I1 +tp61 +g10 +I00 +S'\xe1D\x8fMif\x01\xc0F\xf5\xdd\x9f\x15\x14\xfc\xbf\x7fs!\xfe\xa9f\xd5?' +p62 +tp63 +bag0 +(g1 +(I0 +tp64 +g3 +tp65 +Rp66 +(I1 +(I3 +I1 +tp67 +g10 +I00 +S'g\xe6\xe4\x12vp\x01\xc0*:H9\xea\x16\xfc\xbf?\x1a\\#\x8f"\xd5?' +p68 +tp69 +bag0 +(g1 +(I0 +tp70 +g3 +tp71 +Rp72 +(I1 +(I3 +I1 +tp73 +g10 +I00 +S'\x7fl\xa7\x80\xe0q\x01\xc0\xe3\x16\xdd\x00\xf0\x13\xfc\xbf\x97b\xd3\nk\xc0\xd4?' +p74 +tp75 +bag0 +(g1 +(I0 +tp76 +g3 +tp77 +Rp78 +(I1 +(I3 +I1 +tp79 +g10 +I00 +S'\xbbO\xa4\x07o\xa0\xbcRV\xfd?\x0e\x83c\x9at\xeb\xf2?' +p140 +tp141 +bag0 +(g1 +(I0 +tp142 +g3 +tp143 +Rp144 +(I1 +(I3 +I1 +tp145 +g10 +I00 +S'w\xc4U3\xf0\xf3\xff?\x07[\x0fK\x1f5\xfd?\x8f[9H \xe9\xf2?' +p146 +tp147 +bag0 +(g1 +(I0 +tp148 +g3 +tp149 +Rp150 +(I1 +(I3 +I1 +tp151 +g10 +I00 +S'`\xce(\x9e%\xfd\xff?\xf1\x07|2E\x1e\xfd?G5\xfe\xba\xd0\xdc\xf2?' +p152 +tp153 +bag0 +(g1 +(I0 +tp154 +g3 +tp155 +Rp156 +(I1 +(I3 +I1 +tp157 +g10 +I00 +S'\xbd\x95\x93\xa5\x03\xfd\xff?s$\x8fW)\x12\xfd?\x98\xf8P\xa7`\xcf\xf2?' +p158 +tp159 +bag0 +(g1 +(I0 +tp160 +g3 +tp161 +Rp162 +(I1 +(I3 +I1 +tp163 +g10 +I00 +S'9\xc5 \x8aC\xfa\xff?\x83\xb3\xa6\xf6v\x0b\xfd?\xdb$\x08\xd5\xa0\xbe\xf2?' +p164 +tp165 +bag0 +(g1 +(I0 +tp166 +g3 +tp167 +Rp168 +(I1 +(I3 +I1 +tp169 +g10 +I00 +S'JGk\x95\xac\xf6\xff?5}\x1bWz\x02\xfd?\x16\xac\xaf6\x9a\xb6\xf2?' +p170 +tp171 +bag0 +(g1 +(I0 +tp172 +g3 +tp173 +Rp174 +(I1 +(I3 +I1 +tp175 +g10 +I00 +S'\xdb\xcazL[\xf8\xff??\xc6\xe4[^\xf8\xfc?\xf2\xa4\xdc\xab\xe3\xfc?\xef7\xee\xe3\xa0\x9b\xf2?' +p194 +tp195 +bag0 +(g1 +(I0 +tp196 +g3 +tp197 +Rp198 +(I1 +(I3 +I1 +tp199 +g10 +I00 +S'\x91\xc6\xe3]\xe7\xf7\xff?]\x91?8\x85\xde\xfc?Se\x02k\xb4\x8c\xf2?' +p200 +tp201 +bag0 +(g1 +(I0 +tp202 +g3 +tp203 +Rp204 +(I1 +(I3 +I1 +tp205 +g10 +I00 +S'\xdc\xb1\x96DH\x02\x00@\xbe\x91=wg\xdb\xfc?w,\xdd`\x8bd\xf2?' +p206 +tp207 +bag0 +(g1 +(I0 +tp208 +g3 +tp209 +Rp210 +(I1 +(I3 +I1 +tp211 +g10 +I00 +S'\x85.\xbbB\xb7\xb0\xfe?\xce\x9b\xe2SzR\xf9?\x91\xfe\xdc\r\x1b\x9c\xf1?' +p212 +tp213 +bag0 +(g1 +(I0 +tp214 +g3 +tp215 +Rp216 +(I1 +(I3 +I1 +tp217 +g10 +I00 +S'^\xf3\xc44a\xb1\xfe?\xb7\xbb\x8ef\xa1S\xf9?\x0e\xf0\x8c\xe8k\x97\xf1?' +p218 +tp219 +bag0 +(g1 +(I0 +tp220 +g3 +tp221 +Rp222 +(I1 +(I3 +I1 +tp223 +g10 +I00 +S'\xa1\xe4j.M\xab\xfe?\xfdP\xb3W\nW\xf9?\xa0l\xca\xc2\xb5\x95\xf1?' +p224 +tp225 +bag0 +(g1 +(I0 +tp226 +g3 +tp227 +Rp228 +(I1 +(I3 +I1 +tp229 +g10 +I00 +S'/2^\xc2J\xac\xfe?C\xf6\x06\x8fzf\xf9?A\xf3\r\x82\xdc\x83\xf1?' +p230 +tp231 +bag0 +(g1 +(I0 +tp232 +g3 +tp233 +Rp234 +(I1 +(I3 +I1 +tp235 +g10 +I00 +S'J\x10kW\xd4O\x01@\xf0\x13\xd8\xd7>\xd7\xfd?c)\xd12\xae\xd6\xe6?' +p236 +tp237 +bag0 +(g1 +(I0 +tp238 +g3 +tp239 +Rp240 +(I1 +(I3 +I1 +tp241 +g10 +I00 +S'4s\x0f\xeco\x03\x00\xc0\x9fR2P.Q\xfe\xbf\x87=\xa1\xfc@<\xd1?' +p242 +tp243 +bag0 +(g1 +(I0 +tp244 +g3 +tp245 +Rp246 +(I1 +(I3 +I1 +tp247 +g10 +I00 +S'\x10K\x1a\xeeE\xb7\xff\xbf\xa7\xea)9\xf1K\xfe\xbf \xd4;\xc4+\x1e\xd3?' +p248 +tp249 +bag0 +(g1 +(I0 +tp250 +g3 +tp251 +Rp252 +(I1 +(I3 +I1 +tp253 +g10 +I00 +S'\xe2\x1bC\x87\x89\x97\xff\xbf\x9d\xde\x117{Y\xfe\xbf\x1d\xe2\xb1\x08\xf7D\xd3?' +p254 +tp255 +bag0 +(g1 +(I0 +tp256 +g3 +tp257 +Rp258 +(I1 +(I3 +I1 +tp259 +g10 +I00 +S'\xb0\x01\x8cW\x9c\x89\xff\xbf\x15\xa8\x14<1U\xfe\xbf\xd0\x13\xca\t\xfd\x88\xd2?' +p260 +tp261 +bag0 +(g1 +(I0 +tp262 +g3 +tp263 +Rp264 +(I1 +(I3 +I1 +tp265 +g10 +I00 +S'\xd9<\xba\xac\xee\x88\xff\xbf\x92\x03,\xc6\xfdf\xfe\xbfL\xfc \xa0i)\xd1?' +p266 +tp267 +bag0 +(g1 +(I0 +tp268 +g3 +tp269 +Rp270 +(I1 +(I3 +I1 +tp271 +g10 +I00 +S'iQ\x00\xb7\x14\x98\xff\xbf^\xeb\xd20\xfb{\xfe\xbfE\x8f^\xca\x8e_\xd1?' +p272 +tp273 +bag0 +(g1 +(I0 +tp274 +g3 +tp275 +Rp276 +(I1 +(I3 +I1 +tp277 +g10 +I00 +S'|\xad\x9a\x1cf\xd6\xff\xbf\x88\xdf\xeb\x0f2\xac\xfe\xbf\xa4o\x8e\x98\xbdd\xd2?' +p278 +tp279 +bag0 +(g1 +(I0 +tp280 +g3 +tp281 +Rp282 +(I1 +(I3 +I1 +tp283 +g10 +I00 +S'\xf5\xe9\x87\xab\xec\xf0\x00@\x93\xa4\x07\x9b\xe5D\xff?G\xf8]\xbf>o\xe2\xbf' +p284 +tp285 +bag0 +(g1 +(I0 +tp286 +g3 +tp287 +Rp288 +(I1 +(I3 +I1 +tp289 +g10 +I00 +S'|\x14\xec\xaa\xb2\xe1\x00@z\xe5\x84[\xa6\xc5\xfe?\xf6~\xa2p\xb6\xae\xe2\xbf' +p290 +tp291 +bag0 +(g1 +(I0 +tp292 +g3 +tp293 +Rp294 +(I1 +(I3 +I1 +tp295 +g10 +I00 +S'8%{\xcf\x17\xe7\x00@\\\xcb\xdap\x11\xba\xfe?j\xcd[\xbb\x99\xa3\xe2\xbf' +p296 +tp297 +bag0 +(g1 +(I0 +tp298 +g3 +tp299 +Rp300 +(I1 +(I3 +I1 +tp301 +g10 +I00 +S'\x07\r\xb8xB\xea\x00@\xdbb\xeb\x1c#\xbc\xfe?F\x89*\x9a\xb3\x93\xe2\xbf' +p302 +tp303 +bag0 +(g1 +(I0 +tp304 +g3 +tp305 +Rp306 +(I1 +(I3 +I1 +tp307 +g10 +I00 +S'\x91\x9a\xab\xcb~\xa6\x00@\x8f\xbe7\xb8\xb3\xc2\xf9?/3_\x15\xda\xcf\xb1\xbf' +p308 +tp309 +bag0 +(g1 +(I0 +tp310 +g3 +tp311 +Rp312 +(I1 +(I3 +I1 +tp313 +g10 +I00 +S'\x19\x0eU\x86\xd7\xa7\x00@\x0b\xaaS|\xeb\xd4\xf9?\n}\xa3;\xdc\x90\xaf\xbf' +p314 +tp315 +bag0 +(g1 +(I0 +tp316 +g3 +tp317 +Rp318 +(I1 +(I3 +I1 +tp319 +g10 +I00 +S'\xb0d\xd8z\x1b\xa9\x00@-\xe8\x8c}\x82\xf3\xf9?Nu\tK\xdd\xfe\xab\xbf' +p320 +tp321 +bag0 +(g1 +(I0 +tp322 +g3 +tp323 +Rp324 +(I1 +(I3 +I1 +tp325 +g10 +I00 +S'\xa4\xe2\x1dC{\xab\x00@\xc8\xd0\xd7\x11D\x02\xfa?H;\x9ep\xc0\xee\xad\xbf' +p326 +tp327 +bag0 +(g1 +(I0 +tp328 +g3 +tp329 +Rp330 +(I1 +(I3 +I1 +tp331 +g10 +I00 +S'\xbfb\x7f\xe4C\xad\x00@?\x19;c\x1a\x14\xfa?\x01\x85\xe2\x0c\xf5K\xb1\xbf' +p332 +tp333 +bag0 +(g1 +(I0 +tp334 +g3 +tp335 +Rp336 +(I1 +(I3 +I1 +tp337 +g10 +I00 +S'i\xfb\xd0\xc8|\xbb\x00\xc0w\xa8\x91\x82\xbfT\x01\xc0\xc5D_\xbc\x9bT\xe4?' +p338 +tp339 +bag0 +(g1 +(I0 +tp340 +g3 +tp341 +Rp342 +(I1 +(I3 +I1 +tp343 +g10 +I00 +S'\xe8\x91\xf5k\x9bn\x00\xc0\xb9&{\xf8t5\x01\xc0g\xaexh\xdfx\xe5?' +p344 +tp345 +bag0 +(g1 +(I0 +tp346 +g3 +tp347 +Rp348 +(I1 +(I3 +I1 +tp349 +g10 +I00 +S'^\xf1\x91soe\x00\xc0\x14\xfb\xe5\xb2\x97/\x01\xc0P\xd2\xf4:\xf6\xe1\xe5?' +p350 +tp351 +bag0 +(g1 +(I0 +tp352 +g3 +tp353 +Rp354 +(I1 +(I3 +I1 +tp355 +g10 +I00 +S'\x99\xe2\xb2\xef\xabX\x00\xc0\x12.\x0c\x88\x93)\x01\xc0\xfa\xdd\x13\xdd\x05\xd6\xe5?' +p356 +tp357 +bag0 +(g1 +(I0 +tp358 +g3 +tp359 +Rp360 +(I1 +(I3 +I1 +tp361 +g10 +I00 +S'\xe2\xb6\x12e\xac\x18\xfe\xbf\x17\xc9Q\xac\x95\xaa\xfb\xbf[\x00f\xe9\xa0\xb9\xbf\xbf' +p362 +tp363 +bag0 +(g1 +(I0 +tp364 +g3 +tp365 +Rp366 +(I1 +(I3 +I1 +tp367 +g10 +I00 +S'\x89\xb3\x9f\xa48:\xfe\xbf\xc2\x99\xe3\x9cJ\xa9\xfb\xbf\xeb\x1d\xc0.\xd6\xdc\xc0\xbf' +p368 +tp369 +bag0 +(g1 +(I0 +tp370 +g3 +tp371 +Rp372 +(I1 +(I3 +I1 +tp373 +g10 +I00 +S'Dt\xe4\\s=\xfe\xbf\x88\x10\xbd\xc0*\x96\xfb\xbf\xff\x89=\xd6Y\xe2\xc1\xbf' +p374 +tp375 +bag0 +(g1 +(I0 +tp376 +g3 +tp377 +Rp378 +(I1 +(I3 +I1 +tp379 +g10 +I00 +S't\x062_0J\xfe\xbf\x1ed\t\tP\x96\xfb\xbf<\xc77oRG\xc2\xbf' +p380 +tp381 +bag0 +(g1 +(I0 +tp382 +g3 +tp383 +Rp384 +(I1 +(I3 +I1 +tp385 +g10 +I00 +S'\xe7Ma\x11\xcbW\xfe\xbf1\xf4\x98<\xed\x9c\xfb\xbf\n\xc4\xd2\x7f\xb5w\xc2\xbf' +p386 +tp387 +bag0 +(g1 +(I0 +tp388 +g3 +tp389 +Rp390 +(I1 +(I3 +I1 +tp391 +g10 +I00 +S'\xac\x97\x1d\xc0\xb8U\xfe\xbf\x93\xa9!c\xd4\x97\xfb\xbfz\xd6\x1f?*$\xc3\xbf' +p392 +tp393 +bag0 +(g1 +(I0 +tp394 +g3 +tp395 +Rp396 +(I1 +(I3 +I1 +tp397 +g10 +I00 +S'7C\x8a\xc1\xc0r\xfe\xbfwm\xe3\x9c\xfe\xa1\xfb\xbf?\xc2{\x95R\x82\xc3\xbf' +p398 +tp399 +bag0 +(g1 +(I0 +tp400 +g3 +tp401 +Rp402 +(I1 +(I3 +I1 +tp403 +g10 +I00 +S'L\xdb/\xc3s\x85\xfe\xbf\xb3Ei\x96\x1f\xa9\xfb\xbfK\x90\xe3P\x9f\xb9\xc3\xbf' +p404 +tp405 +bag0 +(g1 +(I0 +tp406 +g3 +tp407 +Rp408 +(I1 +(I3 +I1 +tp409 +g10 +I00 +S'\xebH\xbe0\x88\x92\xfe\xbf\xde\r\x05Z\x97\xad\xfb\xbf\xbc(\xd3\x83K5\xc4\xbf' +p410 +tp411 +bag0 +(g1 +(I0 +tp412 +g3 +tp413 +Rp414 +(I1 +(I3 +I1 +tp415 +g10 +I00 +S's\x02k\x02\xa7\xad\xfe\xbf\xf8\xe2?\x8c\x05\xbd\xfb\xbfR\xeb3\xb8\x9d\x97\xc4\xbf' +p416 +tp417 +bag0 +(g1 +(I0 +tp418 +g3 +tp419 +Rp420 +(I1 +(I3 +I1 +tp421 +g10 +I00 +S'\x06\x82\xc3\xdc\x10\x95\x01@o\x8e\x1b\xd8W\xed\xfd?\xf0\xefF\xbd\x1d\xc1\xf0?' +p422 +tp423 +bag0 +(g1 +(I0 +tp424 +g3 +tp425 +Rp426 +(I1 +(I3 +I1 +tp427 +g10 +I00 +S'\xc4\xbe\xca\xddM\x94\x01@\x15p\x03g\xbb\xef\xfd?\xed\x07D<\xb1\xbc\xf0?' +p428 +tp429 +bag0 +(g1 +(I0 +tp430 +g3 +tp431 +Rp432 +(I1 +(I3 +I1 +tp433 +g10 +I00 +S'\x897)\xb3\xc5\x93\x01@_\xe1XB3\xee\xfd?T\xdf\xa8\x1c-\xc0\xf0?' +p434 +tp435 +bag0 +(g1 +(I0 +tp436 +g3 +tp437 +Rp438 +(I1 +(I3 +I1 +tp439 +g10 +I00 +S'\x9ee\xe1 @\x93\x01@\xe6\xdb\x991\xde\xe1\xfd?\xd4\x87\xd37u\xc5\xf0?' +p440 +tp441 +bag0 +(g1 +(I0 +tp442 +g3 +tp443 +Rp444 +(I1 +(I3 +I1 +tp445 +g10 +I00 +S'\xc4n+\x14\x00\x92\x01@H?\x12\x04K\xd5\xfd?E rg\x18\xc7\xf0?' +p446 +tp447 +bag0 +(g1 +(I0 +tp448 +g3 +tp449 +Rp450 +(I1 +(I3 +I1 +tp451 +g10 +I00 +S'\x08w\xf1\xb7i\x93\x01@\x96\x0fh.\xb4\xcd\xfd?3\xf9\xf4H\xdd\xbe\xf0?' +p452 +tp453 +bag0 +(g1 +(I0 +tp454 +g3 +tp455 +Rp456 +(I1 +(I3 +I1 +tp457 +g10 +I00 +S'Oq\xf9\xe0\x97\x96\x01@\xf7R\x96a\x01\xcc\xfd?\xb9s\x01\xf5B\xab\xf0?' +p458 +tp459 +bag0 +(g1 +(I0 +tp460 +g3 +tp461 +Rp462 +(I1 +(I3 +I1 +tp463 +g10 +I00 +S'\x12[\xfby\x81\x9f\x01@\x17\xf8\x97Y\x8c\xc8\xfd?\xde\x0e(\x08:m\xf0?' +p464 +tp465 +bag0 +(g1 +(I0 +tp466 +g3 +tp467 +Rp468 +(I1 +(I3 +I1 +tp469 +g10 +I00 +S'1\xb4\x9b*v\xa6\x01@\xc7b\x14#E\xca\xfd?\xd7\xa7\x9d\x12OZ\xf0?' +p470 +tp471 +bag0 +(g1 +(I0 +tp472 +g3 +tp473 +Rp474 +(I1 +(I3 +I1 +tp475 +g10 +I00 +S'=\xf9\x97\xd4\xc5\xad\x01@\xc9\x15\xa5B\xa2\xcd\xfd?\xd97\x91?AH\xf0?' +p476 +tp477 +bag0 +(g1 +(I0 +tp478 +g3 +tp479 +Rp480 +(I1 +(I3 +I1 +tp481 +g10 +I00 +S' \x8b\xb6\x02\x8e\xb1\x01@1\x04[\xc55\xce\xfd?\x12\x92\xaf\x03\xdcE\xf0?' +p482 +tp483 +bag0 +(g1 +(I0 +tp484 +g3 +tp485 +Rp486 +(I1 +(I3 +I1 +tp487 +g10 +I00 +S'\xd4\xff\xa1hz\xb2\x01@\xa6\xa6]=\xcd\xd0\xfd?\x1e\x9b\x11H\xd29\xf0?' +p488 +tp489 +bag0 +(g1 +(I0 +tp490 +g3 +tp491 +Rp492 +(I1 +(I3 +I1 +tp493 +g10 +I00 +S";.\x89\xf9\x83\xb0\x01@\xeb\x03\x0c\x9cw\xd8\xfd?/'|\xbe\xeb'\xf0?" +p494 +tp495 +bag0 +(g1 +(I0 +tp496 +g3 +tp497 +Rp498 +(I1 +(I3 +I1 +tp499 +g10 +I00 +S'h\xd6\x01\x0cq\xb1\x01@\xe4\xd3+\xfd\x8a\xe9\xfd?\xd3\x91\n#8 \xf0?' +p500 +tp501 +ba(lp502 +g0 +(g1 +(I0 +tp503 +g3 +tp504 +Rp505 +(I1 +(I3 +I1 +tp506 +g10 +I00 +S't2EQ\xe5\xb4\xd0\xbf\x16\xc1\xb7\xd16\xe5\xa7\xbfO9\xc0Bq \xe0?' +p507 +tp508 +bag0 +(g1 +(I0 +tp509 +g3 +tp510 +Rp511 +(I1 +(I3 +I1 +tp512 +g10 +I00 +S'\x114\xe2h\xbc\xb0\xd0\xbf\x7f`\x02\xfc\xbe\xa8\xa7\xbf\xfbl\xc1\xe5\xdb\x18\xe0?' +p513 +tp514 +bag0 +(g1 +(I0 +tp515 +g3 +tp516 +Rp517 +(I1 +(I3 +I1 +tp518 +g10 +I00 +S',]\xfd0\xd1\xe8\xa1\xbf\x87c\x8eE\xdc\xf6\xb1\xbfM\x9b\xa1\x99\xe6V\xe4?' +p519 +tp520 +bag0 +(g1 +(I0 +tp521 +g3 +tp522 +Rp523 +(I1 +(I3 +I1 +tp524 +g10 +I00 +S'\xa6\x88\xdbf\x84\xa2\xa1\xbf\\\xce\xd2V\xa8\x04\xb2\xbfds#\xca"a\xe4?' +p525 +tp526 +bag0 +(g1 +(I0 +tp527 +g3 +tp528 +Rp529 +(I1 +(I3 +I1 +tp530 +g10 +I00 +S'\xd5&\x89\x94\xcc\xbc\xa1\xbf\xd5\x0e;\xee,\xc3\xb1\xbfp\xe4\r\x18\x9dc\xe4?' +p531 +tp532 +bag0 +(g1 +(I0 +tp533 +g3 +tp534 +Rp535 +(I1 +(I3 +I1 +tp536 +g10 +I00 +S'\xc6\x8fjO>\xce\xa1\xbf\x98%JS\x03t\xb1\xbf\xbaW\x08\xe9\x86f\xe4?' +p537 +tp538 +bag0 +(g1 +(I0 +tp539 +g3 +tp540 +Rp541 +(I1 +(I3 +I1 +tp542 +g10 +I00 +S'F(\xbd\xd0\x14\xe2\xa1\xbf\xe9\xee\x14S:@\xb1\xbf\xd8\x8e\x11\x8e\xd7h\xe4?' +p543 +tp544 +bag0 +(g1 +(I0 +tp545 +g3 +tp546 +Rp547 +(I1 +(I3 +I1 +tp548 +g10 +I00 +S'\x1b\xc2&\xaa%\xe4\xa1\xbf\xfa\xa4\xf8\\\xba<\xb1\xbf\x80\xecX]\xa6l\xe4?' +p549 +tp550 +bag0 +(g1 +(I0 +tp551 +g3 +tp552 +Rp553 +(I1 +(I3 +I1 +tp554 +g10 +I00 +S'c,b\xb8\xfe\xc4\xa1\xbf\xdf\x9f=\x06h\\\xb1\xbf\xad\xf9\x19 \x19j\xe4?' +p555 +tp556 +bag0 +(g1 +(I0 +tp557 +g3 +tp558 +Rp559 +(I1 +(I3 +I1 +tp560 +g10 +I00 +S'\xe6\xb2t\xdc\xef~\xa1\xbf\x96\xcf\xef\x16\xab\x9e\xb1\xbf(\xf51\xc0th\xe4?' +p561 +tp562 +bag0 +(g1 +(I0 +tp563 +g3 +tp564 +Rp565 +(I1 +(I3 +I1 +tp566 +g10 +I00 +S'dU\x1e\xb2Z\x99\xa1\xbf\xec\xf1s\x1d\xbb\x15\xb2\xbfW\xd9\xa4\x0f\x9aQ\xe4?' +p567 +tp568 +bag0 +(g1 +(I0 +tp569 +g3 +tp570 +Rp571 +(I1 +(I3 +I1 +tp572 +g10 +I00 +S'\xa1n\xa8\x97\xe7\x0b\xaf\xbf\xfe\xe4y\xf0\xdc\x07\xb6\xbf\x1c*|\x0c\n\xfa\xe2?' +p573 +tp574 +bag0 +(g1 +(I0 +tp575 +g3 +tp576 +Rp577 +(I1 +(I3 +I1 +tp578 +g10 +I00 +S'9"7R\xfb<\xae\xbf\\"@\xf4\x8a\xb0\xb5\xbf\xa8\xcdc4\x9d\xfc\xe2?' +p579 +tp580 +bag0 +(g1 +(I0 +tp581 +g3 +tp582 +Rp583 +(I1 +(I3 +I1 +tp584 +g10 +I00 +S'\xe50\xe7<\x19\xd6\xad\xbf\xeb\xc1\x91tZ\x86\xb5\xbf\x85\x8b\xbc1L\x00\xe3?' +p585 +tp586 +bag0 +(g1 +(I0 +tp587 +g3 +tp588 +Rp589 +(I1 +(I3 +I1 +tp590 +g10 +I00 +S'\x18\x8a\x00\xc6\x9d\xa6\xad\xbf\x91V@w$W\xb5\xbf\x1e>\x07\xa2\xba\xf9\xe2?' +p591 +tp592 +bag0 +(g1 +(I0 +tp593 +g3 +tp594 +Rp595 +(I1 +(I3 +I1 +tp596 +g10 +I00 +S'}4\xe3\x80O\xe7\xad\xbfB1\xafy\xa0D\xb5\xbf+\x8cu"\xcf\xeb\xe2?' +p597 +tp598 +bag0 +(g1 +(I0 +tp599 +g3 +tp600 +Rp601 +(I1 +(I3 +I1 +tp602 +g10 +I00 +S'\xc5&\xa1\xda\x93\xe6\xc5\xbf\xd6GD\xde\x92X\xa0\xbf\x96vd\xd5\x9b\xa3\xd2?' +p603 +tp604 +bag0 +(g1 +(I0 +tp605 +g3 +tp606 +Rp607 +(I1 +(I3 +I1 +tp608 +g10 +I00 +S'\xde\xfa\x96*z^\xc7\xbfX\xea3=b\xc1\xa2\xbf`15Lx\xab\xd2?' +p609 +tp610 +bag0 +(g1 +(I0 +tp611 +g3 +tp612 +Rp613 +(I1 +(I3 +I1 +tp614 +g10 +I00 +S'\x15\x03\xee\x02\x0f\x8f\xc7\xbf\xc7De\x16T&\xa3\xbf\x83\xcb\x81#\xdc\xbf\xd2?' +p615 +tp616 +bag0 +(g1 +(I0 +tp617 +g3 +tp618 +Rp619 +(I1 +(I3 +I1 +tp620 +g10 +I00 +S'z\x9f,\t\x1e\x9f\xc7\xbf\xbb\x81\x0ed\x89\xa5\xa2\xbfk\xe9m\xd9\x7f\xb7\xd2?' +p621 +tp622 +bag0 +(g1 +(I0 +tp623 +g3 +tp624 +Rp625 +(I1 +(I3 +I1 +tp626 +g10 +I00 +S'\x01\x84\xaa\xb9\xf3\xb3\xc7\xbf~\xbe\x08\xfc\x08\x0b\xa2\xbfL)\xd1\xaa\xe0\xbb\xd2?' +p627 +tp628 +bag0 +(g1 +(I0 +tp629 +g3 +tp630 +Rp631 +(I1 +(I3 +I1 +tp632 +g10 +I00 +S'\x81\x13K\x08\x83\xb8\xc7\xbf\n\x1c\xcb\xb3\x86\xe1\xa1\xbfI\x81BR\x84\xca\xd2?' +p633 +tp634 +bag0 +(g1 +(I0 +tp635 +g3 +tp636 +Rp637 +(I1 +(I3 +I1 +tp638 +g10 +I00 +S'H\x8a\x96\x921\xa6\xc7\xbf\x93K\xe9\x03@\x0e\xa2\xbf\xc5\xe8\x12\x1a\x0f\xd7\xd2?' +p639 +tp640 +bag0 +(g1 +(I0 +tp641 +g3 +tp642 +Rp643 +(I1 +(I3 +I1 +tp644 +g10 +I00 +S'\x90\x8b\xa3\xa4>\x93\xc7\xbf\r\xfc.\xc8*j\xa2\xbf\xc3\xeehm\x9b\xe2\xd2?' +p645 +tp646 +bag0 +(g1 +(I0 +tp647 +g3 +tp648 +Rp649 +(I1 +(I3 +I1 +tp650 +g10 +I00 +S'\x04\xef\xb3\x0b\xb5\x81\xc7\xbf\x11\xcf\xe4=\x84\xbb\xa2\xbf\xcf#B\x91\x9b\xe5\xd2?' +p651 +tp652 +bag0 +(g1 +(I0 +tp653 +g3 +tp654 +Rp655 +(I1 +(I3 +I1 +tp656 +g10 +I00 +S'\xda:\xe3\xe1J\x7f\xc7\xbfn\x01\xcc\xd0\x96\xcd\xa2\xbf\x95W\x0b\xd3\xab\xee\xd2?' +p657 +tp658 +bag0 +(g1 +(I0 +tp659 +g3 +tp660 +Rp661 +(I1 +(I3 +I1 +tp662 +g10 +I00 +S'\xfa\x8c\xac\x8d\xeb\x8c\xc7\xbf\xd9\x83\x0b!\xea\xf8\xa2\xbf*y\x11+\xf5\xfa\xd2?' +p663 +tp664 +bag0 +(g1 +(I0 +tp665 +g3 +tp666 +Rp667 +(I1 +(I3 +I1 +tp668 +g10 +I00 +S'(\xfe%{}\x94\xc7\xbfp\xcd\xf5_p-\xa3\xbf\x97\xce\xcc\x91\xea\xff\xd2?' +p669 +tp670 +bag0 +(g1 +(I0 +tp671 +g3 +tp672 +Rp673 +(I1 +(I3 +I1 +tp674 +g10 +I00 +S'$\xe8\xb4\xb0\xaa\x9f\xc7\xbf\x80\x1bX\xf8Ud\xa3\xbfG\r\x1b\x0e5\n\xd3?' +p675 +tp676 +bag0 +(g1 +(I0 +tp677 +g3 +tp678 +Rp679 +(I1 +(I3 +I1 +tp680 +g10 +I00 +S'\xcd\x83\x85\x15\xe7\xab\xc7\xbf\xb7/\x86\xc7\xed\xa1\xa3\xbf#\xfc\x17\xbeh\x15\xd3?' +p681 +tp682 +bag0 +(g1 +(I0 +tp683 +g3 +tp684 +Rp685 +(I1 +(I3 +I1 +tp686 +g10 +I00 +S'_\x00|\xd0\x16\xcd\xc7\xbf\x00KZg!>\xa4\xbf\xf84\xa1&\xa4.\xd3?' +p687 +tp688 +bag0 +(g1 +(I0 +tp689 +g3 +tp690 +Rp691 +(I1 +(I3 +I1 +tp692 +g10 +I00 +S')\x15 \xdc\xd7\xb7\xc9\xbf\xb4\xa8\x1f\x11\xc71\xa4\xbf\xff\xcd\xccG4w\xd5?' +p693 +tp694 +bag0 +(g1 +(I0 +tp695 +g3 +tp696 +Rp697 +(I1 +(I3 +I1 +tp698 +g10 +I00 +S'`\xce\x1f)\xec\xb9\xc9\xbf>\xaf\xdf01"\xa4\xbf\xa0\x9e\xff\xf3(z\xd5?' +p699 +tp700 +bag0 +(g1 +(I0 +tp701 +g3 +tp702 +Rp703 +(I1 +(I3 +I1 +tp704 +g10 +I00 +S'\xef\x12-\xe4\xd3\xb6\xc9\xbf\xba\xa0\x92\xac\x806\xa4\xbf\xa6\xbdg\\]v\xd5?' +p705 +tp706 +bag0 +(g1 +(I0 +tp707 +g3 +tp708 +Rp709 +(I1 +(I3 +I1 +tp710 +g10 +I00 +S'S\xb2\xf8q\x9a\xc6\xc9\xbf\x13\xcb\x1a\xc8\xbcB\xa4\xbf\n\xc7Y\xb4\xb0z\xd5?' +p711 +tp712 +bag0 +(g1 +(I0 +tp713 +g3 +tp714 +Rp715 +(I1 +(I3 +I1 +tp716 +g10 +I00 +S'\xbb\xc1a\x91xl\xcc\xbf\xb1\xdeu\x04\\\x01\xad\xbfHl\xb0\xe41\xc3\xd9?' +p717 +tp718 +bag0 +(g1 +(I0 +tp719 +g3 +tp720 +Rp721 +(I1 +(I3 +I1 +tp722 +g10 +I00 +S'L\x18\xfd-\x81{\xc6\xbf\xcb\xd9k\x06L\x0c\xb6\xbfG\x05R\x0e6\xad\xe1?' +p723 +tp724 +bag0 +(g1 +(I0 +tp725 +g3 +tp726 +Rp727 +(I1 +(I3 +I1 +tp728 +g10 +I00 +S'@\x0e)_JT\xc6\xbf\xee\xce\xbc\x03\x11S\xb6\xbf\xe35\x06\x94?\xcb\xe1?' +p729 +tp730 +bag0 +(g1 +(I0 +tp731 +g3 +tp732 +Rp733 +(I1 +(I3 +I1 +tp734 +g10 +I00 +S'!\xe5\xdc\xa3\xb8i\xc6\xbf\\\xbc\x06\xc3p\x82\xb6\xbf*\x92\xec\x99&\xc3\xe1?' +p735 +tp736 +bag0 +(g1 +(I0 +tp737 +g3 +tp738 +Rp739 +(I1 +(I3 +I1 +tp740 +g10 +I00 +S'v\x01Ei\xe2u\xc6\xbf},\xb84\xe2L\xb6\xbf\xe3DgP\xdc\xa7\xe1?' +p741 +tp742 +bag0 +(g1 +(I0 +tp743 +g3 +tp744 +Rp745 +(I1 +(I3 +I1 +tp746 +g10 +I00 +S'\xad\x0c\xcc\xa8\xdbO\xc6\xbfR\xe6\xed\xd2\xc5\x8d\xb5\xbfl{"Wo\x83\xe1?' +p747 +tp748 +bag0 +(g1 +(I0 +tp749 +g3 +tp750 +Rp751 +(I1 +(I3 +I1 +tp752 +g10 +I00 +S'\x19\xc1\xe7\xe3\xb1Q\xc6\xbf\x01c\x9f\xdd\x0cT\xb5\xbf\x0b\xc5\xdb\x1c[\x88\xe1?' +p753 +tp754 +bag0 +(g1 +(I0 +tp755 +g3 +tp756 +Rp757 +(I1 +(I3 +I1 +tp758 +g10 +I00 +S'\x97\xafb\xdffi\xc6\xbfX\xfap\x9e\xeaL\xb5\xbf?D\xc5\xd6\x12\x95\xe1?' +p759 +tp760 +bag0 +(g1 +(I0 +tp761 +g3 +tp762 +Rp763 +(I1 +(I3 +I1 +tp764 +g10 +I00 +S'"1\x05\\F"\xc8\xbf\xf4\xed\x08u\xc4\x9d\xa8\xbf;E\xce\xc5m\xa8\xe1?' +p765 +tp766 +bag0 +(g1 +(I0 +tp767 +g3 +tp768 +Rp769 +(I1 +(I3 +I1 +tp770 +g10 +I00 +S'\xe7\xc8\xc9h\x87V\xc8\xbf\x02H\x01\x1e\x18\x8a\xa8\xbf\xc5oW\x8e{\xa9\xe1?' +p771 +tp772 +bag0 +(g1 +(I0 +tp773 +g3 +tp774 +Rp775 +(I1 +(I3 +I1 +tp776 +g10 +I00 +S'\xf5\x89Sy\x1ed\xc8\xbf\x08\xea\xfc\x98^c\xa8\xbfv\x89\t2G\xa4\xe1?' +p777 +tp778 +bag0 +(g1 +(I0 +tp779 +g3 +tp780 +Rp781 +(I1 +(I3 +I1 +tp782 +g10 +I00 +S'\xb2\xcb\x04\xa3\xa8Z\xc8\xbf\xe9i\xb9\xa9r\xed\xa7\xbf\x1f*\x83\xfa\x13\x9d\xe1?' +p783 +tp784 +bag0 +(g1 +(I0 +tp785 +g3 +tp786 +Rp787 +(I1 +(I3 +I1 +tp788 +g10 +I00 +S'\xe5d\x7f\xd2\xb6\xc9\xc5\xbf(i\xfd\x95\t?\xb3\xbf\xa5?dZ`e\xd8?' +p789 +tp790 +bag0 +(g1 +(I0 +tp791 +g3 +tp792 +Rp793 +(I1 +(I3 +I1 +tp794 +g10 +I00 +S't\rI\xdf\x11\xb7\xc5\xbf\x04\xfd\x96\xc3\xeag\xb3\xbf\xf3\xb1\xff\xd4\x0fm\xd8?' +p795 +tp796 +bag0 +(g1 +(I0 +tp797 +g3 +tp798 +Rp799 +(I1 +(I3 +I1 +tp800 +g10 +I00 +S'9p\xee\xef\xfe\xac\xc5\xbf*\x88\x94\x13{+\xb3\xbf\x01\xc0\xaeA\xa3`\xd8?' +p801 +tp802 +bag0 +(g1 +(I0 +tp803 +g3 +tp804 +Rp805 +(I1 +(I3 +I1 +tp806 +g10 +I00 +S'K[R\xc1\x07\xb8\xc5\xbfh\x12\x8fJk\x16\xb3\xbf\xba\x94\xfe\xd7\xb0h\xd8?' +p807 +tp808 +bag0 +(g1 +(I0 +tp809 +g3 +tp810 +Rp811 +(I1 +(I3 +I1 +tp812 +g10 +I00 +S'\xb6o/x\x8a\xcc\xc5\xbf`\x1d\r\xe8\xcc.\xb3\xbf\xef\xe3n\xf8X|\xd8?' +p813 +tp814 +bag0 +(g1 +(I0 +tp815 +g3 +tp816 +Rp817 +(I1 +(I3 +I1 +tp818 +g10 +I00 +S'\xdeN\x14\xe5\xf4\xfc\xbd\xbf:\x11O\x08s5\xb9\xbf\x92\xad\x1a\x1cp(\xdb?' +p819 +tp820 +bag0 +(g1 +(I0 +tp821 +g3 +tp822 +Rp823 +(I1 +(I3 +I1 +tp824 +g10 +I00 +S'\xf1"\xee\xee\x1c\x1d\xbf\xbf\x1b\xa1J\x92\xe7v\xb9\xbf#dj{\xb0Z\xdb?' +p825 +tp826 +bag0 +(g1 +(I0 +tp827 +g3 +tp828 +Rp829 +(I1 +(I3 +I1 +tp830 +g10 +I00 +S"dzi\xce'\x86\xbf\xbf\xa3\xdc\x8c;\xbfT\xb9\xbfM\x80\xb6\xf0\x01c\xdb?" +p831 +tp832 +bag0 +(g1 +(I0 +tp833 +g3 +tp834 +Rp835 +(I1 +(I3 +I1 +tp836 +g10 +I00 +S'\x1d\x96`s\xb0\xdd\xbf\xbfh$\xbfBXn\xb9\xbf\x14d\x93\x13>]\xdb?' +p837 +tp838 +bag0 +(g1 +(I0 +tp839 +g3 +tp840 +Rp841 +(I1 +(I3 +I1 +tp842 +g10 +I00 +S'\xa3\xe0\xc3\x1e\xeb\xf4\xc7\xbf\x06\xae\x06\xb2\x14G\xb3\xbf \x87P\x94\x9f\x9a\xd3?' +p843 +tp844 +bag0 +(g1 +(I0 +tp845 +g3 +tp846 +Rp847 +(I1 +(I3 +I1 +tp848 +g10 +I00 +S'\xe9\xeb\x83o\xab\xf6\xc7\xbf0\x96R\xf8\xd3\xb2\xb2\xbfe\x97yz\xd6\x80\xd3?' +p849 +tp850 +bag0 +(g1 +(I0 +tp851 +g3 +tp852 +Rp853 +(I1 +(I3 +I1 +tp854 +g10 +I00 +S'I)\xab\x83\xb5\xf1\xc7\xbff;\xb7\n\xe56\xb2\xbf\xca[\xb1\x0b\xdbk\xd3?' +p855 +tp856 +bag0 +(g1 +(I0 +tp857 +g3 +tp858 +Rp859 +(I1 +(I3 +I1 +tp860 +g10 +I00 +S'/\x15\x12?\xfb\xe9\xc7\xbf\xd3h\x86\xe7N\xee\xb1\xbf] \x8c\xc0\xe2d\xd3?' +p861 +tp862 +bag0 +(g1 +(I0 +tp863 +g3 +tp864 +Rp865 +(I1 +(I3 +I1 +tp866 +g10 +I00 +S'9\xf4\xc9\x9d\xc1\xea\xc7\xbf\xbb\x97:\x94\x8a\xae\xb1\xbf\xe8\x03&\x9f=c\xd3?' +p867 +tp868 +bag0 +(g1 +(I0 +tp869 +g3 +tp870 +Rp871 +(I1 +(I3 +I1 +tp872 +g10 +I00 +S'\x19\xc6&q\x9c\xf6\xc7\xbfk\x945\x93Y`\xb1\xbf_\xdbMx\xa3Y\xd3?' +p873 +tp874 +bag0 +(g1 +(I0 +tp875 +g3 +tp876 +Rp877 +(I1 +(I3 +I1 +tp878 +g10 +I00 +S'\x8e\xdc\xc7}/\xef\xc7\xbf\xe6\x80\x9c\xa0\xf8\xb7\xb0\xbf[\xdfJ\xa2+F\xd3?' +p879 +tp880 +bag0 +(g1 +(I0 +tp881 +g3 +tp882 +Rp883 +(I1 +(I3 +I1 +tp884 +g10 +I00 +S'\x99\x06\xfc\xe8\xa2\xe6\xc7\xbf5\xebem \x7f\xb0\xbf\xa3_\xe0x\x00D\xd3?' +p885 +tp886 +bag0 +(g1 +(I0 +tp887 +g3 +tp888 +Rp889 +(I1 +(I3 +I1 +tp890 +g10 +I00 +S'n]Fgc\xe2\xc7\xbf`\\\xd41;_\xb0\xbf\x84~\x05\x18\x93;\xd3?' +p891 +tp892 +bag0 +(g1 +(I0 +tp893 +g3 +tp894 +Rp895 +(I1 +(I3 +I1 +tp896 +g10 +I00 +S'\xedlv\x8e,\xdb\xc7\xbfP\x9a9d\x9d@\xb0\xbf=A\x1e0*)\xd3?' +p897 +tp898 +bag0 +(g1 +(I0 +tp899 +g3 +tp900 +Rp901 +(I1 +(I3 +I1 +tp902 +g10 +I00 +S'8\xf8\x0cx\xbam\xc2\xbf`\x8c%L/\xeb\x9d\xbfB\xef\x05\xe1~\xa1\xcf?' +p903 +tp904 +bag0 +(g1 +(I0 +tp905 +g3 +tp906 +Rp907 +(I1 +(I3 +I1 +tp908 +g10 +I00 +S'el\xd2\x056\x80\xc2\xbfh\x9b\xb7\x80\x89\x0e\x9e\xbf(\xc4I\xb1\x7f\x98\xcf?' +p909 +tp910 +bag0 +(g1 +(I0 +tp911 +g3 +tp912 +Rp913 +(I1 +(I3 +I1 +tp914 +g10 +I00 +S'e\xcf\xef?\xff}\xc2\xbf\xf6W\x88\xc7\xfa+\x9e\xbfQ\xd6\xa6\xbc\xb7\x8d\xcf?' +p915 +tp916 +bag0 +(g1 +(I0 +tp917 +g3 +tp918 +Rp919 +(I1 +(I3 +I1 +tp920 +g10 +I00 +S'\xf5)M\n\n{\xc2\xbf\xdf\x1c\x1e\xb6\xdb\xf3\x9d\xbf4\xc9\x12\x95\xb4{\xcf?' +p921 +tp922 +bag0 +(g1 +(I0 +tp923 +g3 +tp924 +Rp925 +(I1 +(I3 +I1 +tp926 +g10 +I00 +S'\x916t\xeb\xc8|\xc2\xbf\xba[\xcd/J\x9b\x9d\xbf\xff-u\xd1\xcet\xcf?' +p927 +tp928 +bag0 +(g1 +(I0 +tp929 +g3 +tp930 +Rp931 +(I1 +(I3 +I1 +tp932 +g10 +I00 +S'\r\xa9\xcc\t`\x81\xc2\xbf\xf7\xcfU%\\l\x9d\xbfc\x99\xc1\x8ct\x80\xcf?' +p933 +tp934 +bag0 +(g1 +(I0 +tp935 +g3 +tp936 +Rp937 +(I1 +(I3 +I1 +tp938 +g10 +I00 +S'\xd0\x87\xb1\xe5\xe7\x85\xc2\xbf\xe5\xbc\x05\xd5b\xd0\x9d\xbf\x04rlK\xc8\x9c\xcf?' +p939 +tp940 +bag0 +(g1 +(I0 +tp941 +g3 +tp942 +Rp943 +(I1 +(I3 +I1 +tp944 +g10 +I00 +S'S/\xd7\xdd\xcc\x97\xc2\xbf8\xcb\x90M\x83\xed\x9e\xbf-\xd2\xd5\xfc\x19\xf6\xcf?' +p945 +tp946 +bag0 +(g1 +(I0 +tp947 +g3 +tp948 +Rp949 +(I1 +(I3 +I1 +tp950 +g10 +I00 +S'my\x13\xf1]\xa8\xc2\xbfLpI\x98\xf4\xff\x9e\xbf\xf0\x15\xd9.\xf7\x12\xd0?' +p951 +tp952 +bag0 +(g1 +(I0 +tp953 +g3 +tp954 +Rp955 +(I1 +(I3 +I1 +tp956 +g10 +I00 +S'b\x1e\xc3\xe1\x95\xc9\xc2\xbf+\xea\xfd\t\xe4U\x9f\xbf\xc3\xbf5R\xa5*\xd0?' +p957 +tp958 +bag0 +(g1 +(I0 +tp959 +g3 +tp960 +Rp961 +(I1 +(I3 +I1 +tp962 +g10 +I00 +S'\xa4\x7f\x86\xbb\x92\xeb\xc2\xbf\xc0\xcc\xa20.\xe6\x9f\xbf\xde\xa9}\x19\xa3.\xd0?' +p963 +tp964 +bag0 +(g1 +(I0 +tp965 +g3 +tp966 +Rp967 +(I1 +(I3 +I1 +tp968 +g10 +I00 +S'3C3\xad\xf7\x10\xc3\xbf\r\xfd\x18\xcb\\R\xa0\xbf\xec\xbc\x1c\xf8\xdd3\xd0?' +p969 +tp970 +bag0 +(g1 +(I0 +tp971 +g3 +tp972 +Rp973 +(I1 +(I3 +I1 +tp974 +g10 +I00 +S'\x0ck\xa4\xd8\xb3.\xc3\xbfu\xe7z&[\xa0\xa0\xbf+\x16U%\xfb;\xd0?' +p975 +tp976 +bag0 +(g1 +(I0 +tp977 +g3 +tp978 +Rp979 +(I1 +(I3 +I1 +tp980 +g10 +I00 +S"\x92'\xa5\xd8RE\xc3\xbfCp\x0f\x94\xe1\xc8\xa0\xbf\xb9n\x13\xf76A\xd0?" +p981 +tp982 +batp983 +. \ No newline at end of file diff --git a/mep3_vision/mep3_vision/onrobot_camera.py b/mep3_vision/mep3_vision/onrobot_camera.py index 2f745e3bc..8ebd65218 100644 --- a/mep3_vision/mep3_vision/onrobot_camera.py +++ b/mep3_vision/mep3_vision/onrobot_camera.py @@ -10,6 +10,9 @@ from rclpy.node import Node # Handles the creation of nodes from sensor_msgs.msg import Image # Image is the message type from cv_bridge import CvBridge # Package to convert between ROS and OpenCV Images +import os +import pickle + class ImageSubscriber(Node): @@ -24,6 +27,20 @@ def __init__(self): # Initiate the Node class's constructor and give it a name super().__init__('image_subscriber') + # TODO: Calibration. Now it's just the Dummy calibration file... + if True: + f = open('/home/milos/foxy_ws/src/mep3/mep3_vision/mep3_vision/DummyCameraCalibration.pckl', 'rb') + u = pickle._Unpickler(f) + u.encoding = 'latin1' + (x, y, _, _) = u.load() + self.cameraMatrix = x + self.distCoeffs = y + f.close() + if self.cameraMatrix is None or self.distCoeffs is None: + print( + "Calibration issue. Remove ./calibration/CameraCalibration.pckl and recalibrate your camera with calibration_ChAruco.py.") + exit() + # Create the subscriber. This subscriber will receive an Image # from the video_frames topic. The queue size is 10 messages. self.subscription = self.create_subscription( @@ -44,7 +61,27 @@ def listener_callback(self, data): self.get_logger().info('Receiving video frame') # Convert ROS Image message to OpenCV image - current_frame = self.br.imgmsg_to_cv2(data) + current_frame = self.br.imgmsg_to_cv2(data, desired_encoding='bgr8') + + # Aruco detection + arucoDict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_4X4_100) + arucoParams = cv2.aruco.DetectorParameters_create() + (corners, ids, rejected) = cv2.aruco.detectMarkers(current_frame, arucoDict, + parameters=arucoParams) + + if ids is not None and len(ids) > 0: + # Estimate the posture per each Aruco marker + + + rotation_vectors, translation_vectors, _objPoints = cv2.aruco.estimatePoseSingleMarkers(corners, 1, + self.cameraMatrix, + self.distCoeffs) + + + + for rvec, tvec in zip(rotation_vectors, translation_vectors): + cv2.aruco.drawAxis(current_frame, self.cameraMatrix, self.distCoeffs, rvec, tvec, 1) + print("Translation vector: ", tvec) # Display image cv2.imshow("camera", current_frame) From a5b47781f27641bbbb604d8915bcd68df1f2f39a Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Tue, 25 Jan 2022 15:54:59 +0100 Subject: [PATCH 7/8] Added calibration file in Webots Current size of one square is 0.0405 --- .../protos/CalibrationChecker.proto | 29 ++++++++++++++++++ .../worlds/assets/samples/check-108.png | Bin 0 -> 136411 bytes mep3_vision/check-108.pdf | Bin 0 -> 5012 bytes mep3_vision/package.xml | 1 + 4 files changed, 30 insertions(+) create mode 100644 mep3_simulation/webots_data/protos/CalibrationChecker.proto create mode 100644 mep3_simulation/webots_data/worlds/assets/samples/check-108.png create mode 100644 mep3_vision/check-108.pdf diff --git a/mep3_simulation/webots_data/protos/CalibrationChecker.proto b/mep3_simulation/webots_data/protos/CalibrationChecker.proto new file mode 100644 index 000000000..9c4544565 --- /dev/null +++ b/mep3_simulation/webots_data/protos/CalibrationChecker.proto @@ -0,0 +1,29 @@ +#VRML_OBJ R2021b utf8 + +PROTO CalibrationChecker [ + field SFString name "CalibrationChecker" + field SFVec3f translation 0.3 0 0 + field SFRotation rotation 0 1 0 0 +] +{ + Solid { + translation IS translation + rotation IS rotation + children [ + Shape { + appearance Appearance { + texture ImageTexture { + url [ + "assets/samples/check-108.png" + ] + } + name "check-108" + } + geometry Box { + size 0.3225 0.405 0.003 + } + } + ] + name IS name + } +} \ No newline at end of file diff --git a/mep3_simulation/webots_data/worlds/assets/samples/check-108.png b/mep3_simulation/webots_data/worlds/assets/samples/check-108.png new file mode 100644 index 0000000000000000000000000000000000000000..e13588716285279311b119740abf74d61c1ff838 GIT binary patch literal 136411 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 literal 0 HcmV?d00001 diff --git a/mep3_vision/package.xml b/mep3_vision/package.xml index 199819150..9a0f35855 100644 --- a/mep3_vision/package.xml +++ b/mep3_vision/package.xml @@ -13,6 +13,7 @@ sensor_msgs std_msgs python3-opencv + image_pipeline ament_copyright ament_flake8 From 6689b5bb9f078f6f9b935f87915d47f13a9eab1c Mon Sep 17 00:00:00 2001 From: Milos Arbanas Date: Tue, 25 Jan 2022 17:36:34 +0100 Subject: [PATCH 8/8] Using .yaml calibration file that is generated by image_pipeline package --- .../protos/CalibrationChecker.proto | 2 +- mep3_vision/mep3_vision/onrobot_camera.py | 44 ++++++++++++------- mep3_vision/mep3_vision/ost.yaml | 20 +++++++++ 3 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 mep3_vision/mep3_vision/ost.yaml diff --git a/mep3_simulation/webots_data/protos/CalibrationChecker.proto b/mep3_simulation/webots_data/protos/CalibrationChecker.proto index 9c4544565..8d2c765f9 100644 --- a/mep3_simulation/webots_data/protos/CalibrationChecker.proto +++ b/mep3_simulation/webots_data/protos/CalibrationChecker.proto @@ -20,7 +20,7 @@ PROTO CalibrationChecker [ name "check-108" } geometry Box { - size 0.3225 0.405 0.003 + size 0.215 0.27 0.003 } } ] diff --git a/mep3_vision/mep3_vision/onrobot_camera.py b/mep3_vision/mep3_vision/onrobot_camera.py index 8ebd65218..5bc0eb805 100644 --- a/mep3_vision/mep3_vision/onrobot_camera.py +++ b/mep3_vision/mep3_vision/onrobot_camera.py @@ -11,8 +11,8 @@ from sensor_msgs.msg import Image # Image is the message type from cv_bridge import CvBridge # Package to convert between ROS and OpenCV Images import os -import pickle - +import yaml +import numpy as np class ImageSubscriber(Node): @@ -29,17 +29,17 @@ def __init__(self): # TODO: Calibration. Now it's just the Dummy calibration file... if True: - f = open('/home/milos/foxy_ws/src/mep3/mep3_vision/mep3_vision/DummyCameraCalibration.pckl', 'rb') - u = pickle._Unpickler(f) - u.encoding = 'latin1' - (x, y, _, _) = u.load() - self.cameraMatrix = x - self.distCoeffs = y - f.close() - if self.cameraMatrix is None or self.distCoeffs is None: - print( - "Calibration issue. Remove ./calibration/CameraCalibration.pckl and recalibrate your camera with calibration_ChAruco.py.") - exit() + with open("src/mep3/mep3_vision/mep3_vision/ost.yaml", "r") as stream: + # with open("ost.yaml", "r") as stream: + try: + camera_data = yaml.safe_load(stream) + except yaml.YAMLError as exc: + print(exc) + + self.cameraMatrix = np.array(camera_data['camera_matrix']['data']) + self.distCoeffs = np.array(camera_data['distortion_coefficients']['data']) + self.cameraMatrix = self.cameraMatrix.reshape(3, 3) + self.distCoeffs = self.distCoeffs.reshape(1, 5) # Create the subscriber. This subscriber will receive an Image # from the video_frames topic. The queue size is 10 messages. @@ -74,13 +74,23 @@ def listener_callback(self, data): rotation_vectors, translation_vectors, _objPoints = cv2.aruco.estimatePoseSingleMarkers(corners, 1, - self.cameraMatrix, - self.distCoeffs) - - + self.cameraMatrix, + self.distCoeffs) + cv2.aruco.drawDetectedMarkers(current_frame, corners, ids) + i = 0 for rvec, tvec in zip(rotation_vectors, translation_vectors): cv2.aruco.drawAxis(current_frame, self.cameraMatrix, self.distCoeffs, rvec, tvec, 1) + font = cv2.FONT_HERSHEY_SIMPLEX + # cv2.putText(current_frame, 'Christmas', (int(corners[i][0][0][0], int(corners[i][0][0][1]))), + # font, 4,(255,255,255),2,cv2.LINE_AA) + print((int(corners[i][0][0][0]), int(corners[i][0][0][1]))) + cv2.putText(current_frame, "{:.3f} {:.3f}".format(translation_vectors[0][0][:2][0], + translation_vectors[0][0][:2][1] + ), (int(corners[i][0][0][0]), int(corners[i][0][0][1])), + font, 1, (0, 128, 128), 2, cv2.LINE_AA) + + i+= 1 print("Translation vector: ", tvec) # Display image diff --git a/mep3_vision/mep3_vision/ost.yaml b/mep3_vision/mep3_vision/ost.yaml new file mode 100644 index 000000000..02095b02d --- /dev/null +++ b/mep3_vision/mep3_vision/ost.yaml @@ -0,0 +1,20 @@ +image_width: 1280 +image_height: 720 +camera_name: narrow_stereo +camera_matrix: + rows: 3 + cols: 3 + data: [29775.468511, 0.000000, 491.076412, 0.000000, 8706.348951, 21.647955, 0.000000, 0.000000, 1.000000] +distortion_model: plumb_bob +distortion_coefficients: + rows: 1 + cols: 5 + data: [49.509086, 6913.707099, 3.098428, -0.685889, 0.000000] +rectification_matrix: + rows: 3 + cols: 3 + data: [1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000] +projection_matrix: + rows: 3 + cols: 4 + data: [54792.343848, 0.000000, 355.715996, 0.000000, 0.000000, 31239.355566, 106.797792, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000]