-
Notifications
You must be signed in to change notification settings - Fork 16
Feature/technical challenge vision #465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
9d45a98
add empty package
confusedlama 2ff6705
add messages for vision
confusedlama 182ed0e
add array message for bounding boxes
confusedlama d8533fe
add seperate lists for different obstacles
confusedlama f7a3bfb
add dependencies for ros messages and dynamic reconfigure
confusedlama 12bddf0
remove unused tests
confusedlama 5c2fa8e
add a bunch of stuff to setup
confusedlama 03a9ef6
add vision node
confusedlama 43e243c
add dynamic reconfigure param file to gitignore
confusedlama 9d56740
add config
confusedlama 6f8f72f
add launch file
confusedlama be0bf06
use Robot message instead of custom message type
confusedlama 70176bd
remove custom messages that are no longer needed
confusedlama c1f3efe
remove rest of unused message types
confusedlama 966dfac
rename package to bitbots_<package>
confusedlama 61edfe8
remove build dependent files from git
confusedlama fab7775
make debug mode dynamic
confusedlama 20d536e
update dependencies
confusedlama dc8e967
make debug mode actually do something
confusedlama 04893f3
fix dependency
confusedlama 6b6ecaa
remove sim param in launch file
confusedlama a827d69
remove ros__parameters
confusedlama a1f5d4c
fix dependency names
confusedlama 214ad6e
get build dependent files back because they are actually really impor…
confusedlama 14ba794
remove rest of sim param
confusedlama cf95af0
stop including range.yaml as params file
confusedlama a37c0fb
update params in 1s intervals
confusedlama f3c34df
update parameters in image_callback
confusedlama a39f792
use same topic as vision for robot annotations
confusedlama c7b08f4
Merge branch 'main' into feature/technical_challenge_vision
Flova 28a8730
Merge branch 'main' into feature/technical_challenge_vision
Flova 09f4f22
Fix and tune tcv
Flova 34ef2ad
Increase obstacle size
Flova File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Empty file.
183 changes: 183 additions & 0 deletions
183
...challenge_vision/bitbots_technical_challenge_vision/bitbots_technical_challenge_vision.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
from typing import Optional, Tuple | ||
|
||
import cv2 | ||
import numpy as np | ||
import rclpy | ||
import rclpy.logging | ||
from ament_index_python.packages import get_package_share_directory | ||
from cv_bridge import CvBridge | ||
from rclpy.node import Node | ||
from sensor_msgs.msg import Image | ||
from soccer_vision_2d_msgs.msg import Robot, RobotArray | ||
|
||
from bitbots_technical_challenge_vision.bitbots_technical_challenge_vision_params import ( | ||
bitbots_technical_challenge_vision, | ||
) | ||
|
||
|
||
class TechnicalChallengeVision(Node): | ||
def __init__(self): | ||
super().__init__("bitbots_technical_challenge_vision") | ||
|
||
self._package_path = get_package_share_directory("bitbots_technical_challenge_vision") | ||
self._cv_bridge = CvBridge() | ||
self._annotations_pub = self.create_publisher(RobotArray, "/robots_in_image", 10) | ||
self._debug_img_pub = self.create_publisher(Image, "/bitbots_technical_challenge_vision_debug_img", 10) | ||
self._debug_clrmp_pub_blue = self.create_publisher( | ||
Image, "/bitbots_technical_challenge_vision_debug_clrmp_blue", 10 | ||
) | ||
self._debug_clrmp_pub_red = self.create_publisher( | ||
Image, "/bitbots_technical_challenge_vision_debug_clrmp_red", 10 | ||
) | ||
self._img_sub = self.create_subscription(Image, "/camera/image_proc", self.image_callback, 10) | ||
self._param_listener = bitbots_technical_challenge_vision.ParamListener(self) | ||
self._params = self._param_listener.get_params() | ||
|
||
def create_robot_msg(self, x: int, y: int, w: int, h: int, t: int) -> Robot: | ||
""" | ||
Creates a Robot message from a robots bounding box data and its color. | ||
|
||
:param x: bb top left x | ||
:param y: bb top left y | ||
:param w: bb width | ||
:param h: bb height | ||
:param t: robot team | ||
:return: robot message for that robot | ||
""" | ||
robot = Robot() | ||
|
||
robot.bb.center.position.x = float(x + (w / 2)) | ||
robot.bb.center.position.y = float(y + (h / 2)) | ||
robot.bb.size_x = float(w) | ||
robot.bb.size_y = float(h) | ||
robot.attributes.team = t | ||
|
||
return robot | ||
|
||
def process_image( | ||
self, img: np.ndarray, debug_img: np.ndarray, arg | ||
) -> Tuple[list[Robot], list[Robot], np.ndarray, np.ndarray]: | ||
""" | ||
gets annotations from the camera image | ||
|
||
:param img: ndarray containing the camera image | ||
:param debug_img: copy of img debug annotations should be drawn here | ||
:param arg: __RosParameters object containing the dynamic parameters | ||
:return: [[blue_robots], [red_robots], clrmp_blue, clrmp_red] | ||
""" | ||
# convert img to hsv to isolate colors better | ||
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) | ||
|
||
# get color maps | ||
blue_map = cv2.inRange( | ||
img, | ||
(arg.blue_lower_h, arg.blue_lower_s, arg.blue_lower_v), | ||
(arg.blue_upper_h, arg.blue_upper_s, arg.blue_upper_v), | ||
) | ||
|
||
red_map = cv2.inRange( | ||
img, | ||
(arg.red_lower_h, arg.red_lower_s, arg.red_lower_v), | ||
(arg.red_upper_h, arg.red_upper_s, arg.red_upper_v), | ||
) | ||
|
||
# get contours in color maps | ||
blue_contours, _ = cv2.findContours(blue_map, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) | ||
red_contours, _ = cv2.findContours(red_map, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) | ||
|
||
# get lists of bounding boxes | ||
blue_robots = [] | ||
red_robots = [] | ||
|
||
def annotate(x, y, w, h, c) -> Optional[np.ndarray]: | ||
if not arg.debug_mode: | ||
return None | ||
return cv2.rectangle( | ||
debug_img, | ||
(x, y), | ||
(x + w, y + h), | ||
c, | ||
2, | ||
) | ||
|
||
for cnt in blue_contours: | ||
x, y, w, h = cv2.boundingRect(cnt) | ||
if min(w, h) >= arg.min_size and max(h, w) <= arg.max_size: | ||
# draw bb on debug img | ||
annotate(x, y, w, h, (255, 0, 0)) | ||
|
||
# TODO I think 1 is for the blue team? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can/should use the constant in the message for that. |
||
blue_robots.append(self.create_robot_msg(x, y, w, h, 1)) | ||
|
||
for cnt in red_contours: | ||
x, y, w, h = cv2.boundingRect(cnt) | ||
if min(w, h) >= arg.min_size and max(h, w) <= arg.max_size: | ||
# draw bb on debug img | ||
annotate(x, y, w, h, (0, 0, 255)) | ||
|
||
red_robots.append(self.create_robot_msg(x, y, w, h, 2)) | ||
|
||
return blue_robots, red_robots, blue_map, red_map, debug_img | ||
|
||
def image_callback(self, msg: Image): | ||
# get dynamic parameters | ||
if self._param_listener.is_old(self._params): | ||
self._param_listener.refresh_dynamic_parameters() | ||
self._params = self._param_listener.get_params() | ||
|
||
arg = self._params | ||
|
||
# set variables | ||
img = self._cv_bridge.imgmsg_to_cv2(img_msg=msg, desired_encoding="bgr8") | ||
header = msg.header | ||
|
||
if arg.debug_mode: | ||
debug_img = np.copy(img) | ||
else: | ||
debug_img = None | ||
|
||
# get annotations | ||
blue_robots, red_robots, blue_map, red_map, debug_img = self.process_image(img, debug_img, arg) | ||
robots = [] | ||
robots.extend(blue_robots) | ||
robots.extend(red_robots) | ||
|
||
# make output message | ||
robot_array_message = RobotArray() | ||
robot_array_message.header = header | ||
robot_array_message.robots = robots | ||
|
||
# publish output message | ||
self._annotations_pub.publish(robot_array_message) | ||
|
||
if arg.debug_mode: | ||
# make debug image message | ||
debug_img_msg = self._cv_bridge.cv2_to_imgmsg(cvim=debug_img, encoding="bgr8", header=header) | ||
|
||
# publish debug image | ||
self._debug_img_pub.publish(debug_img_msg) | ||
|
||
# make color map messages | ||
clrmp_blue_img = cv2.cvtColor(blue_map, cv2.COLOR_GRAY2BGR) | ||
clrmp_blue_msg = self._cv_bridge.cv2_to_imgmsg(cvim=clrmp_blue_img, encoding="bgr8", header=header) | ||
|
||
clrmp_red_img = cv2.cvtColor(red_map, cv2.COLOR_GRAY2BGR) | ||
clrmp_red_msg = self._cv_bridge.cv2_to_imgmsg(clrmp_red_img, encoding="bgr8", header=header) | ||
|
||
# publish color map messages | ||
self._debug_clrmp_pub_blue.publish(clrmp_blue_msg) | ||
self._debug_clrmp_pub_red.publish(clrmp_red_msg) | ||
|
||
|
||
def main(args=None): | ||
rclpy.init(args=args) | ||
node = TechnicalChallengeVision() | ||
try: | ||
rclpy.spin(node) | ||
except KeyboardInterrupt: | ||
pass | ||
node.destroy_node() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not suuuper important, but I think it is a bit confusing that you named your parameters bitbots_technical_challenge_vision, which is the same as the python file and the package name. But because this is for a technical challenge, it is okay.