对于我的班级机器人项目,我们需要从使用凉亭模拟的虚拟乌龟机器人中逐帧读取视频馈送。然后我们检测图像中的颜色(红色、蓝色和绿色),如果它们位于图像的中心,在我们必须在框架中心绘制的矩形内。如果检测到其中一种颜色,则矩形应从绿色变为红色,如果在矩形为红色时单击“s”按钮(即检测到一种颜色),则它应发布到主题,说明目标是射击。这段代码的大部分是为之前的任务编写的,在该任务中,我们必须在网络摄像头的帧中的任何位置检测这些颜色中的任何一种,并用边界框或圆圈指示它,而我的代码适用于该任务。现在我稍微更改了我的代码以从虚拟相机中读取帧,我从教授提供给我们的一些示例代码中添加了一些代码,以尝试发布修改后的图像,以便我可以使用 Rviz 查看它。我添加的任何内容都会使代码不再正常工作,并且出现错误,但我对代码的理解不够深入,无法找到我的错误。
我收到的错误如下:
[错误] [1575253473.863051, 2724.055000]:回调错误:
回溯(最近一次通话最后):
_invoke_callback cb(msg) 中的文件“/opt/ros/melodic/lib/python2.7/dist-packages/rospy/topics.py”,第 750 行
ImageCallback upper_left(int(w/4), h) 中的文件“/home/project_ws/src/project_gazebo/scripts/color_detect.py”,第 49 行
TypeError:“NoneType”对象不可调用
我不知道这意味着什么或如何解决它。我知道这可能是订阅者回调函数的问题,但我试图准确地写出教授的示例对人脸检测(而不是颜色检测)的作用。除此之外,我不知道如何解决这个问题。我真的可以使用一些指导。
这是文件的样子(我只会发布一个片段,但由于我不确定问题出在哪里,所以我将所有这些都发布):
#!/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
hit_pub = rospy.Publisher('Cait/hit', String, queue_size=10)
image_pub = rospy.Publisher("Cait/image_topic_2",Image, queue_size=10)
bridge = CvBridge()
frame = None
height= None
width= None
upper_left=None
lower_right=None
inRange= False
targetHit = False
def ImageCallback(data):
try:
global frame
frame = bridge.imgmsg_to_cv2(data, "bgr8")
#frame = data.data
global height
global width
(h, w) = frame.shape[:2] #w:image-width and h:image-height
height = h
width = w
global centerPoint_x
global centerPoint_y
centerPoint_x = w/2
centerpoint_y= h/2
global upper_left
global lower_right
upper_left(int(w/4), h)
lower_right(int(w*3/4), 0)
except CvBridgeError as e:
print(e)
image_sub = rospy.Subscriber("Cait/camera/rgb/image_raw",Image,ImageCallback)
def Image_converter():
# 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)}
# grab frames from webcam -> now grab fromm rviz raw_image in subscriber
#camera = cv2.VideoCapture(0)
# keep looping
while True:
# grab the current frame -> now done by ImageCallback()
#(grabbed, frame) = camera.read()
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, upper_left, lower_right, (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)
# 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
# only proceed if at least one contour was found
if len(cnts) > 0:
# 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)
#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
if (x > int(width/4) & x< int(width*3/4)):
if(y > 0 & y < height):
cv2.rectangle(frame, upper_left, lower_right, (0, 0, 255), 2)
inRange = True
else:
cv2.rectangle(frame, upper_left, lower_right, (0, 255, 0), 2)
inRange= False
# show the frame to our screen
cv2.imshow("Image window", frame)
key = cv2.waitKey(1) & 0xFF
try:
image_pub.publish(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.")
if key == ord("q"): #q quits loop
break
def main(args):
rospy.init_node('image_converter', anonymous=True)
Image_converter()
try:
rospy.spin()
except KeyboardInterrupt:
print("Shutting down")
cv2.destroyAllWindows()
if __name__ == '__main__':
main(sys.argv)