Reputation: 1
recently I was commissioned to use a robot already made in gazebo, using Ros which has a camera and I have been able to see that image through .py code. Now they ask me to filter colors (green, red and blue), I already have the high and low values, and I can do it with an image, but I don't know how to mix both programs, so that what is filtered by color, I only know what transmit the robot's camera and not an image.
All of this while using Open CV
Attached both codes
////////////////////////////////////////////////////////////////////////////////////////
Code to see the gazeebo virtual camera
////////////////////////////////////////////////////////////////////////////////////////
#!/usr/bin/env python
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import cv2
bridge_object = CvBridge() # create the cv_bridge object
image_received = 0 #Flag to indicate that we have already received an image
cv_image = 0 #This is just to create the global variable cv_image
def show_image():
image_sub = rospy.Subscriber("/two_wheels_robot/camera1/image_raw",Image,camera_callback)
r = rospy.Rate(10) #10Hz
while not rospy.is_shutdown():
if image_received:
cv2.waitKey(1)
r.sleep()
cv2.destroyAllWindows()
def camera_callback(data):
global bridge_object
global cv_image
global image_received
image_received=1
try:
print("received ROS image, I will convert it to opencv")
# We select bgr8 because its the OpenCV encoding by default
cv_image = bridge_object.imgmsg_to_cv2(data, desired_encoding="bgr8")
#Add your code to save the image here:
#Save the image "img" in the current path
cv2.imwrite('robot_image.jpg', cv_image)
#Display the image in a window
cv2.imshow('Image from robot camera', cv_image)
except CvBridgeError as e:
print(e)
if __name__ == '__main__':
rospy.init_node('load_image', anonymous=True)
show_image()
////////////////////////////////////////////////////////////////////////////////////////
code to see an image segmented in RGB by windows
////////////////////////////////////////////////////////////////////////////////////////
#!/usr/bin/env python
import rospy
from sensor_msgs.msg import Image
#Import the numpy library which will help with some matrix operations
import numpy as np
from cv_bridge import CvBridge, CvBridgeError
import cv2
bridge_object = CvBridge() # create the cv_bridge object
image_received = 0 #Flag to indicate that we have already received an image
cv_image = 0 #This is just to create the global variable cv_image
def show_image():
image_sub = rospy.Subscriber("/two_wheels_robot/camera1/image_raw",Image,camera_callback)
r = rospy.Rate(10) #10Hz
image = cv2.imread('/home/user/catkin_ws/src/opencv_for_robotics_images/Unit_2/Course_images/Filtering.png')
while not rospy.is_shutdown():
#I resized the image so it can be easier to work with
image = cv2.resize(image,(300,300))
#Once we read the image we need to change the color space to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
#Hsv limits are defined
#here is where you define the range of the color you're looking for
#each value of the vector corresponds to the H,S & V values respectively
min_green = np.array([50,220,220])
max_green = np.array([60,255,255])
min_red = np.array([170,220,220])
max_red = np.array([180,255,255])
min_blue = np.array([110,220,220])
max_blue = np.array([120,255,255])
#This is the actual color detection
#Here we will create a mask that contains only the colors defined in your limits
#This mask has only one dimension, so its black and white }
mask_g = cv2.inRange(hsv, min_green, max_green)
mask_r = cv2.inRange(hsv, min_red, max_red)
mask_b = cv2.inRange(hsv, min_blue, max_blue)
#We use the mask with the original image to get the colored post-processed image
res_b = cv2.bitwise_and(image, image, mask= mask_b)
res_g = cv2.bitwise_and(image,image, mask= mask_g)
res_r = cv2.bitwise_and(image,image, mask= mask_r)
cv2.imshow('Green',res_g)
cv2.imshow('Red',res_b)
cv2.imshow('Blue',res_r)
cv2.imshow('Original',image)
cv2.waitKey(1)
r.sleep()
cv2.destroyAllWindows()
def camera_callback(data):
global bridge_object
global cv_image
global image_received
image_received=1
try:
print("received ROS image, I will convert it to opencv")
# We select bgr8 because its the OpenCV encoding by default
cv_image = bridge_object.imgmsg_to_cv2(data, desired_encoding="bgr8")
except CvBridgeError as e:
print(e)
if __name__ == '__main__':
rospy.init_node('opencv_example1', anonymous=True)
show_image()
Upvotes: 0
Views: 1391
Reputation: 83
First of all there a lot structural problems in that code. You should consider using Classes and follow the ROS philosophy by implementing separates nodes that communicates with each other. Please take a look also to the rospy tutorials.
To "mix" both programs you can either create a function that processes the color in your first program that receives the image
def process_image(image):
image = cv2.resize(image,(300,300))
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
min_green = np.array([50,220,220])
max_green = np.array([60,255,255])
min_red = np.array([170,220,220])
max_red = np.array([180,255,255])
min_blue = np.array([110,220,220])
max_blue = np.array([120,255,255])
mask_g = cv2.inRange(hsv, min_green, max_green)
mask_r = cv2.inRange(hsv, min_red, max_red)
mask_b = cv2.inRange(hsv, min_blue, max_blue)
res_b = cv2.bitwise_and(image, image, mask= mask_b)
res_g = cv2.bitwise_and(image,image, mask= mask_g)
res_r = cv2.bitwise_and(image,image, mask= mask_r)
cv2.imshow('Green',res_g)
cv2.imshow('Red',res_b)
cv2.imshow('Blue',res_r)
cv2.imshow('Original',image)
cv2.waitKey(1)
And calling it once every time you receive an image (inside the callback). Usually it's preferable to divide all this processing in multiple threads, but, as a start point you could use something like this:
#!/usr/bin/env python
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import cv2
bridge_object = CvBridge() # create the cv_bridge object
image_received = 0 #Flag to indicate that we have already received an image
cv_image = 0 #This is just to create the global variable cv_image
def show_image():
image_sub = rospy.Subscriber("/two_wheels_robot/camera1/image_raw",Image,camera_callback)
r = rospy.Rate(10) #10Hz
while not rospy.is_shutdown():
if image_received:
cv2.waitKey(1)
r.sleep()
cv2.destroyAllWindows()
def process_image(image):
image = cv2.resize(image,(300,300))
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
min_green = np.array([50,220,220])
max_green = np.array([60,255,255])
min_red = np.array([170,220,220])
max_red = np.array([180,255,255])
min_blue = np.array([110,220,220])
max_blue = np.array([120,255,255])
mask_g = cv2.inRange(hsv, min_green, max_green)
mask_r = cv2.inRange(hsv, min_red, max_red)
mask_b = cv2.inRange(hsv, min_blue, max_blue)
res_b = cv2.bitwise_and(image, image, mask= mask_b)
res_g = cv2.bitwise_and(image,image, mask= mask_g)
res_r = cv2.bitwise_and(image,image, mask= mask_r)
cv2.imshow('Green',res_g)
cv2.imshow('Red',res_b)
cv2.imshow('Blue',res_r)
cv2.imshow('Original',image)
cv2.waitKey(1)
def camera_callback(data):
global bridge_object
global cv_image
global image_received
image_received=1
try:
print("received ROS image, I will convert it to opencv")
# We select bgr8 because its the OpenCV encoding by default
cv_image = bridge_object.imgmsg_to_cv2(data, desired_encoding="bgr8")
#Add your code to save the image here:
#Save the image "img" in the current path
cv2.imwrite('robot_image.jpg', cv_image)
## Calling the processing function
process_image(cv_image)
cv2.imshow('Image from robot camera', cv_image)
except CvBridgeError as e:
print(e)
if __name__ == '__main__':
rospy.init_node('load_image', anonymous=True)
show_image()
You should also avoid declaring globals variables inside a function.
Upvotes: 1