Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am attempting to do real-time object detection without any ML. The approach is to identify the object per its color profile. I am trying to identify a rectangular object with a single colour and draw a bounding box. This is the code:

import cv2
import numpy as np

class ColourBounds:
    def __init__(self, rgb):
        hsv = cv2.cvtColor(np.uint8([[[rgb[2], rgb[1], rgb[0]]]]), cv2.COLOR_BGR2HSV).flatten()

        lower = [hsv[0] - 10]
        upper = [hsv[0] + 10]

        if lower[0] < 0:
            lower.append(179 + lower[0]) # + negative = - abs
            upper.append(179)
            lower[0] = 0
        elif upper[0] > 179:
            lower.append(0)
            upper.append(upper[0] - 179)
            upper[0] = 179

        self.lower = [np.array([h, 100, 100]) for h in lower]
        self.upper = [np.array([h, 255, 255]) for h in upper]

def contains_vertical(r1, r2):
    x1, y1, w1, h1 = r1
    x2, y2, w2, h2 = r2

    return x1 <= x2 < x1 + w1 and x1 <= x2 + w2 < x1 + w1

def drawLabel(w, h, x, y, text, frame):
    cv2.rectangle(frame,(x,y),(x+w,y+h),(120,0,0),2)
    cv2.putText(frame, text, (x,y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,255), 2)

colourMap = {"Antigen Device": ColourBounds((237,237,237))}

while(True):

    frame = cv2.imread('antigen.png')

    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    rects = {}

    for name, colour in colourMap.items():
        mask = cv2.inRange(hsv, colour.lower[0], colour.upper[0])

        if len(colour.lower) == 2:
            mask = mask | cv2.inRange(hsv, colour.lower[1], colour.upper[1])

        conts, heirarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

        if (len(conts) == 0):
            continue

        biggest = sorted(conts, key=cv2.contourArea, reverse=True)[0]
        rect = cv2.boundingRect(biggest)
        x, y, w, h = rect

        if w < 50 or h < 50:
            continue

        if name == "Antigen Device":
            if any([contains_vertical(rects[n], rect) for n in rects]):
                continue

        rects[name] = rect
        drawLabel(w, h, x, y, name, frame)

    cv2.imshow('image',frame)
    k = cv2.waitKey(0) & 0xFF
    if k == 27:
        break

cv2.destroyAllWindows()
cv2.waitKey(1)

However, I do not see a bounding box or label. Below is my image. No changes are applied: enter image description here

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
140 views
Welcome To Ask or Share your Answers For Others

1 Answer

You are trying to do "color detection" and then draw a bounding box around it.

The easiest way:

Step 1: Implement color detection.

I implemented the following code to find the right values for the mask for your image. Play with the trackbars and when you are satisfied with the results, press q and the values for the mask ??will be printed for you.

Note: it's ok that you find more small contours besides your goal.

I found this values working great:

h_min, h_max, s_min, s_max, v_min, v_max: 0 179 0 15 223 255

import cv2
import numpy as np

def empty():
   pass


while True:

   img = cv2.imread(Path to your image)
   imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
   h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
   h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
   s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
   s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
   v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
   v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
   lower = np.array([h_min, s_min, v_min])
   upper = np.array([h_max, s_max, v_max])
   mask = cv2.inRange(imgHSV, lower, upper)
   imgResult = cv2.bitwise_and(img, img, mask=mask)

   # for OpenCV 4
   contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
   cv2.CHAIN_APPROX_NONE) 

    # ---For OpenCV 3---
    # _, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
    # cv2.CHAIN_APPROX_NONE) 
    # ---For OpenCV 3---

   for contour in contours:
         cv2.drawContours(img, contour, -1, (0, 255, 0), 3)

   cv2.imshow("Original", img)
   cv2.imshow("Result", imgResult)

   if cv2.waitKey(27) & 0xFF == ord('q'):
       print(h_min, h_max, s_min, s_max, v_min, v_max)
       break

Step 2: Draw the bounding box only around your goal. (2 drawing Options)

The code is similar to before but now we know the right values and we will draw the line around the contour that we want. Our goal is the biggest contour so we can use the contourArea() method to extract the size of the contour and then draw the "bounding box" only if the contour is big enough. It's a little different implementation from your code but you can adjust it to your logic (sorting the sizes of the areas of the contours and draw only on the biggest one).

For example:

import cv2
import numpy as np

while True:
    frame = cv2.imread("stackoverflow2pic.jpeg")
    blurred_frame = cv2.GaussianBlur(frame, (5, 5), 0)
    hsv = cv2.cvtColor(blurred_frame, cv2.COLOR_BGR2HSV)

    lower = np.array([0, 0, 223])
    upper = np.array([179, 15, 255])
    mask = cv2.inRange(hsv, lower, upper)
    
    # for OpenCV 4
    contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
       cv2.CHAIN_APPROX_NONE) 

    # ---For OpenCV 3---
    # _, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
    # cv2.CHAIN_APPROX_NONE) 
    # ---For OpenCV 3---

    for contour in contours:
        area = cv2.contourArea(contour)
        if area > 5000:
             # -- Draw Option 1 --
             cv2.drawContours(frame, contour, -1, (0, 255, 0), 3)

             # -- Draw Option 2--
             # rect = cv2.boundingRect(contour)
             # x, y, w, h = rect
             # cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    cv2.imshow("Mask", mask)
    cv2.imshow("Frame", frame)

    cv2.waitKey(1)

Result (Drawing Option 1):

image

Result (Drawing Option 2):

image

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...