我正在尝试完成我的机器人课程的最后一个项目,在该项目中,我们正在凉亭中运行Turtlebot仿真,我们应该订阅image_raw并检测环境中的某些颜色(红色,绿色,黄色)。
我们被要求在屏幕中间绘制一个绿色矩形(在x轴的中间,该矩形是框架的整个高度)。并且,当检测到某个颜色在该矩形中时,该矩形将变为红色,并将文本添加到列出检测到的颜色的框架中。我们还应该在每次检测到颜色时将其发布到一个主题。
但是,我无法通过检测轮廓来找到适合的颜色。最终项目是对一项作业的详细说明,该作业要求我们使用网络摄像头检测颜色,并且代码可以正常工作。我不知道为什么它不起作用。
以下是轮廓检测部分:
# define the lower and upper boundaries of the colors in the HSV color space
lower = {'red':(166, 84, 141), 'green':(66, 122, 129), 'yellow':(23, 59, 119)}
upper = {'red':(186,255,255), 'green':(86,255,255), 'yellow':(54,255,255)}
colors = {'red':(0,0,255), 'green':(0,255,0), 'yellow':(0, 255, 217)}
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
#for each color in dictionary check object in frame
#draw rectangle in the center of the frame
cv2.rectangle(frame, (left, upper_rect), (right, lower_rect), (0, 255, 0), 2)
for key, value in upper.items():
# construct a mask for the color from dictionary`1, then remove any small blobs left in the mask
kernel = np.ones((9,9),np.uint8)
mask = cv2.inRange(hsv, lower[key], upper[key])
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
#print('key is:' + key)
# find contours in the mask and initialize the current (x, y) center of the ball
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
center = None
#print(cnts) #this prints [] meaning that the contour is empty and not working
# only proceed if at least one contour was found
if len(cnts) > 0:
#print("if len(cnts) is called") #this is not getting printed, thus it is not finding contours
# find the largest contour in the mask, then use it to compute the minimum enclosing circle
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
# only proceed if the radius meets a minimum size. Correct this value for your object's size
#this part is only done for debugging purposes (I am trying to see if it will read any contours
if radius > 0.5:
# draw the circle and centroid on the frame,
# then update the list of tracked points
cv2.circle(frame, (int(x), int(y)), int(radius), colors[key], 2)
如果需要查看,这里是整个程序。
#!/usr/bin/env python
from __future__ import print_function
from collections import deque
import numpy as np
import cv2
import sys
import rospy
import rospkg
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import array as arr
hit_pub = rospy.Publisher('Caitlyn/hit', String, queue_size=10)
color_pub = rospy.Publisher("Caitlyn/color_detect",String, queue_size=10)
#bridge = CvBridge()
frame = None
height=0
width= 0
upper= 0
left= 0
lower= 0
right= 0
inRange= False
targetHit = False
#new stuff
redFound = False
greenFound = False
yellowFound = False
red= False
yellow= False
green= False
color_list = []
color_string = ""
font = cv2.FONT_HERSHEY_SIMPLEX
class image_converter:
def __init__(self):
self.image_pub = rospy.Publisher("Caitlyn/image_topic_2",Image, queue_size= 10)
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("Caitlyn/camera/rgb/image_raw",Image,self.callback)
def callback(self,data):
try:
global frame
frame = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
global height
global width
h = frame.shape[0]
w = frame.shape[1]
height = h
width = w
global centerPoint_x
global centerPoint_y
centerPoint_x = w/2
centerpoint_y= h/2
global upper_rect
global left
global lower_rect
global right
upper_rect = int(h)
left = int(w/4)
lower_rect = int(0)
right = int(w*3/4)
# define the lower and upper boundaries of the colors in the HSV color space
lower = {'red':(166, 84, 141), 'green':(66, 122, 129), 'yellow':(23, 59, 119)}
upper = {'red':(186,255,255), 'green':(86,255,255), 'yellow':(54,255,255)}
colors = {'red':(0,0,255), 'green':(0,255,0), 'yellow':(0, 255, 217)}
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
#for each color in dictionary check object in frame
#draw rectangle in the center of the frame
cv2.rectangle(frame, (left, upper_rect), (right, lower_rect), (0, 255, 0), 2)
for key, value in upper.items():
# construct a mask for the color from dictionary`1, then remove any small blobs left in the mask
kernel = np.ones((9,9),np.uint8)
mask = cv2.inRange(hsv, lower[key], upper[key])
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
#print('key is:' + key)
# find contours in the mask and initialize the current (x, y) center of the ball
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
center = None
#print(cnts)
# only proceed if at least one contour was found
if len(cnts) > 0:
print("if len(cnts) is called")
# find the largest contour in the mask, then use it to compute the minimum enclosing circle
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
# only proceed if the radius meets a minimum size. Correct this value for your obect's size
if radius > 0.5:
# draw the circle and centroid on the frame,
# then update the list of tracked points
cv2.circle(frame, (int(x), int(y)), int(radius), colors[key], 2)
#check to see if the point found is at the center of the screen, and if yes change the color of the rectangle
global inRange
global redFound
global greenFound
global yellowFound
if int((x) > left & int(x) < right):
if(y > 0 & int(y) < upper_rect):
if(key == 'red'): redFound = True
elif (key == 'green'): greenFound = True
elif (key == 'yellow'): yellowFound = True
inRange = True
else:
#cv2.rectangle(frame, (left, upper_rect), (right, lower_rect), (0, 255, 0), 2)
inRange= False
if(key == 'red'): redFound = False
elif (key == 'green'): greenFound = False
elif (key == 'yellow'): yellowFound = False
global color_list
global red
global yellow
global green
#adding necessary colors
if(redFound):
if (red == False):
color_list.append(" red ")
red = True
if(greenFound):
if (green == False):
color_list.append(" green ")
green = True
if(yellowFound):
if (yellow == False):
color_list.append(" yellow ")
yellow = True
#removing necessary colors
if(redFound == False):
if (red):
color_list.remove(" red ")
red = False
if(greenFound):
if (green):
color_list.remove(" green ")
green = False
if(yellowFound):
if (yellow):
color_list.remove(" yellow ")
yellow = False
#creating the message and text string
global color_string
color_string = ""
for detected in color_list:
color_string = color_string + detected
#changing rectangle, adding words, and publishing to topic
if(inRange):
if(redFound or greenFound or yellowFound):
cv2.rectangle(frame, (left, upper_rect), (right, lower_rect), (0, 0, 255), 2)
cv2.putText(frame,' Found color: ' + color_string , (left,int(upper_rect*1/4)), font, 1, (0,0,255), 2)
color_pub.publish("Color(s) detected: " + color_string)
else:
cv2.rectangle(frame, (left, upper_rect), (right, lower_rect), (0, 255, 0), 2)
color_pub.publish("Nothing detected yet")
# show the frame to our screen
cv2.imshow("Image window", frame)
key = cv2.waitKey(1) & 0xFF
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(frame, "bgr8"))
except CvBridgeError as e:
print(e)
# if the 's' key is pressed, publish an answer to the topic
if key == ord("s"):
if (inRange):
hit_pub.publish("Target hit!")
else:
hit_pub.publish("Sorry. Nothing was hit.")
def main(args):
#rospy.init_node('image_converter', anonymous=True)
#Image_converter()
rospy.init_node('image_converter', anonymous=True)
ic = image_converter()
try:
rospy.spin()
except KeyboardInterrupt:
print("Shutting down")
cv2.destroyAllWindows()
if __name__ == '__main__':
main(sys.argv)