在OpenCV中,如何正确检测轮廓?

时间:2019-12-05 06:06:33

标签: python opencv ros gazebo-simu

我正在尝试完成我的机器人课程的最后一个项目,在该项目中,我们正在凉亭中运行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)

0 个答案:

没有答案